类型转换
温馨提示
阅读《你不知道的 JavaScript(中卷)》和各个大佬的文章所归纳的总结,如有异议按你的理解为主
将值从一种类型转换为另一种类型称为类型转换
在 JavaScript
中进行类型转换时,根据调用形式的不同可以分为以下两种:
- 显式类型转换
- 隐式类型转换
抽象操作 (内部的类型转换规则)
在了解类型转换前我们需要知道 JavaScript
的 抽象操作 (类型转换规则)
抽象操作 是指仅供内部使用的操作
ToPrimitive
将引用类型转换成相应的基本类型值ToString
将非字符串值转换成字符串ToBoolean
将非布尔值转换成布尔值ToNumber
将非数字值转换成数字值
ToPrimitive
ToPrimitive
用来处理引用类型到基本类型的类型转换
ToPrimitive 转换规则
- 检查是否存在
Symbol.toPrimitive()
- 基本类型直接返回
- 引用类型抛出
TypeError
错误
- 检查是否存在
valueOf()
- 基本类型直接返回
- 引用类型则继续调用
toString()
- 调用
toString()
- 基本类型直接返回
- 引用类型抛出
TypeError
错误
注意点
- 使用
Object.create(null)
创建的对象没有原型,即不存在valueOf()
和toString()
,当对其进行类型转换时会抛出TypeError
错误 - 在做显式类型转换时
valueOf()
和toString()
的调用顺序会根据转换目标不同去做相应调整- 默认情况下都是先调用
valueOf()
再调用toString()
- 当需要转换的目标为字符串时,会先调用
toString()
再调用valueOf()
- 默认情况下都是先调用
const obj1 = {
toString() {
console.log('toString')
return []
},
valueOf() {
console.log('valueOf')
return 2021
},
}
const obj2 = {
toString() {
console.log('toString')
return 'LY'
},
valueOf() {
console.log('valueOf')
return []
},
}
/** 显式类型转换 */
Number(obj1) // valueOf => 2021
Number(obj2) // valueOf toString => NaN
String(obj1) // toString valueOf => '2021'
String(obj2) // toString => 'LY'
/** 隐式类型转换 */
1 + obj1 // valueOf => 2022
1 + obj2 // valueOf toString => '1LY'
'str: ' + obj1 // valueOf => 'str: 2021'
'str: ' + obj2 // valueOf toString => 'str: LY'
ToString
ToString
用来处理非字符串到字符串的类型转换
ToString 转换规则
- 基本类型
undefined
=>'undefined'
null
=>'null'
true
=>'true'
false
=>'false'
number
- 普通数值直接加引号
- 极小和极大的数字将转换成指数形式的字符串
+0 0 -0
=>'0'
Infinity
=>'Infinity'
- 引用类型会先调用
ToPrimitive
逻辑将其转换成基本类型,如果返回的基本类型不是字符串,再遵循以上规则进行转换
ToBoolean
ToBoolean
用来处理非布尔值到布尔值的类型转换,在 JavaScript
中,布尔类型分为真值(true
)和假值(false
)
- 假值:可以被强制类型转换为
false
的值 - 真值:除假值之外的值
ToBoolean 转换规则
- 以下值会被转换成假值(
false
)undefined
null
false
+0 0 -0 NaN
''
- 除假值之外的值都会被转换成真值(
true
)
ToNumber
ToNumber
用来处理非数字值到数字值的类型转换
ToNumber 转换规则
- 基本类型
undefined
=>NaN
null
=>0
true
=>1
false
=>0
string
- 空字符串(
''
) =>0
- 非数字字符串 =>
NaN
- 空字符串(
- 引用类型会先调用
ToPrimitive
逻辑将其转换成基本类型,如果返回的基本类型不是数值,再遵循以上规则进行转换
显式类型转换
显式类型转换是指显式的去调用类型转换方法
- 转换成布尔值
Boolean()
- 转换成数值
Number()
parseInt()
parseFloat()
- 转换成字符串
String()
注意点
Number()
转换的是整个值parseInt()
和parseFloat()
转换的是部分值,是对字符串逐个进行解析和转换,如果传入的参数不是字符串,会先对其进行字符串的转换
隐式类型转换
隐式类型转换是指在执行过程中,当实际操作的值与 JavaScript
内部期望得到的值不同时,就会对其做隐式类型转换(即不易察觉的类型转换)
在 JavaScript
中有以下场景会发生隐式类型转换
- 相等运算符 (
==
) - 四则运算符 (
+ - * /
) - 关系运算符 (
> < >= <=
) - 逻辑操作符 (
&& ||
) - 条件判断语句
if()
while()
- 三元运算符
相等运算符运算规则(重点)
为什么 0 == null
是 false
?
0 == null // false
ECMA-262 规范 7.2.12 小节对相等运算符的描述
- 如果
x
不是正常值(比如抛出一个错误),中断执行; - 如果
y
不是正常值,中断执行; - 如果
Type(x)
与Type(y)
相同,执行严格相等运算x === y
; - 如果
x
是null
,y
是undefined
,返回true
; - 如果
x
是undefined
,y
是null
,返回true
; - 如果
Type(x)
是数值,Type(y)
是字符串,返回x == ToNumber(y)
的结果; - 如果
Type(x)
是字符串,Type(y)
是数值,返回ToNumber(x) == y
的结果; - 如果
Type(x)
是布尔值,返回ToNumber(x) == y
的结果; - 如果
Type(y)
是布尔值,返回x == ToNumber(y)
的结果; - 如果
Type(x)
是字符串或数值或Symbol
值,Type(y)
是对象,返回x == ToPrimitive(y)
的结果; - 如果
Type(x)
是对象,Type(y)
是字符串或数值或Symbol
值,返回ToPrimitive(x) == y
的结果; - 返回
false
。
Type(x) 是
the type of x
的简写,其中的type
是 ECMA-262 规范中定义的 ECMAScript 语言和规范类型
所以在计算 0 == null
时,由于 0
的类型是数值,null
的类型是 Null
(这是规格 4.3.13 小节的规定,是内部 Type
运算的结果,跟 typeof
运算符无关);
因此上面的前 11 步都得不到结果,要到第 12 步才能得到 false
。
相等运算符运算规则总结
- 同类型比较时,执行严格相等运算
x === y
undefined
与null
比较时返回true
string
与number
进行比较时,先将string
做ToNumber
处理,再进行比较boolean
与其它类型进行比较时,先将boolean
做ToNumber
处理,再进行比较引用类型
与基本类型
进行比较时,将引用类型
做ToPrimitive
处理,再进行比较undefined
null
与其它类型的比较时都返回false
四则运算符运算规则
四则运算符运算规则
-
(减)*
(乘)/
(除) 运算符: 先对操作数做ToNumber
处理再执行运算+
(加) 运算符- 做一元运算时,对操作数做
ToNumber
处理 - 做二元运算时
- 当其中一个操作数为
string
时,将另一个操作数做ToString
处理再执行字符串拼接 - 当一个操作数为
number
另一个操作数为基本类型时,将基本类型做ToNumber
处理再执行运算 - 当一个操作数为
number
另一个操作数为引用类型时,都会先做ToString
处理再执行字符串拼接
- 当其中一个操作数为
- 做一元运算时,对操作数做
关系、逻辑、条件运算符运算规则
关系运算符运算规则
- 将引用类型做
ToPrimitive
处理 - 如果两个参数都是
string
类型时进行Unicode 编码
大小比较 - 否则将两个参数做
ToNumber
处理,再进行数值大小比较
逻辑操作符与条件判断语句
在逻辑操作符与条件判断语句中都是做 ToBoolean
处理