javascript中的相等性判断
JavaScript
提供三种不同的值比较操作:
- 严格相等 (“triple equals” 或 “identity”),使用
===
- 宽松相等 (“double equals”) ,使用
==
- 以及
Object.is
(ECMAScript 2015/ ES6 新特性)
选择使用哪个操作取决于你需要什么样的比较。
简而言之,在比较两件事情时,双等号将执行类型转换; 三等号将进行相同的比较,而不进行类型转换 (如果类型不同, 只是总会返回 false
); 而Object.is
的行为方式与三等号相同,但是对于NaN
和 -0
和 +0
进行特殊处理,所以最后两个不相同,而Object.is
(NaN,NaN)将为 true
。(通常使用双等号或三等号将 NaN
与 NaN
进行比较,结果为 false
) 请注意,所有这些之间的区别都与其处理原语有关; 这三个运算符的原语中,没有一个会比较两个变量是否结构上概念类似。对于任意两个不同的非原始对象,即便他们有相同的结构, 以上三个运算符都会计算得到 false
。
严格相等 ===
全等操作符比较两个值是否相等,两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型,这两个值是不全等的。否则,如果两个被比较的值类型相同,值也相同,并且都不是 number
类型时,两个值全等。最后,如果两个值都是 number
类型,当两个都不是 NaN
,并且数值相同,或是两个值分别为 +0 和 -0
时,两个值被认为是全等的。
1 | var num = 0; |
在日常中使用全等操作符几乎总是正确的选择。对于除了数值之外的值,全等操作符使用明确的语义进行比较:一个值只与自身全等。对于数值,全等操作符使用略加修改的语义来处理两个特殊情况:第一个情况是,浮点数 0
是不分正负的。区分 +0 和 -0
在解决一些特定的数学问题时是必要的,但是大部分情况下我们并不用关心。全等操作符认为这两个值是全等的。第二个情况是,浮点数包含了 NaN
值,用来表示某些定义不明确的数学问题的解,例如:正无穷加负无穷。全等操作符认为 NaN
与其他任何值都不全等,包括它自己。(等式 (x !== x) 成立的唯一情况是 x 的值为 NaN)
宽松相等 ==
相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 ===
的比较方式。 相等操作符满足交换律。
一般而言,根据 ECMAScript
规范,所有的对象都与 undefined
和 null
不相等。但是大部分浏览器允许非常窄的一类对象(即,所有页面中的 document.all
对象),在某些情况下,充当效仿 undefined
的角色。相等操作符就是在这样的一个背景下。因此,IsFalsy(A)
方法的值为 true
,当且仅当 A 效仿 undefined
。在其他所有情况下,一个对象都不会等于 undefined
或 null
。
1 | var num = 0; |
Object.is()
ES5
比较两个值是否相等,只有两个运算符:相等运算符 ==
和严格相等运算符 ===
。它们都有缺点,前者会自动转换数据类型,后者的 NaN
不等于自身,以及 +0
等于 -0
。JavaScript
缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
ES6
提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is
就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符 ===
的行为基本一致。
1 | Object.is('foo', 'foo') |
不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
1 | +0 === -0 //true |
ES5
可以通过下面的代码,部署 Object.is
。
1 | Object.defineProperty(Object, 'is', { |
判等对照表
x | y | == | === | Object.is() |
---|---|---|---|---|
undefined | undefined | true | true | true |
null | null | true | true | true |
true | true | true | true | true |
false | false | true | true | true |
“foo” | “foo” | true | true | true |
0 | 0 | true | true | true |
+0 | -0 | true | true | false |
0 | false | true | false | false |
“” | false | true | false | false |
“” | 0 | true | false | false |
“0” | 0 | true | false | false |
“17” | 17 | true | false | false |
[1,2] | “1,2” | true | false | false |
new String(“foo”) | “foo” | true | false | false |
null | undefined | true | false | false |
null | false | false | false | false |
undefined | false | false | false | false |
{ foo: “bar” } | { foo: “bar” } | false | false | false |
new String(“foo”) | new String(“foo”) | false | false | false |
0 | null | false | false | false |
0 | NaN | false | false | false |
“foo” | NaN | false | false | false |
NaN | NaN | false | false | true |