javascript如何实现数组去重_有哪些高效方法?

10次阅读

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

javascript如何实现数组去重_有哪些高效方法?

用 Set 快速去重,适合基础场景

最直接的方法是用 Set 构造器配合扩展运算符,它自动剔除重复原始值(stringnumberBooleanNULLundefined),时间复杂度接近 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免费学习笔记(深入)”;

  • findIndexsome 多返回索引,但这里只用布尔判断,实际可改用 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 返回非字符串/数字/symbolMap 仍能存,但作为 key 会被转为 [Object Object],失去意义

性能敏感场景下,避免高开销操作

数组去重不是越“通用”越好。真实项目中,多数只需单字段唯一,强行套用深比较或 JSON 序列化反而拖慢 3–10 倍:

  • 纯数字/字符串数组:无条件用 [...new Set(arr)]
  • 对象数组按单字段去重:优先用 Map 缓存该字段值,比每次调用 find 快一个数量级
  • 需要保留首次出现项:所有方法默认满足;若要保留最后出现项,把 filter 改成 reduceRight 或反转数组再处理
  • 千万级数据?别在前端做——交给后端DISTINCT 或聚合逻辑

真正容易被忽略的是:去重前先确认是否真的需要——有时只是渲染层重复,用 key 属性控制 react/vue 列表就够了,根本不用动数据。

text=ZqhQzanResources