js 数组去重就是把数组里面重复出现的元素剔除,只保留一份,是前端开发非常高频的基础操作,常用方案包含 Set 结构去重 filter 加 indexOf 双重循环遍历 reduce 利用对象键名去重这几类,不同方案在兼容性 性能 数据类型支持上差别很大,简单基础类型优先推荐 Set 写法,对象类型数组不能直接用 Set,需要自定义判断规则。需要做 js 数组去重的根本原因,接口返回数据 用户录入数据 计算生成的数据经常会出现重复项,如果不去重就直接渲染页面 统计计算,会造成重复渲染 统计数值错误,而且不同数据类型判断相等的规则不一样,比如 NaN 引用类型对象 空字符串,普通全等判断会有坑,所以要根据业务数据类型选择对应的 js 数组去重方法。
主流方案对照表
| 方法名称 | 核心原理 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| Set 去重 | 利用 Set 自动不存储重复值 | 代码最短 ES6 原生 | 无法处理对象数组 低版本 IE 不支持 | 数字 字符串 布尔 NaN 基础类型 |
| filter 加 indexOf | 只保留第一次出现的元素 | 兼容性较好 | NaN 无法识别 大数据性能一般 | 老项目兼容环境 基础类型 |
| 双重 for 循环 | 逐个对比元素 标记重复项 | 兼容所有旧浏览器 | 时间复杂度高 大数据很慢 | 老旧浏览器兼容项目 |
| reduce 去重 | 累加器记录已经出现元素 | 灵活可扩展 | 写法理解门槛稍高 | 需要自定义判断逻辑 |
| 对象键名去重 | 把元素转成对象 key | 大数据性能高 | 类型会隐式转换 容易误判 | 纯字符串数字大数据数组 |
各类方法详细说明
Set 去重
ES6 新增 Set 集合,Set 本身特性就是成员唯一,不会存放重复值,把原数组传入 Set 构造函数,再用 Array.from 或者扩展运算符转回数组,就完成 js 数组去重。这个方案最大优势是可以正确识别 NaN,因为 Set 内部判断相等的规则和全等不一样,能识别 NaN 等于 NaN,但是对象是引用比较,两个内容一模一样的对象,Set 依然判定为不重复,这点一定要注意。
filter 加 indexOf
遍历数组,用 indexOf 查找当前元素在数组里面第一次出现的下标,如果当前下标等于第一次出现下标,就保留这个元素。这个方案兼容 ES5 环境,但是 indexOf 内部使用全等判断,NaN 使用 indexOf 永远找不到,所以这种 js 数组去重方法遇到 NaN 会失效。
双重循环遍历
外层循环取出每一个元素,内层循环对比后面所有元素,如果发现相等就删除重复项。这个方案兼容性最强,很早版本浏览器都可以运行,但是循环嵌套,数组长度很大的时候运算耗时明显上升,数组上万条数据的时候不推荐使用。
reduce 去重
使用 reduce 维护一个累计结果数组,每次遍历原数组元素,判断累计数组里面是否已经存在这个元素,如果不存在就追加进去。这个 js 数组去重方法优势是可以自定义判断函数,基础类型和对象数组都可以改造实现,灵活度高。
对象键名去重
创建空对象,遍历数组,把元素转为字符串当作对象的键,如果键不存在就存入结果数组,同时给对象标记这个键。这个方法大数据量性能很好,但是存在隐式类型转换,比如数字 1 和字符串 "1" 会被当成同一个键,业务里面要特别小心这个坑。
对象数组去重补充说明
普通 js 数组去重方法不能直接处理对象数组,因为对象比较是引用地址对比,哪怕两个对象里面所有属性值都相同,引用地址不一样也不会判定重复。对象数组去重一般是指定唯一标识字段,比如 id,遍历的时候判断结果数组里面是否已经存在相同 id 的对象,存在就跳过,不存在就 push 进新数组。
选型步骤
1 先确认数组里面的数据类型,是基础类型还是对象类型
2 确认项目浏览器兼容要求,是否需要支持老 IE
3 确认数组数据量大小,小数据优先代码简洁,大数据优先高性能方案
4 如果存在 NaN,避开 indexOf 方案,优先选择 Set 或者自定义 reduce 方案
5 如果是对象数组,放弃 Set indexOf 这类基础方案,改成根据唯一字段自定义去重逻辑
【常见问题】
问题 1 js 数组去重的时候为什么 Set 不能去除相同内容对象
回答 1 js 数组去重使用 Set 的时候,对象是引用类型,Set 对比的是内存引用地址,两个属性完全一样的对象内存地址不同,所以 Set 不会判定重复,对象数组需要单独写 js 数组去重逻辑。
问题 2 js 数组去重哪种方法性能最好
回答 1 小数据量差别不大,超大数据量优先对象键名去重,其次是 Set,双重循环的 js 数组去重方法性能最差,不适合大数据场景。
问题 3 js 数组去重为什么 indexOf 方案无法去除 NaN
回答 1 indexOf 底层使用全等运算符判断,NaN 和任何值都不相等,包括自身,所以 indexOf 查找 NaN 永远返回负一,这种 js 数组去重方法遇到 NaN 就会失效。
问题 4 js 数组去重之后原数组会改变吗
回答 1 绝大多数 js 数组去重写法都是生成新数组,原数组保持不变,如果需要直接修改原数组,需要额外写 splice 删除重复元素的写法。
【免责申明】
本文内容仅用于前端技术学习参考,不同 ES 版本浏览器支持情况存在差异,实际业务请结合项目兼容要求测试,不构成代码方案强制选型建议。


