欢迎订阅前端面试知识学爆系列:
一次理解执行上下文、作用域链、闭包,最通俗易懂的一集 - 掘金 (juejin.cn)
翻遍MDN,我做出了最新最全数组相关知识点归纳总结,最系统全面的一集 - 掘金 (juejin.cn)
废话不多说,我们现在开始~
JavaScript有4种相等比较算法:
===
——严格相等(IsStrictlyEqual)==
——宽松相等 (IsLooselyEqual)Object.is()
——同值相等 (SameValue)- 未公开作为API ——零值相等 (SameValueZero)
4种算法都有对NaN
、-0
和 +0
的特殊处理。
严格相等比较 ===
===
首先会检查两个值的类型是否相同,之后再对比两个值是否一致。
换句话说,不仅要对比两者的值,还要对比两者的类型。
特殊处理:NaN
不等于自身,+0
和-0
是相等的。
宽松相等比较 ==
==
不像===
那样严格,对于一般情况,只要值相等,就返回true
,但==
遇到两值类型不同时,会进行隐式类型转换,使得两值类型相同。
关于类型转换,之后我可能单独出一篇文章详细讲,这里仅比较4种算法差异。
特殊处理:与===
一样,NaN
不等于自身,+0
和-0
相等。
大多情景下,为了考虑到程序的健壮性,我们会偏向使用===
而不是==
。
同值相等比较 Object.is()
简单来讲,就是使得NaN
可以等于自身,+0
和-0
不相等,其他表现和===
一致。
一种可能的场景是在数学计算中,特别是涉及除法和倒数的计算。在JavaScript中,1/+0
会返回正无穷大(Infinity
),而1/-0
则会返回负无穷大(-Infinity
)。在需要进行这种计算的情况下,保持+0
和-0
的区分是重要的。
还有一个产生-0
的例子,使用 Math.pow
函数将 -Infinity
的任何负奇数次幂求值为 -0
:
console.log(Math.pow(-Infinity, -1)); // -0
console.log(Math.pow(-Infinity, -3)); // -0
所以如果你要考虑到数学计算、或是开发一些通用库时,Object.is()
是更好的选择。
我们可以手写一个:
function is(x, y) {
if (x === y) {
//运行到1/x === 1/y的时候x和y都为0,但是1/+0 = +Infinity, 1/-0 = -Infinity, 是不一样的
return x !== 0 || y !== 0 || 1 / x === 1 / y;
} else {
//NaN===NaN是false,这是不对的,我们在这里做一个拦截,x !== x,那么一定是 NaN, y 同理
//两个都是NaN的时候返回true
return x !== x && y !== y;
}
}
零值相等比较
简单来讲,就是使得NaN
依然可以等于自身,但+0
和-0
又相等了(“零”值比较嘛),其他表现和===
一致。
零值相等被许多内置运算使用,它在搜索期间通常具有最实用的行为,特别是在与 NaN
一起使用时。它被用于 Array.prototype.includes()
、TypedArray.prototype.includes()
及 Map
和 Set
方法用来比较键的相等性。
let map = new Map();
map.set(+0, "positive zero");
map.set(-0, "negative zero");
console.log(map.get(+0)); // "negative zero"
console.log(map.get(-0)); // "negative zero"
> negative zero
> negative zero
map.set(NaN,1)
> Map(2) {0 => 'negative zero', NaN => 1}
map.set(NaN,'NaN');
console.log(map.get(NaN));
> NaN
//键的比较符合零值相等的规则
一些没有使用零值相等算法
的数组方法如查找索引的(indexOf()
、lastIndexOf()
)不能找到 NaN
,而查找值的(includes()
)可以:
const arr = [2, 4, NaN, 12];
arr.indexOf(NaN); // -1
arr.includes(NaN); // true
// 需要借助isNaN方法
arr.findIndex((n) => Number.isNaN方法(n)); // 2
零值相等不作为 JavaScript API 公开,但可以通过自定义代码实现:
function sameValueZero(x, y) {
if (typeof x === "number" && typeof y === "number") {
// x 和 y 相等(可能是 -0 和 0)或它们都是 NaN
return x === y || (x !== x && y !== y);
}
return x === y;
}
总结
==
比较值遇到类型不同会转换===
不会转换会连同类型一起比较。 这两种算法中NaN不等于自身,+0和-0相等。Object.is()
使得NaN
可以等于自身,+0
和-0
不相等,其他表现和===
一致。- 零值相等使得
NaN
可以等于自身,+0
和-0
相等,其他表现和===
一致。 - 不要忘了,无论哪种算法遇到非原始值比较的就都是内存地址了~
遇到类似的面试题再提一嘴零值相等比较,应该也会加分罢
学到了记得点个赞!
参考: