==、===、Object.is()区别?零值相等是什么?

213 阅读3分钟

欢迎订阅前端面试知识学爆系列:

一次理解执行上下文、作用域链、闭包,最通俗易懂的一集 - 掘金 (juejin.cn)

翻遍MDN,我做出了最新最全数组相关知识点归纳总结,最系统全面的一集 - 掘金 (juejin.cn)

废话不多说,我们现在开始~

1b9da807472c5788548642d806d17e42.jpg

JavaScript有4种相等比较算法:

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相等,其他表现和===一致。
  • 不要忘了,无论哪种算法遇到非原始值比较的就都是内存地址了~

遇到类似的面试题再提一嘴零值相等比较,应该也会加分罢

99d9942a0b934160b43ca527dfd97841.jpg

学到了记得点个赞!

参考:

JavaScript 中的相等性判断 - JavaScript | MDN (mozilla.org)

interview.poetries.top/docs/excell…