JavaScript 中,数组去重
在 JavaScript 中,数组去重有多种实现方式,以下是常见的几种方法,适用于不同场景:
1. 使用 Set(最简洁,ES6+)
Set 是 ES6 新增的数据结构,其特性是成员唯一,结合数组扩展运算符 ... 可快速去重。
优点:简洁高效,一行代码搞定。
缺点:无法处理引用类型(如对象、数组)的去重(因为引用类型地址不同)。
const arr = [1, 2, 2, 3, 3, 3, null, null, undefined, undefined, NaN, NaN];
const uniqueArr = [...new Set(arr)];
// 结果:[1, 2, 3, null, undefined, NaN]
// 注意:Set 能正确识别 NaN(认为 NaN === NaN)
2. 使用 filter + indexOf
利用 indexOf 返回元素首次出现的索引,结合 filter 保留首次出现的元素。
优点:兼容性较好(ES5+)。
缺点:
- 无法处理
NaN(因为indexOf(NaN)始终返回-1,会过滤掉所有NaN)。 - 性能一般(嵌套遍历)。
const arr = [1, 2, 2, 3, 3, null, null, NaN, NaN];
const uniqueArr = arr.filter((item, index) => {return arr.indexOf(item) === index;
});
// 结果:[1, 2, 3, null](NaN 被过滤掉了)
3. 使用 filter + includes(改进 indexOf 的 NaN 问题)
includes 能正确识别 NaN([NaN].includes(NaN) === true),可修复上一种方法的缺陷。
优点:支持 NaN 去重。
缺点:仍需嵌套遍历,性能一般。
const arr = [1, 2, 2, 3, 3, null, null, NaN, NaN];
const uniqueArr = [];
arr.filter(item => {if (!uniqueArr.includes(item)) {uniqueArr.push(item);return true;}return false;
});
// 结果:[1, 2, 3, null, NaN]
4. 使用对象键名(利用对象属性唯一)
通过对象的键名存储已出现的元素(键名自动去重),适用于简单类型。
优点:性能较好(对象查找是 O(1))。
缺点:
- 需注意数据类型转换(如
'1'和1会被视为同一个键)。 - 无法直接处理
null、undefined(可手动处理键名)。
const arr = [1, 2, 2, 3, 3, '1', null, null];
const obj = {};
const uniqueArr = [];
arr.forEach(item => {// 处理键名,避免类型混淆(如区分 1 和 '1')const key = typeof item + item; if (!obj[key]) {obj[key] = true;uniqueArr.push(item);}
});
// 结果:[1, 2, 3, '1', null](正确区分了 1 和 '1')
5. 使用 reduce 实现
reduce 可累计去重后的数组,逻辑类似 filter + includes。
优点:代码简洁,支持 NaN。
缺点:性能依赖内部判断逻辑。
const arr = [1, 2, 2, 3, 3, null, null, NaN, NaN];
const uniqueArr = arr.reduce((prev, curr) => {if (!prev.includes(curr)) {prev.push(curr);}return prev;
}, []);
// 结果:[1, 2, 3, null, NaN]
6. 针对引用类型去重(如对象数组)
如果数组包含对象/数组等引用类型,需根据具体属性判断唯一性(例如根据 id 去重)。
const arr = [{ id: 1, name: 'a' },{ id: 2, name: 'b' },{ id: 1, name: 'a' } // 重复(id 相同)
];// 根据 id 去重
const uniqueArr = [];
const ids = new Set(); // 存储已出现的 id
arr.forEach(item => {if (!ids.has(item.id)) {ids.add(item.id);uniqueArr.push(item);}
});
// 结果:[{ id: 1, name: 'a' }, { id: 2, name: 'b' }]
总结
- 简单类型去重:优先用
[...new Set(arr)](简洁高效)。 - 需要兼容旧环境:用
filter + indexOf(注意 NaN 问题)。 - 引用类型去重:根据具体属性(如
id)结合Set或对象判断。
