跳到主要内容

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

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

  • 大多数情况下:Object.is(a, b)a === b 结果相同。
  • 两个关键差异(必须背):
    • NaNNaN === NaNfalse,但 Object.is(NaN, NaN)true
    • +0/-0+0 === -0true,但 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== 混在一起讲:== 涉及类型转换,是另一套话题。