为什么 [] == ![] 是 true?
[] == ![] 是 JavaScript 隐式类型转换里很经典的一道题。它的结果是 true,但原因不是“空数组是假值”,而是多个操作符按不同规则依次转换后的结果。
一、先看结论
[] == ![] // true
二、推导链路
| 步骤 | 表达式状态 | 原因 |
|---|---|---|
| 原式 | [] == ![] |
初始状态 |
| 步 1 | [] == false |
1.! 的优先级高于 ==,所以![]会先计算,2.所有对象在布尔语境下都是真值,空数组也一样。 Boolean([]) // true3. ![]得到 false |
| 步 2 | [] == 0 |
1.宽松相等 == 中,如果一边是布尔值,布尔值会先转成数字2.布尔值 false 转换为数字 0 |
| 步 3 | "" == 0 |
1.左边是对象,右边是数字。对象参与 == 比较时,会先转成原始值。2.空数组转原始值流程:[] → [].valueOf() → [].toString() → “” 3.空数组 [] 转换为字符串 "" |
| 步 4 | 0 == 0 |
1.字符串和数字用 == 比较时,字符串会转成数字,Number(“”) → 02.空字符串 "" 转换为数字 0 |
| 结果 | true |
两者完全相等 |
根据 ECMAScript 的官方规范,当使用 ==(宽松相等)进行比较时,只要有一侧是对象(Object),另一侧是原始类型(String、Number、Symbol、Boolean),JavaScript 都会对对象这一侧调用内部的 ToPrimitive 操作,将其转换为原始值,然后再进行下一步的比较。
三、实际开发建议
业务代码里不建议依赖这种隐式转换。判断数组是否为空,应该看 length;比较值时,优先使用 ===,必要时先做显式类型转换。
const list = [];
if (list.length === 0) {
console.log('数组为空');
}
四、总结
[] == ![] 为 true,核心原因是:![] 先得到 false,随后 false 转成 0,空数组转成空字符串,空字符串再转成 0。它不是说明空数组是假值,而是说明 == 的隐式转换链路很复杂。