JS 中的隐式转换

JS 中有个“经典”的面试题:请问 [] == ![] 的结果是什么?一眼看上去肯定是 false,但结果却是 true,要清楚为什么是这样,就要了解 JS 在进行数据比较时的隐式转换规则是怎样的?

注:除了对本问题的解释部分,其他都来自 JavaScript 高级程序设计,建议看书!我这里摘出了其中两点,来作为对常见问题的解释,其实还有其他细节或特殊注意的地方,建议在精力充沛的情况下可以自己去探索!

相等操作符规则

在转换不同的数据类型时,相等和不相等操作符遵循下列基本规则:

1 . 如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值,false 转换为 0,而 true 转换为 1
2 . 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转换为数值
3 . 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf()方法,用得到的基本类型值按照前面的规则进行比较

这两个操作符在进行比较时又要遵循下列特殊的情况:

1 . null 和 undefined 是相等的
2 . 要比较相等性之前,不能将 null 和 undefined 转换成其他任何值
3 . 如果有一个操作数是 NaN,则相等操作符返回 false,而不相等操作符返回 true。重要提示:即使两个操作数都是 NaN,相等操作符也返回 false;因为按照规则,NaN 不等于 NaN
4 . 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true;否则,返回 false

关系操作符规则

当关系操作符的操作数使用了非数值时,也要进行数据转换或完成某些奇怪的操作。以下就是相应的规则:

1 . 如果两个操作数都是数值,则执行数值比较
2 . 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值
3 . 如果一个操作数是数值,则将另一个操作数转换为一个数值,然后执行数值比较
4 . 如果一个操作数是对象,则调用这个对象的 valueOf()方法,用得到的结果按照前面的规则执行比较。如果对象没有 valueOf()方法,则调用 toString()方法,并用得到的结果根据前面的规则执行比较
5 . 如果一个操作数是布尔值,则先将其转换为数值,然后再执行比较

解释 [] == ![]

1
[] == ![]

Step1: ! 的优先级比 == 高,先执行 ![],除了 null、undefined、’’、NaN、0 都是 true,所以 ![] 是 false

1
[] == false

Step2: 参考相等操作符比较的第 1 条规则,如果有一个操作数是布尔值,则在比较相等性之前先将其转换为数值,故结果如下:

1
[] == 0

Step3: 参考相等操作符比较的第 3 条规则,调用对象的 valueOf() 方法得到原始值,并将原始值转换为数字结果如下:

1
Number([].valueOf()) == 0