跳到主要内容

Object.is 和 === 的区别是什么?

面试速答(30 秒版 TL;DR)​

  • 大多数情况下:Object.is(a, b) 与 a === b 结果相同。
  • 两个关键差异(必须背):
    • NaN:NaN === NaN 是 false,但 Object.is(NaN, NaN) 是 true。
    • +0/-0:+0 === -0 是 true,但 Object.is(+0, -0) 是 false。
  • 口径:=== 是“严格相等(Strict Equality)”,Object.is 更接近“同值相等(SameValue)”。

为什么会有差异?​

可以把它理解成“规范层面的相等算法不同”:

  • ===:对 NaN 特判为不相等;不区分 +0/-0。
  • Object.is:把 NaN 视为等于自身;区分 +0/-0。

这两个差异本质上都来自 IEEE 754 浮点数的一些边界行为。


一眼看懂的例子​

// 1) NaN
NaN === NaN; // false
Object.is(NaN, NaN); // true

// 2) +0 / -0
0 === -0; // true
Object.is(0, -0); // false

// 3) 其他大多数情况
Object.is("a", "a") === ("a" === "a"); // true
Object.is({}, {}) === ({} === {}); // true,都为 false(引用不同)

什么时候用 Object.is 更合适?​

  • 你需要把 NaN 当作“等于自身”的值来比较(例如一些数值计算结果的稳定性判断)。
  • 你需要区分 +0 和 -0(极少见,但可能出现在数值分析/底层库中)。
  • 你在写一些通用工具函数,希望在边界上更“精确”。

业务代码里绝大多数比较仍然用 === 即可,语义更直观。


典型题 & 标准答法​

Q1:那 Object.is 是不是可以完全替代 ===?​

不建议这么说。面试回答可以是:

  • “绝大多数情况下两者一致,我默认用 ===,只有在需要 NaN 自反性或区分 +0/-0 时用 Object.is。”

Q2:Map / Set / includes 用的是哪种相等?​

常见口述点(记住结论即可):

  • Array.prototype.includes 会把 NaN 当作可匹配到(这点和 indexOf 不同)。
  • Map/Set 的 key 匹配也能匹配到 NaN。

你可以用下面的小例子记忆验证:

[NaN].indexOf(NaN); // -1
[NaN].includes(NaN); // true

const s = new Set([NaN]);
s.has(NaN); // true

易错点/坑(速记)​

  • Object.is 不是“深相等”,对象比较依然是引用比较:Object.is({}, {}) 仍为 false。
  • 不要把 Object.is 和 == 混在一起讲:== 涉及类型转换,是另一套话题。