诱因
之前写的一篇文章已经简单介绍过了 ==
与 ===
的比较运算符(见《JavaScript 中 == 与 === 的区别》一文)了,之所以再谈 JavaScript
中的相等比较,缘于昨天下午,同事出了一道灵魂拷问的题目:null == 0
的比较结果是什么?
这还用想吗,==
比较在类型不同时会隐式类型转换,最终结果为 true
呗……
但,等会儿,结果会这么简单?嗯,应该不简单。
简单测试一下,果然,运行结果为 false
。
小朋友,你是否有很多的问号???
==
确实是一个令人头痛的运算符,它的语法行为多变,不符合直觉,为了一劳永逸,还是把 ==
和 ===
一次性搞清楚了吧。
规范
运算符==说明
为了弄清楚 null == 0
结果为 false
的原因,查阅 ECMAScript® 2019 Language Specification,在 7.2.14 节中有详细的说明:
7.2.14 Abstract Equality Comparison
The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
- If Type(x) is the same as Type(y), then Return the result of performing Strict Equality Comparison x === 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 comparison ! ToNumber(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, return the result of the comparison x == ToPrimitive(y).
- If Type(x) is Object and Type(y) is either String, Number, or Symbol, return the result of the comparison ToPrimitive(x) == y.
- Return false.
这段关于 x == y
的比较,总共有10步,简单翻译如下:
- 如果
Type(x)
与Type(y)
相等,则返回x === y
的比较结果。(x === y
的比较说明在 7.2.15 节 Strict Equality Comparison中)。 - 如果
x
为null
,y
为undefined
,则返回true
。 - 如果
x
为undefined
,y
为null
,则返回true
。 - 如果
Type(x)
是Number
,Type(y)
是String
,则返回x == ToNumber(y)
的比较结果。(! ToNumber(y) 不是对转换结果取!
运算,而是ReturnIfAbrupt()
的简写方式,而ReturnIfAbrupt()
会判断如果参数不是正常值时中断执行,详见 5.2.3.4 ReturnIfAbrupt Shorthands 的说明)。 - 如果
Type(x)
是String
,Type(y)
是Number
,则返回ToNumber(x) == y
的比较结果。 - 如果
Type(x)
是Boolean
,则返回ToNumber(x) == y
的比较结果。 - 如果
Type(y)
是Boolean
,则返回x == ToNumber(y)
的比较结果。 - 如果
Type(x)
是String
、Number
或Symbol
,Type(y)
是Object
,则返回x == ToPrimitive(y)
的比较结果。 - 如果
Type(x)
是Object
,Type(y)
是String
、Number
或Symbol
,则返回ToPrimitive(x) == y
的比较结果。 - 其它情况,返回
false
。
步骤中的 Type()
方法是取参数的数据类型,在 6 ECMAScript Data Types and Values 有其说明:
Within this specification, the notation “Type(x)” is used as shorthand for “the type of x” where “type” refers to the ECMAScript language and specification types defined in this clause.
这和 JavaScript
中的 typeof
运算符的结果不同。ECMAScript
中定义的类型有 Undefined
,Null
,Boolean
,String
,Symbol
,Number
和 Object
。
再来分析 null == 0
的判断,null
的类型为 Null
,根据以上步骤分析,前9步条件都不满足,所以最终返回结果应该为 false
。
运算符===说明
7.2.15 Strict Equality Comparison
The comparison x === y, where x and y are values, produces true or false. Such a comparison is performed as follows:
If Type(x) is different from Type(y), return false.
If Type(x) is Number, then
a. If x is NaN, return false.
b. If y is NaN, return false.
c. If x is the same Number value as y, return true.
d. If x is +0 and y is -0, return true.
e. If x is -0 and y is +0, return true.
f. Return false.
Return SameValueNonNumber(x, y).
NOTE This algorithm differs from the SameValue Algorithm in its treatment of signed zeroes and NaNs.
===
是严格比较相等,步骤翻译如下:
-
如果
x
与y
的类型不一致,返回false
; -
如果
x
类型为Number
,继续判断:a. 如果
x
是NaN
,返回false
;b. 如果
y
是NaN
,返回false
;c. 如果
x
与y
是相同的数字值,返回true
;d. 如果
x
是+0
,y
是-0
,返回true
;e. 如果
x
是-0
,y
是+0
,返回true
;f. 否则返回
false
。 -
返回
SameValueNonNumber(x, y)
的运算结果。
注意:这个算法和 SameValue
算法的不同之处在于对有符号 0
和 NaN
的处理。
继续查看 SameValueNonNumber(x, y) 算法:
7.2.12 SameValueNonNumber ( x, y )
The internal comparison abstract operation SameValueNonNumber(x, y), where neither x nor y are Number values, produces true or false. Such a comparison is performed as follows:
Assert: Type(x) is not Number.
Assert: Type(x) is the same as Type(y).
If Type(x) is Undefined, return true.
If Type(x) is Null, return true.
If Type(x) is String, then
a. If x and y are exactly the same sequence of code units (same length and same code units at corresponding indices), return true; otherwise, return false.
If Type(x) is Boolean, then
a. If x and y are both true or both false, return true; otherwise, return false.
If Type(x) is Symbol, then
a. If x and y are both the same Symbol value, return true; otherwise, return false.
If x and y are the same Object value, return true. Otherwise, return false.
-
断言
x
类型为Number
; -
断言
x
与y
类型相同; -
如果
x
类型为Undefined
,返回true
; -
如果
x
类型为Null
,返回true
; -
如果
x
类型为String
,继续判断:a. 如果
x
和y
是相同的字符串序列(相同长度,各位置字符也相同),返回true
,否则返回false
。 -
如果
x
类型为Boolean
,继续判断:a. 如果
x
和y
都是true
或都是false
,返回true
,否则返回false
。 -
如果
x
类型是Symbol
,继续判断:a. 如果
x
和y
是相同的Symbol
值,返回true
,否则返回false
。 -
如果
x
和y
是相同的对象值,返回true
,否则返回false
。
以上就是在 ECMAScript
规范中关于 ==
与 ===
相等比较的说明。