18. JavaScript 中如何进行隐式类型转换?
18. JavaScript 中如何进行隐式类型转换?
ToPrimitive 方法
这是 JavaScript
中每个值隐含的自带的方法, 用来将值(无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型, 则直接返回值本身; 如果值为对象, 其看起来大概是这样:
/**
* @obj 需要转换的对象
* @type 期望的结果类型
*/
ToPrimitive(obj, type)
type 的值
当 type 为 number 时规则
- 调用
obj
的valueOf
方法, 如果为原始值, 则返回, 否则下一步 - 调用
obj
的toString
方法, 后续同上 - 抛出
TypeError
异常
当 type 为 string 时规则
- 调用
obj
的toString
方法, 如果为原始值, 则返回, 否则下一步 - 调用
obj
的valueOf
方法, 后续同上 - 抛出
TypeError
异常
两者的主要区别
两者的主要区别在于调用 toString
和 valueOf
的先后顺序。默认情况下:
- 如果对象为
Date
对象, 则type
默认为string
- 其他情况下,
type
默认为number
总结
对于 Date
以外的对象, 转换为基本类型的大概规则可以概括为一个函数:
var objToNumber = value => Number(value.valueOf().toString())
objToNumber([]) === 0
objToNumber({}) === NaN
基本类型在不同操作符的情况下隐式转换的规则
JavaScript
中的隐式类型转换主要发生在 +
、 -
、 *
、 /
以及 ==
、 >
、 <
这些运算符之间。而这些运算符只能操作基本类型值, 所以在进行这些运算前的第一步就是将两边的值用 ToPrimitive
转换成基本类型, 再进行操作。对于对象, 其会被 ToPrimitive
转换成基本类型, 所以最终还是要应用基本类型转换规则。
+ 操作符
+
操作符的两边有至少一个 string
类型变量时, 两边的变量都会被隐式转换为字符串, 其他情况下两边的变量都会被转换为数字:
1 + '23' // '123'
1 + false // 1
1 + Symbol() // Uncaught TypeError: Cannot convert a Symbol value to a number
'1' + false // '1false'
false + true // 1
-、 *、 \ 操作符
NaN
也是一个数字:
1 * '23' // 23
1 * false // 0
1 / 'aa' // NaN
对于 == 操作符
操作符两边的值都尽量转成 number
:
3 == true // false, 3 转为number为3, true转为number为1
'0' == false //true, '0'转为number为0, false转为number为0
'0' == 0 // '0'转为number为0
对于 < 和 > 比较符
如果两边都是字符串, 则比较字母表顺序:
'ca' < 'bd' // false
'a' < 'b' // true
其他情况下, 转换为数字再比较:
'12' < 13 // true
false > -1 // true
以上说的是基本类型的隐式转换, 而对象会被 ToPrimitive
转换为基本类型再进行转换:
var a = {}
a > 2 // false
其对比过程如下:
a.valueOf() // {}, 上面提到过, ToPrimitive默认type为number, 所以先valueOf, 结果还是个对象, 下一步
a.toString() // "[object Object]", 现在是一个字符串了
Number(a.toString()) // NaN, 根据上面 < 和 > 操作符的规则, 要转换成数字
NaN > 2 // false, 得出比较结果
又比如:
var a = {name: 'Jack'}
var b = {age: 18}
a + b // "[object Object][object Object]"
运算过程如下:
a.valueOf() // {}, 上面提到过, ToPrimitive默认type为number, 所以先valueOf, 结果还是个对象, 下一步
a.toString() // "[object Object]"
b.valueOf() // 同理
b.toString() // "[object Object]"
a + b // "[object Object][object Object]"