JS相等判别全解析:==、===、Object.is()、同值相等、零值相等
希望这篇文章能成为您日后查询相等判别知识的字典
==(相等)
相等操作符会先进行强制类型转换,再确定操作数是否相等。
类型转换规则
- 任一操作符是布尔值,将其转换为数值。
- 一个操作符是字符串,一个操作符是数值,先将字符串转换为数值。
- 一个操作数是对象,另一个不是,将对象转换为原始值。
比较规则
- null和undefined相等。
- null和undefined不能转换为其他类型的值进行比较。(只要和null和undefined比较的不是null或undefined,就返回false)。
- 如果有任一操作数是NaN,相等操作符返回false。
输出示例
console.log(null == undefined);// true
console.log(NaN == NaN);// false
经典面试题 - [] == ![]
面试官经常会问,为什么[] == ![],实际上就是按照上述规则进行类型转换与比较的过程
console.log([] == ![]);// true
- ![]会被转换为false
- 对于任一操作符是布尔值,将其转换为数值。false => 0
- 一个操作符是对象,另一个不是,取得对象原始值。[] => ''
- 一个操作符是字符串,一个操作符是数值,将字符串转为数值。'' => 0
- 0 == 0
===(全等)
全等操作符不会进行强制类型转换,只要操作数的类型不同或者引用数据类型的引用地址不同,都会返回false。
特殊情况
// 浮点数特殊情况
console.log(-0 === +0);//true
console.log(NaN === NaN);//false
// 类型不同的值始终不相等
console.log(1 === '1'); // false
console.log(true === 1); // false
console.log(null === undefined); // false
// 两个对象引用同一个内存地址才被认为是相等的
let obj1 = { a: 1 };
let obj2 = { a: 1 };
console.log(obj1 === obj2); // false (不同的引用)
console.log(obj1 === obj1); // true (相同的引用)
console.log([] === []);// false
除了
===之外,数组索引查找方法也使用严格相等,包括 Array.prototype.indexOf()、Array.prototype.lastIndexOf()、TypedArray.prototype.index()、TypedArray.prototype.lastIndexOf() 和 case 匹配。这意味着你不能使用indexOf(NaN)查找数组中NaN值的索引,也不能将NaN用作case值在switch语句中匹配任何内容。
Object.is() | 同值相等(SameValue)
为什么将Object.is()和同值相等(SameValue)放在一起呢?相同的判别规则。
同值相等由Object.is()方法提供。
Object.is()提供了一种更严格的相等比较方法,解决了===无法正确处理NaN和-0/+0的问题
特殊情况判定规则
// 正确的0、-0、+0相等/不等判定
console.log(Object.is(+0, -0));//false
console.log(Object.is(+0, 0));//true
console.log(Object.is(-0, 0));//false
// 正确的NaN相等判定
console.log(Object.is(NaN, NaN));//true
对比===
console.log(Object.is(-0, +0));//false
console.log(-0 === +0);//true
console.log(Object.is(NaN, NaN));//true
console.log(NaN === NaN);//false
Object.is()判定多个值相等
//工具函数:要检查超过两个值,递归地利用相等性传递即可
function recursivelyCheckEqual(x, ...rest) {
return Object.is(x, rest[0]) &&
(rest.length < 2 || recursivelyCheckEqual(...rest));
}
零值相等(SameValueZero)
将NaN视作相等,将+0和-0视作相等。
Map数据结构基于零值相等算法,我们可以借助Map数据结构验证:
const m = new Map();
//Map内部使用SameValueZero比较操作,基本上相当于使用严格对象相等的标准来检查键的匹配性
const a = 0/"",//NaN
b = 0/"";//NaN
const pz = +0;
const nz = -0;
console.log(a === b);//false
console.log(pz === nz);//true
m.set(a, "foo");
m.set(pz, "bar");
console.log(m.get(b));// foo
console.log(m.get(nz));// bar
自定义代码实现
零值相等不作为 JavaScript API 公开,但可以通过自定义代码实现:
function SameValueZero(x, y) {
if (typeof x === 'number' && typeof y === 'number') {
return x === y || (x !== x && y !== y)
}
return x === y
}
console.log(SameValueZero(NaN, NaN));// true
console.log(SameValueZero(-0, +0));// true