Set能正确去重NaN而indexOf失效:Set用SameValueZero算法使NaN===NaN为真,保留一个NaN;indexOf用严格相等导致NaN===NaN恒假,总返回-1,无法识别NaN重复。

JS 中 NaN 在数组去重时的表现差异,核心在于底层比较逻辑不同:Set 能正确去重 NaN,而 indexOf 会完全失效。
Set 能把多个 NaN 当作同一个值
Set 内部使用 SameValueZero 算法判断重复,该算法明确规定:NaN 与 NaN 相等。所以无论数组里有多少个 NaN,Set 都只保留一个。
- 例如:
new Set([NaN, NaN, 1, NaN])→Set { NaN, 1 } - 顺序不变,插入位置按首次出现的 NaN 保留
- 这个行为是 ECMAScript 规范强制要求的,所有现代浏览器和 Node.js 都一致
indexOf 对 NaN 总是返回 -1
indexOf 使用严格相等(===)做匹配,而 NaN === NaN 恒为 false。因此它永远找不到 NaN 的“第一次出现位置”。
- 例如:
[NaN, NaN].indexOf(NaN)→-1(不是 0) - 用它配合 filter 去重时,所有 NaN 都会被当成“新元素”,结果保留全部 NaN
- 手动循环 + indexOf 判断是否已存在,也会漏掉 NaN 的重复识别
includes 可以替代 indexOf 处理 NaN
includes() 同样基于 SameValueZero,所以它对 NaN 的判断和 Set 一致。
-
[NaN, NaN].includes(NaN)→true - 用
filter(item => !result.includes(item))或forEach + includes就能正确过滤 NaN - 但注意:includes 在 IE 中不支持,如需兼容旧环境,不能直接替换 indexOf
别被 JSON.stringify 搞混了
Set 里明明存了 NaN,但 JSON.stringify(Array.from(set)) 会把 NaN 变成 null。这不是去重失败,而是 JSON 格式本身不支持 NaN —— 调试时直接 console.log(set) 才能看到真实内容。











