之前看到一个思考题,是关于js的相等运算和隐式类型转换的,大部分都还好理解,但是看到了一个看起来很不合常理的结果,让我们一起来探究下。
console.log([] == ![])
// true
看以上的题目,左边一个空数组,右侧一个空数组取反,乍一看很容易得出结果是 false
,但真正运行的时候才发现结果居然是 true
.这是什么原因呢?
我去查了下 MDN Web Doc 关于 「相等(==)运算的文档(具体地址:文档介绍),上面介绍了与严格相等运算符(===)不同,它会尝试强制类型转换并且比较不同类型的操作数。
具体的类型转换规则如下:
依据上述规则,我们来解析一下 [] == ![]
执行隐式类型转换的过程:
[]
是一个 Array, 也是属于 object 类型(真值),所以![]
会被解析成对对象类型取反得到 false
;得到的表达式可以转换成:[] == false
操作数之一是Boolean,则将布尔操作数转换为1或0
, 则得到新的表达式为:[] == 0
如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的valueOf()和toString()方法将对象转换为原始值
, 尝试将 []
通过valueOf/toString
方法进行转化;[].valueOf()
结果还是 []
, 所以继续使用 [].toString()
方法得到表达式:"" == 0
当数字与字符串进行比较时,会尝试将字符串转换为数字值
继续转换表达式为:0 == 0
最终得到相等的结果。({}) == {}
// false, 两个都是object, 但并不指向同一个对象,所以为false
({}) == !{}
// false, 和 [] == ![] 不同的是,Object.prototype.toString.call({}) 的结果是 "[object, object]", 并不是空字符串;
// "[object, object]" 被转换成数字的时候是 NaN,所以并不和 0 是相等的
NaN == NaN
// false, 任意一方为 NaN,结果都为 false