前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库Object.is 与 === 区别 NaN +0 -0
JavaScript对象与原型

Object.is 和 === 有什么区别?NaN 和 +0、-0 怎么比?

Object.is 和 === 只有两处不一样:Object.is(NaN, NaN) 是 true,Object.is(+0, -0) 是 false,=== 正好相反。比较两个对象时它们完全一样,都只看是不是同一个引用。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#对象与原型
先看核心答案读代码示例
理解线索

JavaScript 里的三种「相等」

  1. ===严格相等,NaN 不等于自己,+0 等于 -0
  2. Object.is同值相等,NaN 等于自己,+0 不等于 -0
  3. SameValueZeroincludes、Map、Set 用它,NaN 相等,+0 等于 -0

题目里说的「两个对象」是个陷阱。对象比较时 Object.is 和 === 没有任何差别,内容相同但不是同一个对象,两个都返回 false。

核心回答

先记住这个答案

Object.is 和 === 大部分情况下结果一样,只有两个例外:NaN === NaN 是 false,而 Object.is(NaN, NaN) 是 true;+0 === -0 是 true,而 Object.is(+0, -0) 是 false。比较两个对象时,两者都只看是不是同一个引用,内容一样但不是同一个对象,都返回 false。Object.is 用的规则叫「同值相等」,可以理解成「修掉了两个怪癖的 ===」。

  • Object.is(NaN, NaN) 为 true
  • Object.is(+0, -0) 为 false
  • 比较对象时两者都只看引用,不比内容
  • includes 使用 SameValueZero

先看两者不一样的地方

把所有差异放在一段代码里,一次看全。

NaN、+0 和对象的对比JavaScript
const n = NaN
console.log(n === n)             // false
console.log(Object.is(n, n))     // true
console.log(+0 === -0)           // true
console.log(Object.is(+0, -0))   // false

const a = { id: 1 }
const b = { id: 1 }
console.log(a === b, Object.is(a, b)) // 内容一样,但不是同一个对象
const c = a
console.log(a === c, Object.is(a, c)) // 同一个引用
查看输出与解释
false
true
true
false
false false
true true

前四行就是两者全部的差别。后两行说明对象比较时它们行为一致:a 和 b 是两块独立的内存,哪怕字段一模一样也不相等;c 只是 a 的另一个名字,所以相等。

为什么 === 会有这两个怪癖

这两处都来自 IEEE 754 浮点数标准,JavaScript 的数字就是按它实现的。

NaN 表示「不是一个有效数字」,比如 0 / 0、Number('abc') 的结果。标准规定 NaN 和任何值比较都不相等,包括它自己。所以判断一个值是不是 NaN,不能写 x === NaN,要用 Number.isNaN(x),或者 Object.is(x, NaN)。

-0 在浮点数里有独立的符号位,和 +0 是两个不同的值,但标准规定它们比较时相等。大多数时候这没问题,可有些计算会暴露差别:1 / +0 是 Infinity,1 / -0 是 -Infinity。比如做一个带方向的速度动画,速度从负数减到 0 时得到的是 -0,符号代表方向,这时就要用 Object.is(v, -0) 才能区分出来。

在项目里哪儿会用到 Object.is

日常写业务判断,=== 足够用了。Object.is 更多出现在框架内部,用来回答「这个值到底变了没有」。

React 用它判断状态有没有变化
React 的 useState 在 setState 时,会用 Object.is 比较新旧值,相同就跳过这次更新;useEffect、useMemo 的依赖数组也是逐项用 Object.is 比较。所以状态是 NaN 时,再 setState(NaN) 不会触发重复渲染,用 === 的话会认为变了。反过来,直接修改对象再 setState 同一个引用,React 会认为没变,页面不更新,这就是为什么要写 setUser({ ...user, name }) 生成新对象。
第三种规则:SameValueZero
Array.prototype.includes、Map 的键、Set 的成员用的是 SameValueZero,它介于两者之间:NaN 等于自己,但 +0 和 -0 也相等。所以 [NaN].includes(NaN) 是 true,而老的 [NaN].indexOf(NaN) 返回 -1,因为 indexOf 用的是 ===。
回答前,多想一步

容易答错的地方

以为 Object.is 能比较对象内容
Object.is 不是深比较。Object.is({ a: 1 }, { a: 1 }) 是 false,和 === 一样。要比较内容得自己递归比较字段,或者用 lodash 的 isEqual。
以为 Object.is 能完全替代 ===
它能替代,但没必要。业务代码里几乎不会遇到 -0,判断 NaN 也有更直白的 Number.isNaN。满篇 Object.is 反而让读代码的人以为这里有什么特殊的边界要处理。
把 isNaN 和 Number.isNaN 混着用
全局的 isNaN 会先把参数转成数字,所以 isNaN('abc') 是 true。Number.isNaN 不做转换,只有真的是 NaN 才返回 true,结果和 Object.is(x, NaN) 一致。
试着用自己的话回答

面试官还会怎么问?

== 在这两个值上表现如何?

和 === 一样:NaN == NaN 是 false,+0 == -0 是 true。== 只是多了类型转换,对这两个特殊值没有额外处理。

不用 Object.is,怎么手写一个等价的函数?

先用 === 比较。相等时再排除 +0 和 -0 的情况,可以用 1 / x === 1 / y 区分正负零;不相等时再看两个值是不是都是 NaN,利用 x !== x 只对 NaN 成立这一点。这也是早期 polyfill 的写法。

为什么 React 选 Object.is 而不是 ===?

因为 React 要的是「值是否真的一样」。NaN 状态用 === 永远判为变化,会导致每次都重新渲染;+0 和 -0 在某些计算里结果不同,也应该算作变化。Object.is 在这两点上都更贴近「同一个值」的直觉。

从一道题,走向一组知识

把知识连起来

对象与原型

Symbol.hasInstance 是怎么改写 instanceof 结果的?

同样是「判断两个东西是什么关系」,instanceof 判断的是原型链关系,而且可以用 Symbol.hasInstance 改写。

对象与原型

isPrototypeOf 和 instanceof 都查原型链,区别在哪?

isPrototypeOf 沿原型链逐个比较对象,每一步用的就是引用相等。

参考资料

  • JavaScript:对象与原型参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 先看两者不一样的地方
  3. 为什么 === 会有这两个怪癖
  4. 在项目里哪儿会用到 Object.is
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑