前言
之前看到一个思考题,是关于js的相等运算和隐式类型转换的,大部分都还好理解,但是看到了一个看起来很不合常理的结果,让我们一起来探究下。
console.log([] == ![])
// true
复制代码
看以上的题目,左边一个空数组,右侧一个空数组取反,乍一看很容易得出结果是 false
,但真正运行的时候才发现结果居然是 true
.这是什么原因呢?
隐式类型转换
我去查了下 MDN Web Doc 关于 「相等(==)运算的文档(文档介绍),上面介绍了与严格相等运算符(===)不同,它会尝试强制类型转换并且比较不同类型的操作数。
具体的类型转换规则如下:
- 如果两个操作数都是对象,则仅当两个操作数都引用同一个对象时才返回true。
- 如果一个操作数是null,另一个操作数是undefined,则返回true。
- 如果两个操作数是不同类型的,就会尝试在比较之前将它们转换为相同类型:
- 当数字与字符串进行比较时,会尝试将字符串转换为数字值。
- 如果操作数之一是Boolean,则将布尔操作数转换为1或0。
- 如果是true,则转换为1。
- 如果是 false,则转换为0。
- 如果操作数之一是对象,另一个是数字或字符串,会尝试使用对象的valueOf()和toString()方法将对象转换为原始值。
- 如果操作数具有相同的类型,则将它们进行如下比较:
- String:true仅当两个操作数具有相同顺序的相同字符时才返回。
- Number:true仅当两个操作数具有相同的值时才返回。+0并被-0视为相同的值。如果任一操作数为NaN,则返回false。
- Boolean:true仅当操作数为两个true或两个false时才返回true。
依据上述规则,我们来解析一下 [] == ![]
执行隐式类型转换的过程:
[]
是一个 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
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END