Set对NaN去重是符合规范的:它使用SameValueZero算法,将多个NaN视为同一值,故只保留一个;该算法规定NaN与NaN相等,+0与-0相等,其余等价于===。

JavaScript 中 Set 对 NaN 的去重是特殊且符合预期的:它把多个 NaN 视为**同一个值**,只保留一个。这和 NaN === NaN 为 false 的表层直觉不同,但背后有明确规范支持。
Set 内部使用 SameValueZero 算法判断重复
Set 并不依赖 ===(严格相等)来判断是否重复,而是使用 ECMAScript 规范定义的 SameValueZero 算法。该算法的关键规则包括:
-
NaN与NaN被认为相等(这是唯一打破===行为的例外) -
+0和-0被认为相等(+0 === -0本身也为true) - 其余情况等价于
===
实际表现:NaN 自动去重
你可以直接验证:
const set = new Set([NaN, NaN, 1, '1', 1]);
console.log(set); // Set { NaN, 1, '1' }
console.log(set.size); // 3
即使连续添加多个 NaN,Set 也只存一个 —— 这正是 SameValueZero 在起作用。
立即学习“Java免费学习笔记(深入)”;
对比 Map 的键去重行为
Map 的键比较也用 SameValueZero,所以对 NaN 同样有效:
const map = new Map(); map.set(NaN, 'first'); map.set(NaN, 'second'); console.log(map.size); // 1 console.log(map.get(NaN)); // 'second'(后设覆盖)
这说明 NaN 作为键能被正确识别为同一项,不是靠 ===,而是靠 SameValueZero。
注意:JSON.stringify 无法体现 NaN 存在
虽然 Set 正确保存了 NaN,但序列化时会有陷阱:
const set = new Set([NaN, 1]); console.log(JSON.stringify(Array.from(set))); // "[null,1]"
JSON.stringify 将 NaN、undefined、函数等转为 null,这不是 Set 的问题,而是 JSON 格式限制。调试时建议用 console.log(set) 或检查 Array.from(set) 的原始值。


















