为什么 [] == ![] 是 true?

2022/08/18

为什么 [] == ![] 是 true?

[] == ![] 是 JavaScript 隐式类型转换里很经典的一道题。它的结果是 true,但原因不是“空数组是假值”,而是多个操作符按不同规则依次转换后的结果。

一、先看结论

[] == ![] // true

二、推导链路

步骤 表达式状态 原因
原式 [] == ![] 初始状态
步 1 [] == false 1.! 的优先级高于 ==,所以![]会先计算,
2.所有对象在布尔语境下都是真值,空数组也一样。Boolean([]) // true
3.![]得到 false
步 2 [] == 0 1.宽松相等 == 中,如果一边是布尔值,布尔值会先转成数字
2.布尔值 false 转换为数字 0
步 3 "" == 0 1.左边是对象,右边是数字。对象参与 == 比较时,会先转成原始值。
2.空数组转原始值流程:[] → [].valueOf() → [].toString() → “”
3.空数组 [] 转换为字符串 ""
步 4 0 == 0 1.字符串和数字用 == 比较时,字符串会转成数字,Number(“”) → 0
2.空字符串 "" 转换为数字 0
结果 true 两者完全相等

根据 ECMAScript 的官方规范,当使用 ==(宽松相等)进行比较时,只要有一侧是对象(Object),另一侧是原始类型(String、Number、Symbol、Boolean),JavaScript 都会对对象这一侧调用内部的 ToPrimitive 操作,将其转换为原始值,然后再进行下一步的比较。

三、实际开发建议

业务代码里不建议依赖这种隐式转换。判断数组是否为空,应该看 length;比较值时,优先使用 ===,必要时先做显式类型转换。

const list = [];

if (list.length === 0) {
  console.log('数组为空');
}

四、总结

[] == ![]true,核心原因是:![] 先得到 false,随后 false 转成 0,空数组转成空字符串,空字符串再转成 0。它不是说明空数组是假值,而是说明 == 的隐式转换链路很复杂。