能,object.is 可区分 +0 和 -0;而 === 将二者视为相等。浮点运算如 0 / -infinity、math.sqrt(-0)、负数位运算等易产生 -0,需用 object.is(x, -0) 显式检测,避免经 number() 或 json 序列化后符号丢失。

Object.is 能否区分 +0 和 -0?
能,这是 Object.is 相比 === 的关键优势。JavaScript 中 +0 === -0 返回 true,但 Object.is(+0, -0) 返回 false。浮点数计算中,位运算(如 >>>、^、~)或某些除法/取模操作可能意外生成 -0,而它在数值比较中常被忽略,导致逻辑偏差。
哪些浮点运算容易产出 -0?
不是所有浮点运算都会产生 -0,但以下场景高发:
-
-0.1 * 0或0 / -Infinity→ 直接得-0 - 对负数执行无符号右移:
-1 >>> 31得1,但-0 >>> 0会先转为0再无符号处理,而1 / -Infinity更稳妥地得-0 - 使用
Math.pow(-0, 1)、Math.sqrt(-0)(后者返回-0) - 二进制位操作作用于包含
-0的数组索引或 TypedArray 元素时,可能隐式传播-0
用 Object.is 检测 -0 的典型写法与陷阱
检测必须显式传入待测值和 -0 字面量,不能依赖中间变量误转:
// ✅ 正确:直接比对
if (Object.is(x, -0)) { /* x 是负零 */ }
<p>// ❌ 错误:x === -0 不成立;-0 被当成 +0
if (x === -0) { /<em> 永远不进这里 </em>/ }</p><p>// ❌ 危险:Number(x) 或 +x 会把 -0 转成 +0
if (Object.is(Number(x), -0)) { /<em> 失效 </em>/ }
</p>
注意:若 x 来自 Float32Array 或 Float64Array,读取后仍保留符号位,Object.is 可靠;但经 JSON.parse(JSON.stringify(...)) 后 -0 会丢失符号,变成 +0。
结合位运算结果做 -0 防御的实操建议
当函数接收由位运算推导出的“安全索引”或“标志位”,需警惕 -0 作为边界值混入:
- 若你用
value & 0清除小数部分,-0.5 & 0得-0,而非预期的0 - 对数组长度取模:
index % arr.length若index是-0,结果仍是-0,而arr[-0]等价于arr[0],但语义已错 - 推荐统一归一化:遇到
Object.is(x, -0)就赋值为0,避免后续===或==判断失准
最易被忽略的是:-0 在 Object.keys()、for...in、JSON.stringify() 中完全不可见,但它真实参与算术和位运算——检测必须在数据流早期完成,不能拖到序列化之后。










