javascript去重含nan数组的关键是用object.is或number.isnan替代===,因nan!==nan;推荐object.is+filter或map分治法,避免set失效。

JavaScript 中去重包含 NaN 的数组,难点在于 NaN !== NaN,所以常规的 Set、filter + indexOf 或 includes 都无法正确识别重复的 NaN。解决的关键是:**用 Number.isNaN() 单独处理 NaN,再对其他值用标准去重逻辑**。
用 Map + Number.isNaN 区分处理
这是最清晰可控的方式:遍历数组,对每个元素判断是否为 NaN;是则单独记录一次,否则按值存入 Map(利用对象键的唯一性)。最后合并结果。
示例代码:
function uniqueWithNaN(arr) {
const seen = new Map();
const nanAdded = false;
const result = [];
for (const item of arr) {
if (Number.isNaN(item)) {
if (!nanAdded) {
result.push(NaN);
nanAdded = true;
}
} else {
if (!seen.has(item)) {
seen.set(item, true);
result.push(item);
}
}
}
return result;
}
// 测试
console.log(uniqueWithNaN([1, NaN, 2, NaN, 1, -0, 0]));
// → [1, NaN, 2, -0, 0](注意:-0 和 0 在 Map 键中是不同的)
用 Array.from + Set + 自定义包装(兼容 -0 和 NaN)
如果希望更简洁且统一处理(包括区分 -0 和 0),可将每个元素转为可比较的字符串标识。但要注意:NaN、-0、0、Infinity 等需特殊序列化。
推荐使用 Object.is() 语义做去重——它能正确识别 NaN === NaN 和 -0 !== 0:
- 用
filter配合findIndex+Object.is - 或手写 reduce,用
Object.is判断是否已存在
示例(filter 版):
function uniqueByObjectIs(arr) {
return arr.filter((item, index) =>
arr.findIndex(el => Object.is(el, item)) === index
);
}
console.log(uniqueByObjectIs([1, NaN, NaN, -0, 0, 1]));
// → [1, NaN, -0, 0]
避开陷阱:为什么 new Set([...]) 不行?
new Set([NaN, NaN]) 看似会去重,但实际上 Set 内部使用 SameValueZero 算法(类似 ===),而 NaN === NaN 是 false —— 所以 Set 会把多个 NaN 当作不同值保留:
console.log([...new Set([NaN, NaN, 1, 1])]); // → [NaN, NaN, 1] ❌(两个 NaN 都在)
这就是必须显式用 Object.is 或 Number.isNaN 的根本原因。
小结:选哪种方法?
- 追求语义准确、兼容
-0/0/NaN→ 用Object.is+filter/findIndex - 性能敏感且数组很大 → 用
Map+ 分支判断(避免反复调用findIndex) - 项目已用 Lodash → 直接
_.uniqWith(arr, Object.is)
核心就一条:别依赖 === 或默认 Set 行为来处理 NaN,改用 Object.is 或显式 Number.isNaN 判断。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











