Object.is 是唯一能稳定识别 -0 的原生方法,因其直接按 IEEE 754 位模式比较,使 Object.is(x, -0) 精准返回 true,而 === 和 isNaN() 均无法区分 -0 与 +0(前者返回 true,后者返回 false),易致方向判断、跨系统交互等场景出现隐蔽偏差。

Object.is 是唯一能稳定识别 -0 的原生方法,不用它,浮点计算中产生的 -0 会悄无声息地混进业务逻辑,尤其在方向判断、归零策略或跨系统数据交换时引发不可复现的偏差。
为什么 === 和 isNaN() 都拦不住 -0
JavaScript 中 === 认为 +0 和 -0 相等,isNaN() 对 -0 返回 false(它根本不是 NaN),所以常规校验完全失效。比如:
const result = -123 * 0; // 得到 -0 result === 0; // true → 你以为是“归零成功” isNaN(result); // false → 你以为没出错 1 / result === -Infinity; // true → 但除法行为已经暴露符号
这种“看起来正常、用起来翻车”的情况,在金融风控阈值归零、3D 坐标系朝向归零、或导出数据给 Python/Java 后端时特别危险——那些语言通常严格区分 +0 和 -0。
检测 -0 必须用 Object.is(x, -0),别手写倒数判断
有人用 1 / x === -Infinity 判断 -0,但这有三个硬伤:
-
1 / 0是Infinity,但1 / -0是-Infinity—— 看似可行,可一旦x是极小负数(如-1e-308),1 / x也会下溢成-Infinity,误报 -
1 / x在x为 0 时会触发除零警告(某些调试器或严格模式下) - 可读性差,别人维护时得反推你在防什么
正确姿势只有一行:Object.is(x, -0)。它不依赖任何运算,直接比 IEEE 754 位模式,安全、明确、无副作用。
需要同时排除 +0 和 -0?别用 !== 0
常见错误写法:x !== 0 —— 它对 -0 返回 false(因为 -0 === 0),完全无效。
真正可靠的写法是:
!Object.is(x, 0) && !Object.is(x, -0)
这明确表达了“既不是正零,也不是负零”的语义。如果业务只要求“非零数值”,这个判断比 x !== 0 更贴近真实意图;如果后续还要处理 NaN,可以追加 && !Object.is(x, NaN)。
浮点计算中哪些操作真会产出 -0
不是所有负数参与的运算都会生成 -0,只有当「零」作为结果且符号被显式继承时才发生。典型场景包括:
- 负数乘以
0:-5 * 0、Math.PI * -0 - 负数除以无穷大:
-10 / Infinity - 一元负号作用于
+0:-+0 - 某些数学函数:
Math.atan2(-0, 1)、Math.pow(-0, 1)
注意:0 - 0、0 + 0、Math.abs(-0) 这些仍返回 +0。所以不能靠“有没有负号”猜,必须实测或用 Object.is 验证。
真正难缠的不是 -0 本身,而是它在链式计算中被层层掩盖:前一步输出 -0,中间步骤用 === 判等放行,最后一步做 1 / x 才崩。所以关键不是“哪里产生”,而是“在哪一层必须拦截”——答案永远是:只要业务语义上 +0 和 -0 不等价,那个判断点就必须用 Object.is。

















