8.3 JavaScript 抽象相等比较算法
一、基本事实
console.log(null == 0); // false
console.log(null >= 0); // true
console.log(null <= 0); // true
console.log(null > 0); // false
console.log(null < 0); // false
注意:
==
和关系运算符(如>=
,<=
)的行为不同!
二、null == 0
为什么是 false
?
抽象相等比较(==
)规则(ECMAScript 规范)
当执行 x == y
时,JavaScript 会根据类型进行一系列转换。关键规则如下(简化版):
- 如果
x
是null
且y
是undefined
,返回true
。 - 如果
x
是null
或undefined
,且y
不是null
/undefined
,不会进行数字转换,直接返回false
。
因此:
null == 0
// → null 不等于 undefined,且 0 是 number 类型
// → 根据规则,null 只与 undefined 相等(在 == 下)
// → 返回 false
✅ 结论:
null == 0
是false
,因为null
在==
中只与undefined
相等,不参与数字转换。
三、为什么 null >= 0
是 true
?
这是最容易让人困惑的地方!
关系运算符(<
, <=
, >
, >=
)的处理方式不同!
关系运算符不会使用抽象相等比较算法,而是使用 ToNumber 转换。
根据 ECMAScript 规范(Relational Operators):
- 对两个操作数分别调用 ToPrimitive(通常返回自身)。
- 如果两个操作数都是字符串,按字典序比较。
- 否则,将两个操作数都转换为 数字(使用
ToNumber
)。 - 然后比较数字。
而 ToNumber(null)
的结果是 +0
!
Number(null) // 0
所以:
null >= 0
// → ToNumber(null) = 0, ToNumber(0) = 0
// → 0 >= 0 → true
同理:
null <= 0 // true (0 <= 0)
null > 0 // false(0 > 0 → false)
null < 0 // false(0 < 0 → false)
✅ 关键点:关系运算符会把
null
转为0
,而==
不会!
四、对比总结
表达式 | 结果 | 原因 |
---|---|---|
null == 0 | false | == 中 null 只等于 undefined ,不转数字 |
null === 0 | false | 严格相等,类型不同 |
null >= 0 | true | 关系运算符将 null 转为 0 |
null <= 0 | true | 同上 |
null > 0 | false | 0 > 0 为假 |
null < 0 | false | 0 < 0 为假 |
五、实际建议
避免使用
==
,改用===
,防止隐式类型转换带来的陷阱。比较
null
时,显式判断:if (value == null) // 可用于同时检查 null 和 undefined if (value === null) // 仅检查 null
不要用关系运算符直接和
null
比较,除非你明确知道它会被转为0
。
六、扩展:undefined
的行为
undefined == 0 // false
undefined >= 0 // false(Number(undefined) → NaN,任何比较都为 false)
因为 Number(undefined)
是 NaN
,而 NaN
与任何值(包括自己)的比较都是 false
。
总结
null == 0
为 false
是因为 ==
对 null
有特殊处理(只与 undefined
相等),而关系运算符会将 null
转为 0
,导致看似矛盾的行为。这是 JavaScript 类型系统中一个经典“陷阱”,理解其背后的转换机制是写出健壮代码的关键。