Appearance
JavaScript 类型转换深度解析
强制类型转换
parseInt 和 parseFloat
parseInt
从左向右提取有效数字parseFloat
解析浮点数- 第二个参数指定进制(2-36)
javascript
parseInt("10"); // 10
parseInt("10px"); // 10
parseInt("n10px"); // NaN
parseInt(27.2, 0); // 27 (基数为0时当作10进制处理)
parseInt(0, 1); // NaN (基数必须在2-36之间)
parseInt("0013", 2); // 1 (二进制001 -> 1)
parseInt("14px", 3); // 1 (三进制1 -> 1)
parseInt(123, 4); // 27 (4进制: 1*16 + 2*4 + 3*1 = 27)
一元加号运算符
- 将值转换为数字类型
- 对
BigInt
和Symbol
会报错
javascript
console.log(+null); // 0
console.log(+undefined); // NaN
console.log(+"123aa"); // NaN
console.log(+{}); // NaN
console.log(+true); // 1
// BigInt 和 Symbol 不能使用一元加号
console.log(+10n); // TypeError
console.log(+Symbol("a")); // TypeError
布尔值转换规则
if 语句中的假值
以下值在布尔上下文中会被转换为 false
:
undefined
null
NaN
0
''
(空字符串)
javascript
const result = {};
const obj = { name: 0 };
// 错误方式:0 会被转换为 false
if (obj.name) {
result.name = obj.name;
}
// 正确方式:使用 hasOwnProperty 检查属性存在性
if (obj.hasOwnProperty("name")) {
result.name = obj.name;
}
逻辑非运算符
!
将值转换为布尔类型并取反- 假值取反为
true
,真值取反为false
javascript
console.log(!0); // true
console.log(!""); // true
console.log(!null); // true
console.log(!undefined); // true
console.log(!NaN); // true
console.log(!{}); // false
console.log(![]); // false
相等比较(==)的隐式转换
特殊规则
null
和undefined
相等NaN
不等于任何值(包括自身)- 布尔值会先转换为数字
- 字符串和数字比较,字符串转为数字
- 对象与原始值比较,对象转为原始值
- 对象与对象比较引用地址
javascript
console.log(null == undefined); // true
console.log(null == 0); // false
console.log("0" == false); // true (false→0, '0'→0)
console.log([] == ![]); // true (![]→false→0, []→''→0)
console.log("000" == 0); // true
console.log([true] == 1); // false ([true]→'true'→NaN)
加法运算符(+)的转换规则
二元加法规则
- 如果有操作数是对象,先转为原始值
- 如果有一个操作数是字符串,执行字符串拼接
- 否则,将两个操作数转为数字进行加法运算
javascript
console.log([] + []); // '' (数组转字符串)
console.log([] + {}); // '[object Object]'
console.log({} + []); // '[object Object]' (Node.js) | 0 (浏览器控制台)
console.log({} + {}); // '[object Object][object Object]'
对象到原始值的转换机制
转换过程
- 检查是否存在
Symbol.toPrimitive
方法 - 没有则根据提示(hint)调用:
- "number": 先
valueOf()
后toString()
- "string": 先
toString()
后valueOf()
- "default": 同 "number"
- "number": 先
javascript
const obj = {
[Symbol.toPrimitive](hint) {
console.log(`Hint: ${hint}`);
if (hint === "number") return 10;
if (hint === "string") return "hello";
return true;
},
};
console.log(+obj); // Hint: number → 10
console.log(`${obj}`); // Hint: string → 'hello'
console.log(obj + 5); // Hint: default → true + 5 = 6
默认 valueOf 和 toString
javascript
// Array
[1, 2]
.valueOf() // [1, 2] (数组本身)
[(1, 2)].toString()(
// "1,2"
// Object
{}
)
.valueOf()(
// {} (对象本身)
{}
)
.toString(); // "[object Object]"
// Date
const now = new Date();
now.valueOf(); // 时间戳 (数字)
now.toString(); // 可读日期字符串
对象比较的特殊性
- 对象比较的是引用地址,不会进行隐式类型转换
- 不会调用
Symbol.toPrimitive
、valueOf
或toString
javascript
const obj1 = { value: 10 };
const obj2 = { value: 10 };
console.log(obj1 == obj2); // false (不同引用)
console.log(obj1 === obj2); // false
console.log(obj1 != obj2); // true
复杂隐式转换案例分析
案例 1:数组和对象的组合
javascript
const arr = [4, 10];
arr[Symbol.toPrimitive] = function (hint) {
return hint;
};
arr.valueOf = function () {
return this;
};
const obj = {};
// 转换步骤:
// 1. +arr → "number" (字符串)
// 2. "number" + obj → "number[object Object]"
// 3. "number[object Object]" + arr → "number[object Object]default"
// 4. "number[object Object]default" + obj → "number[object Object]default[object Object]"
console.log(+arr + obj + arr + obj);
// 输出: "number[object Object]default[object Object]"
案例 2:数组和布尔值的转换
javascript
// 解析: [] == ![]
// 1. ![] → false (布尔值)
// 2. false → 0 (数字)
// 3. [] → "" → 0 (数字)
// 4. 0 == 0 → true
const val = [] == ![]; // true
// 解析: [1, 1] == [1, "1"]
// 数组比较引用地址,不是内容
console.log([+val, [] + 1] == [1, "1"]); // false
案例 3:对象和空数组的转换
javascript
// 步骤解析:
// 1. +{} → NaN
// 2. +[] → 0
// 3. (NaN + []) → "NaN" (字符串拼接)
// 4. "NaN"[0] → "N"
const val = (+{} + [])[+[]];
console.log(val); // "N"
类型转换总结表
转换类型 | 规则说明 |
---|---|
数字转换 | null →0, undefined →NaN, 字符串解析数字,true →1, false →0 |
布尔转换 | 假值(null ,undefined ,0 ,NaN ,'' )→false , 其他 →true |
字符串转换 | 数组 → 元素逗号分隔,对象 →[object Object] ,null →"null", undefined →"undefined" |
对象转换 | 优先使用Symbol.toPrimitive ,然后根据 hint 调用valueOf /toString |