一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

如何理解 Set 内部对 NaN 与正零和负零的唯一性判定规则

时间:2026-07-21 11:14:07 编辑:袖梨 来源:一聚教程网

Set 使用 SameValueZero 算法判断重复,将 +0、-0、0 视为相等,NaN 只保留一个,不依赖 === 也不完全等同 Object.is(),导致去重行为与直觉不符。

Set 用 SameValueZero 算法判断重复,不是 ===

Set 不是靠 === 判断两个值是否重复,而是用更底层的 SameValueZero 算法。这个算法和 Object.is() 几乎一样,但有个关键区别:它把 +0-0 当作相等,而 Object.is(+0, -0) 返回 false

NaN 在 Set 中只存一个,但 !== 自身

这是最常让人困惑的点:虽然 NaN === NaNfalseObject.is(NaN, NaN)true,而 Set 选择的是“只留第一个 NaN”——它不依赖 ===,也不完全等同于 Object.is(),而是按规范硬编码了 NaN 的唯一性。

  • new Set([NaN, NaN, NaN]).size1
  • NaN === NaN 始终为 false,所以不能靠 === 模拟 Set 行为
  • 如果你手动写去重逻辑(比如用 filter() + includes()),默认不会合并 NaN

+0 和 -0 在 Set 中无法共存

哪怕你显式写出 -0,Set 也会把它和 +0 当作同一个值:

new Set([+0, -0, 0]) // → Set { 0 }

注意:-0 被打印为 0,但它在内存中仍是 -0;只是 Set 内部判定时认为三者等价。

  • 0+0-0 插入任意顺序,最终只保留一个
  • Array.from(new Set([+0, -0]))[0] === -0 可能为 true(取决于插入顺序和引擎实现)
  • 不要依赖 JSON.stringify(-0)String(-0) 做唯一性预处理,它们都输出 "0",会掩盖差异

实际去重时最容易忽略的边界

当你用 [...new Set(arr)] 去重数组,这些行为会悄悄影响结果:

  • ["0", 0, false] → 三个不同值(字符串、数字、布尔),不会被合并
  • [NaN, "NaN"] → 两个不同值(类型不同),都会保留
  • [0, -0, Object.is(0, -0)]false,但 Set 里仍只留一个
  • 对象或函数传进去,永远按引用比较,new Set([{a:1}, {a:1}]) 长度是 2

真正需要稳定去重时,别直接塞原始数组进 Set——先统一转成字符串或提取 key,否则 +0/-0NaN 的隐式合并可能破坏业务语义。

热门栏目