JS 中相等性的判断
截止至 ES6,有四种相等判断的算法
- 全等 (三等)
=== - 等于
== - 零值相等
-0 === +0 - 同值相等
-0 !== +0
NaN === NaN
JS 提供有关相等判断的方法
严格相等
- ===
- Strict Equality
不进行隐匿类型转换 类型相同,值也相同
1 === '1'
? false1 === 2
? false引用值必须是同一地址
var obj = {}; obj === obj
? true{} === {}
? false两个 NaN 或者是 NaN 跟其它值都不相等
NaN === NaN
? falseNaN === undefined
? false +0 和 -0 相等+0 === -0
? trueInfinity 与 Infinity 相等
Infinity === Infinity
? true+Infinity 与 -Infinity 不相等
+Infinity === -Infinity
? false
面试题
如何定义变量 a,使 a !== a
为 true?
那么 a = NaN
非严格(抽象/非约束)相等
- ==
- 学述上叫法:Loose (自由的,不受限制的) Equality
- 一般英文描术为 Abstract Equaliy
- 隐匿类型转换 - 等式两边都有可能被隐式类型转换
- 转换以后还是用严格相等来进行比较 | | 被比较值 B | | | | | | | | —- | —- | —- | —- | —- | —- | —- | —- | | | | Undefined | Null | Number | String | Boolean | Object | | 被比较值 A | Undefined | true | true | false | false | false | IsFalsy(B) | | | Null | true | true | false | false | false | IsFalsy(B) | | | Number | false | false | A === B | A === ToNumber(B) | A === ToNumber(B) | A == ToPrimitive(B) | | | String | false | false | ToNumber(A) === B | A === B | ToNumber(A) === ToNumber(B) | ToPrimitive(B) == A | | | Boolean | false | false | ToNumber(A) === B | ToNumber(A) === ToNumber(B) | A === B | ToNumber(A) == ToPrimitive(B) | | | Object | false | false | ToPrimitive(A) == B | ToPrimitive(A) == B | ToPrimitive(A) == ToNumber(B) | A === B |
- ToNumber 尝试在比较前将参数转换为数字
- ToPrimitive 尝试调用 .toString() 和 .valueOf() 方法,将参数转换为原始值(Primitive)
- 任何对象都与 null / undefined 不相等
- 特例,除了 窄对象 Narrow Object,目前只有 document.all (废除的),仅仅在 IE10 以前
- IsFalsy 方法的值为 true
- typeof docuement.all // “undefined”
- document.all == undefined // true
严格相等的优点
- 全等对于结果的预测是更加清晰明确
- 全等在不隐式类型转换的前提下更快
注意:但不一等在所有的情况下都使用全等,在特定的情况下使用非严格也是有其意义。 例如在封装一个插件时,需要使用者传入一个参数。可以传入 1 或 ‘1’ 会使其程序更有弹性。
falsy 值(虚值)
- -0 !== +0 ```javascript var obj = {};
Object.defineProperty(obj, ‘myZero’, { value: -0, writable: false, configurable: false, enumerable: false, });
// +0/0 抛出异常,不能重新定义myZero属性,而 -0 是可以 // 所以在 Object.defineProperty 中 -0 与 +0 不是相同值 Object.defineProperty(obj, ‘myZero’, { value: +0, }); Object.defineProperty(obj, ‘myZero’, { value: 0, }); Object.defineProperty(obj, ‘myZero’, { value: -0, });
- NaN === NaN
```javascript
var obj = {};
Object.defineProperty(obj, 'myNaN', {
value: NaN,
writable: false,
configurable: false,
enumerable: false,
});
// 不会抛出异常,NaN === NaN 是同值相等
Object.defineProperty(obj, 'myNaN', {
value: NaN,
});
同值相等的底层实现
是通过 Object.is() 的方法,Object.is() 是 ES6 抛出来的,在 ES5 并没有暴露 JS 引擎的同值相等的方法。
Object.is(v1, v2)
- ES6 新的 API
- 判断两个参数是否是同一个值(同值相等的实现)
- 参数为两个值
- 返回值为同值相等判断的布尔结果
ES2015 (ES6)
Object.is(undefined, undefined); // true
Object.is(null, null); // true
Object.is('1', '1'); // true
var obj = {};
Object.is(obj, obj); // true 同一个引用
Object.is({}, {}); // false 不同引用
Object.is(1, 1); // true
Object.is(0, 0); // true
// Object.is()判断标准就是同值相等
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false
// 不进行隐式转换
Object.is(1, '1'); // false
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 |
明显看出 Object.is 与 === 的区别只有 +0与-0比较 和 NaN与NaN比较。
Polyfill
1/+0 === Infinity
1/-0 === -Infinity
如何定义变量a a!==a // true
只有a = NaN
Object.myIs = function(a, b){
if(a === b){
return a !== 0 || 1 / a === 1 / b; // 如果等于0(+0/-0)时,转为Infinity再,实现同值相等
}
return a !== a && b !== b; // a不等于a只能是NaN
}
零值相等 same-value-zero
+0 === -0