这是 JavaScript 中每个值隐含的自带的方法, 用来将值(无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型, 则直接返回值本身; 如果值为对象, 其看起来大概是这样:
/**
* @obj 需要转换的对象
* @type 期望的结果类型
*/
ToPrimitive(obj, type)
obj 的 valueOf 方法, 如果为原始值, 则返回, 否则下一步obj 的 toString 方法, 后续同上TypeError 异常obj 的 toString 方法, 如果为原始值, 则返回, 否则下一步obj 的 valueOf 方法, 后续同上TypeError 异常两者的主要区别在于调用 toString 和 valueOf 的先后顺序。默认情况下:
Date 对象, 则 type 默认为 stringtype 默认为 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]"