Set能正确去重NaN,因其使用SameValueZero算法,将NaN视为相等且0与-0也相等;而indexOf依赖===导致NaN去重失败,includes可替代;JSON序列化会丢失NaN。

JavaScript 中 NaN 在 Set 中能被正确去重,是因为 Set 内部使用的是 SameValueZero 算法(不是严格相等 ===),该算法规定 NaN === NaN 为 true —— 这是唯一能让多个 NaN 被视为“相同值”并只保留一个的关键。
为什么 Set 能正确去重 NaN
Set 判断重复不依赖 ===,而是 SameValueZero:它对 NaN 特殊处理,认为所有 NaN 相等;同时保持 0 和 -0 相等(这点和 === 一致)。
例如:
const s = new Set([NaN, NaN, 1, '1', 0, -0]);
console.log(s); // Set { NaN, 1, '1', 0 }
可以看到:NaN 只存一个,0 和 -0 也被合并为一个 0(SameValueZero 视二者相等)。
立即学习“Java免费学习笔记(深入)”;
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
对比 Array.filter + indexOf 的陷阱
如果手动用数组去重(如 arr.filter((v, i) => arr.indexOf(v) === i)),indexOf 内部用的是 ===,而 NaN === NaN 是 false,导致所有 NaN 都被保留:
const arr = [NaN, NaN, 1]; console.log(arr.filter((v, i) => arr.indexOf(v) === i)); // [NaN, NaN, 1] ← ❌ 错误去重
安全的手动去重方法(需兼容 NaN)
若不能用 Set(比如需要自定义逻辑),可用 Array.prototype.includes() 替代 indexOf,因为 includes 使用 SameValueZero:
-
[NaN].includes(NaN)返回 true - 所以可写:
arr.filter((v, i) => arr.slice(0, i).includes(v) === false) - 或更简洁:用
new Set是最推荐、最可靠的方式
注意:JSON.stringify 会丢失 NaN
如果后续要序列化 Set(如转 JSON),NaN、undefined、函数等会被自动过滤或转为 null:
JSON.stringify(new Set([NaN, 1])); // "null" ← 整个 Set 变成 null JSON.stringify([...new Set([NaN, 1])]); // "[null,1]"
因此,涉及持久化或传输时,建议提前将 NaN 显式替换为可序列化的标记值(如 "NaN" 字符串)。

















