最直接的去重方法是用 Set 构造器配合扩展运算符,如 [...new Set(arr)],适用于基础类型且性能好;对象数组需按字段去重时推荐 reduce + findIndex 或 Map 缓存优化;深度去重应避免 JSON.stringify,改用稳定 getKey 函数。

用 Set 快速去重,适合基础场景
最直接的方法是用 Set 构造器配合扩展运算符,它自动剔除重复原始值(string、number、boolean、null、undefined),时间复杂度接近 O(n),性能好且代码极简:
const arr = [1, 2, 2, 3, 'a', 'a', null, null]; const unique = [...new Set(arr)]; // [1, 2, 3, 'a', null]
注意:它不处理对象或数组等引用类型,因为 Set 判重基于 SameValueZero(即 ===),而两个字面量对象永远不相等。
对对象数组按字段去重,用 reduce + findIndex
当你要根据某个 key(如 id)去重时,reduce 配合 findIndex 是较清晰的方案,避免多次遍历:
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice2' },
{ id: 3, name: 'Charlie' }
];
const uniqueById = users.reduce((acc, cur) => {
const exists = acc.findIndex(item => item.id === cur.id) !== -1;
return exists ? acc : [...acc, cur];
}, []);
关键点:
立即学习“Java免费学习笔记(深入)”;
-
findIndex比some多返回索引,但这里只用布尔判断,实际可改用some略微提速 - 若数据量大(>5000 条),建议先用
Map缓存已见id,把内层查找降到 O(1) - 不要用
filter+indexOf,因为indexOf对对象无效(始终返回 -1)
兼容旧环境或需深度去重时,手动实现 Map 缓存
IE 不支持 Set,且某些场景需按多个字段或深层属性判重(如 {a: {b: 1}}),这时用 Map 手动建 key 更可控:
function deepUnique(arr, getKey) {
const seen = new Map();
return arr.filter(item => {
const key = getKey(item);
if (seen.has(key)) return false;
seen.set(key, true);
return true;
});
}
// 按 id + name 组合去重
const result = deepUnique(users, u => `${u.id}-${u.name}`);
常见陷阱:
-
JSON.stringify当作getKey函数看似方便,但会因属性顺序不同导致误判({a:1,b:2}≠{b:2,a:1}) - 嵌套对象含
undefined或函数时,JSON.stringify会静默丢弃,key 失真 - 若
getKey返回非字符串/数字/Symbol,Map仍能存,但作为 key 会被转为[object Object],失去意义
性能敏感场景下,避免高开销操作
数组去重不是越“通用”越好。真实项目中,多数只需单字段唯一,强行套用深比较或 JSON 序列化反而拖慢 3–10 倍:
- 纯数字/字符串数组:无条件用
[...new Set(arr)] - 对象数组按单字段去重:优先用
Map缓存该字段值,比每次调用find快一个数量级 - 需要保留首次出现项:所有方法默认满足;若要保留最后出现项,把
filter改成reduceRight或反转数组再处理 - 千万级数据?别在前端做——交给后端加
DISTINCT或聚合逻辑
真正容易被忽略的是:去重前先确认是否真的需要——有时只是渲染层重复,用 key 属性控制 React/Vue 列表就够了,根本不用动数据。











