一、类型转换分类
JavaScript 是一门弱类型语言,变量在声明时不需要指定类型,且在运行过程中会发生各种类型转换。类型转换分为显式类型转换和隐式类型转换两大类,理解类型转换是掌握 JS 底层机制的关键一步。
| 类别 | 说明 |
|---|---|
| 显式类型转换 | 主动调用 String()、Number()、Boolean() 等进行转换 |
| 隐式类型转换 | JS 引擎在运算、比较等场景下自动进行的类型转换 |
二、原始类型之间的显式转换
2.1 String(x) ------ 转换为字符串
底层调用 ToString(x)(注意:是大写 T,不是原型上的 toString)。
js
console.log(String()); // ''(空字符串)
console.log(String(undefined)); // 'undefined'
console.log(String(null)); // 'null'
console.log(String(true)); // 'true'
console.log(String(false)); // 'false'
console.log(String(-0)); // '0'(-0 与 0 相等,输出 '0')
console.log(String(NaN)); // 'NaN'
console.log(String(Infinity)); // 'Infinity'(数学中的无穷大)
ToString (x)方法:
完整转换规则
无值 → ""
Undefined → "undefined"
Null → "null"
Boolean
true→"true"false→"false"
Number
- 常规数字:直接转字符串(
123→"123") NaN→"NaN"Infinity→"Infinity"
String → 原值(不转换)
Symbol → 报错(TypeError)
Object → 调用ToPrimitive(x , String)
2.2 Number(X) ------ 转数字
底层调用 ToNumber(x)
js
console.log(Number()); //0
console.log(Number(undefined)); // NaN,无法处理
console.log(Number(null)); //0
console.log(Number(true)); //1
console.log(Number('123')); //123
console.log(Number('-123')); //-123
console.log(Number('1.123')); //1.123
console.log(Number('00123')); //123
console.log(Number('00123a')); // NaN,无法处理
ToNumber(x)方法:
无值 → 0
Undefined → NaN
Null → 0
Boolean
true→1false→0
Number → 原值
String
- 空字符串
""→0 - 纯数字字符串 → 对应数字(
"123"→123) - 含非数字字符 →
NaN
Symbol → 报错
Object → 调用ToPrimitive(x , Number)
2.3 Boolean(X) ------ 转布尔
底层调用 ToBoolean(x)
js
console.log(Boolean()); //false
console.log(Boolean(undefined)); //false
console.log(Boolean(null)); //false
console.log(Boolean(0)); //false
console.log(Boolean(-0)); //false
console.log(Boolean(NaN)); //false
console.log(Boolean('')); //false 字符串转布尔 只有空字符串是false
console.log(Boolean(' ')); //true
ToBoolean(x)方法:
无值 → false
Undefined → false
Null → false
false → false
+-0 → false
"" → false
其余均为true
注意:
ToString(x) ToNumber(x) ToBoolean(x)方法是 JS 引擎在需要转字符串 / 数字 / 布尔值时,自动执行的转换逻辑,我们无法直接调用
三、引用类型的显式转换
3.1 引用类型转字符串:
js
console.log(String({a: 1})); // '[object Object]'
console.log(String([])); // ''(空字符串)
引用类型转字符串的底层路径:String(x) → ToString(x)(判断为Object类型) → ToPrimitive(x, String)。
ToPrimitive(x, String) 的执行流程:
- 调用
x.toString(),如果得到一个原始值,则直接返回 - 否则调用
x.valueOf(),如果得到一个原始值,则直接返回 - 否则报错
以 {a: 1} 为例:
{a: 1}.toString()返回'[object Object]',得到了原始值,直接返回
以 [] 为例:
[].toString()返回''(数组内部元素以逗号拼接,空数组即空字符串),得到了原始值,直接返回
3.2 引用类型转数字:
js
console.log(Number({})); // NaN
console.log(Number([])); // 0
引用类型转数字的底层路径:Number(x) → ToNumber(x)(判断为Object类型) → ToPrimitive(x, Number)。
以 {} 为例的转换过程:
ToPrimitive({}, Number)- 调用
{}.valueOf()→ 返回{}本身,不是原始值 - 调用
{}.toString()→ 返回'[object Object]' - 然后
Number('[object Object]')→NaN
以 [] 为例的转换过程:
ToPrimitive([], Number)- 调用
[].valueOf()→ 不是原始值 - 调用
[].toString()→ 返回''(空字符串) - 然后
Number('')→0
注意: ToPrimitive 的第二个参数是 String 时,优先调用 toString();是 Number 时,优先调用 valueOf()。valueOf() 只能将包装类的对象转成原始值
3.3 toString() 方法补充
每种原型中都有一个 toString 方法:
| 调用 | 返回值 | 来源 |
|---|---|---|
{}.toString() |
'[object Object]' |
对象原型 |
[].toString() |
数组元素以逗号拼接的字符串(空数组为 '') |
数组原型 |
'xx'.toString() |
'xx' |
其他 |
三、隐式类型转换
隐式类型转换绝大多数朝数字转,发生在以下场景:
- 四则运算:
+-*/% - 判断语句:
ifwhile==>=<=!=>< +作为一元运算符: 朝数字转,如+'1'→1
3.1 + 作为二元运算符
规则:
x + y
- lprim = ToPrimitive(x)
- 令 rprim = ToPrimitive(y)
- lprim + rprim
- 如果 lprim 或 rprim 中有一个是字符串,则将另一个也转成字符串进行拼接
- 否则全部转成 Number 进行相加
示例:[] + [] 分析
\[\] + \[\]
-
lval + rval
-
令 lprim = ToPrimitive(\[\]) → \[\].valueOf() 返回\[\](非原始) → \[\].toString() 返回 'object Object'
-
令 rprim = ToPrimitive(\[\]) → \[\].valueOf() 返回\[\](非原始) → \[\].toString() 返回 ''
''+''(两个原始值都是字符串,字符串拼接) -
结果:
''
示例:{} + [] 分析
当 {} 在语句开头时,浏览器引擎将其解析为代码块而非对象字面量,但如果正确解析:
{} + \[\]
- lval + rval
- 令 lprim = ToPrimitive({}) → {}.valueOf() 返回{}(非原始) → {}.toString() 返回'object Object'
- 令 rprim = ToPrimitive(\[\]) → \[\].valueOf() 返回\[\](非原始) → \[\].toString() 返回 ''
''+''(两个原始值都是字符串,字符串拼接) - 结果:
'[object Object]'
3.2 == 运算符 ------ 经典案例分析
js
[] == ![]
分析过程:
!字符优先级比==高,先![]→ 所有引用类型转布尔都是true,所以!true=false[] == false- 两边类型不同,先将布尔转数字:
false→0,此时[] == 0 - 对象与数字比较,将对象转原始值:
ToPrimitive([])→[].valueOf()→[](非原始)→[].toString()→'' '' == 0- 字符串与数字比较,将字符串转数字:
Number('')→0 0 == 0→true
四、总结
- 原始类型 →
String:ToString(x)→ 直接转换 - 引用类型 →
String:ToPrimitive(x, String)→toString()→valueOf() - 原始类型 →
Number:ToNumber(x)→ 直接转换 - 引用类型 →
Number:ToPrimitive(x, Number)→valueOf()→toString() - 任意 →
Boolean:ToBoolean(x)→ 只有几个值为false,其余为true