一、前言
先说答案:
null == 0 // false
null > 0 // false
null >= 0 //true
null <= 0 //true
很多人认为 null 应该转化成 0 ,然后 0 === 0 为true。其实这是对操作符在转换操作数类型时的规则不熟悉导致的。
实际上,在javascript不同操作符的类型的转化规则是不同的且相互独立。并且一些操作符对特定的类型制定了特殊的规则。
二、为什么
1.null == 0 为false
- 先看一下在 '==' 操作符下的比较规则
《JavaScript高级程序设计(第4版)》中第3章的 3.5.8 相等操作符中指出:
在转换操作数的类型时,相等和不相等操作符遵循如下规则
如果任一操作数是布尔值,则将其转换为数值再比较是否相等。 false 转换为 0 , true 转换为 1 。 如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等。 如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf() 方法取得其原始值,再 根据前面的规则进行比较。在进行比较时,这两个操作符会遵循如下规则。 null 和 undefined 相等。 null 和 undefined 不能转换为其他类型的值再进行比较。 如果有任一操作数是 NaN ,则相等操作符返回 false ,不相等操作符返回 true 。记住:即使两 个操作数都是 NaN ,相等操作符也返回 false ,因为按照规则, NaN 不等于 NaN 。 如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回 true 。否则,两者不相等。
通过上面规则我们可以看到对null 和undefined制定了特殊的规则,即 null 和 undefined 不能转换为其他类型的值再进行比较。所以在null == 0 的判断中,不能将null 转化为0比较,同时也没有其他规则可以遵循,所以最后会返回 false。
同样的,根据规则 undefined == 0 也返回 false。
2.null >= 0 为true
- 在看看关系操作符(包括小于(<)、大于(>)、小于等于(<=)和大于等于(>=))的规则
《JavaScript高级程序设计(第4版)》中第3章的 3.5.7 关系操作符中指出:与 ECMAScript 中的其他操作符一样,在将它们应用到不同数据类型时也会发生类型转换和其他行为。 如果操作数都是数值,则执行数值比较。 如果操作数都是字符串,则逐个比较字符串中对应字符的编码。 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。 如果有任一操作数是对象,则调用其 valueOf() 方法,取得结果后再根据前面的规则执行比较。如果没有 valueOf() 操作符,则调用 toString() 方法,取得结果后再根据前面的规则执行比较。 如果有任一操作数是布尔值,则将其转换为数值再执行比较。
可以看到,在关系操作符中有 如果有任一操作数是数值,则将另一个操作数转换为数值,执行数值比较。这一条规则,因此在 null >= 0 时,由于有 '0' 这个操作数为数值,另一个操作数会进行转换,将null 转化为 0 然后 0 === 0 ,返回 true。
同理:
null > 0 //false
null <= 0 //true
三、算法细节
其实看过上面的规则后,已经可以判断出正确答案了,但是这些规则都是一些具体算法的描述总结,而底层实现源码也不是容易看懂的。恰好在知乎上看到一个回答,给出了一个判断的过程,也可以让我们感受一下底层是如何判断的:
Return If Abrupt(x).
Return If Abrupt(y).
If Type(x) is the same as Type(y), then
Return the result of performing Strict Equality Comparisonx === y.
If x is null and y is undefined, return true.
If x is undefined and y is null, return true.
If Type(x) is Number and Type(y) is String,
return the result of the comparison x == ToNumber(y).
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
If Type(x) is Boolean, return the result of the comparisonToNumber(x) == y.
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
If Type(x) is either String, Number, or Symbol and Type(y)is Object, then
return the result of the comparison x == ToPrimitive(y).
If Type(x) is Object and Type(y) is either String, Number, or Symbol, then
return the result of the comparison ToPrimitive(x) == y.
Return false.
即下方的步骤:
- 如果x不是正常值(比如抛出一个错误),中断执行。
- 如果y不是正常值,中断执行。
- 如果Type(x)与Type(y)相同,执行严格相等运算x === y。
- 如果x是null,y是undefined,返回true。
- 如果x是undefined,y是null,返回true。
- 如果Type(x)是数值,Type(y)是字符串,返回x == ToNumber(y)的结果。
- 如果Type(x)是字符串,Type(y)是数值,返回ToNumber(x) == y的结果。
- 如果Type(x)是布尔值,返回ToNumber(x) == y的结果。
- 如果Type(y)是布尔值,返回x == ToNumber(y)的结果。
- 如果Type(x)是字符串或数值或Symbol值,Type(y)是对象,返回x == ToPrimitive(y)的结果。
- 如果Type(x)是对象,Type(y)是字符串或数值或Symbol值,返回ToPrimitive(x) == y的结果。
- 返回false。
作者:老猫爱打盹
链接:https://www.zhihu.com/question/52666420/answer/132231109
四、'==' 的一些特殊情况及比较的结果
表 达 式
| 结果 |
---|---|
null == undefined
|
true
|
"NaN" == NaN
|
false
|
5 == NaN
| false |
NaN == NaN
|
false
|
NaN != NaN
|
true
|
false == 0
|
true
|
true == 1
|
true
|
true == 2
|
false
|
undefined == 0
|
false
|
null == 0
|
false
|
"5" == 5
|
true
|
五、参考资料
[美]马特·弗里斯比(Matt Frisbie)著 李松峰 译 ——《JavaScript高级程序设计(第4版)》