首页 > 严选问答 >

问 js 数组去重方法 前端常用方案深度解析

2026-11-08 17:00:10
最佳答案

答

js 数组去重是 JavaScript 开发高频基础操作,核心目标就是把数组里面重复的元素剔除,只保留一份,主流方案包含 Set 去重 indexOf 去重 filter 结合 includes reduce 去重 双重 for 循环去重,不同方法在兼容性 性能 数据类型识别上有差别,需要重点区分基本类型和对象类型,Set 方法写法最简洁,是现代 ES6 之后首选方案,但是它使用严格相等判断,也就是 SameValueZero 规则,NaN 可以识别重复,这点和 indexOf 不一样,indexOf 无法识别 NaN,对象类型不管哪种基础去重方法,默认都是按引用地址判断,两个内容一模一样但是不同引用的对象,会判定成不重复,这个是面试和开发最容易踩坑的点,选择方法的时候,要根据浏览器兼容要求,数组元素类型,是否保留原数组顺序这几个条件来挑选,老项目如果需要兼容非常老旧浏览器,就不能使用 Set,要选择传统循环方案。

常用方法对照表

方法名称核心原理ES 版本是否识别 NaN优点缺点
Set 展开运算符利用 Set 集合元素唯一特性ES6可以识别代码最短,性能优秀老 IE 不支持,对象按引用判断
filter + indexOf判断当前元素第一次出现索引是否等于当前下标ES5不能识别 NaNES5 兼容好数组很大的时候性能一般,NaN 失效
filter + includesincludes 内部 SameValueZero 判断ES7可以识别写法简洁,支持 NaN低版本浏览器不支持 includes
reduce 累加器遍历数组,判断累加数组是否已经存在元素ES5默认不能识别 NaN灵活,可自定义判断逻辑代码相对长
双重 for 循环两层循环对比元素,重复就 splice 删除ES3不能识别 NaN兼容性最强时间复杂度高,大数据数组很慢

方案一 Set 展开运算符 现代首选

代码核心写法

const arr = [1,2,2,3,NaN,NaN]

const newArr = [...new Set (arr)]

原理:new Set 会自动剔除重复值,之后展开运算符把 Set 转回数组,保持原始顺序,支持 NaN 去重,适合数字 字符串 布尔 这些基本类型数组。

方案二 filter + indexOf 兼容 ES5 写法

代码核心写法

const newArr = arr.filter ((item,index)=> arr.indexOf (item) === index)

原理:遍历每一项,如果该项第一次出现的索引,等于当前遍历下标,代表是第一次出现,保留,如果索引不一样,说明前面已经出现过,属于重复项过滤掉,缺点就是 indexOf 对 NaN 永远返回负一,所以 NaN 无法去重。

方案三 filter + includes

代码核心写法

const newArr = arr.filter ((item,index)=> !newArr.includes (item))

原理:维护一个结果数组,每遍历一项,用 includes 判断结果数组里面是否已经存在该元素,不存在就 push 进去,includes 可以正确识别 NaN。

方案四 reduce 实现去重

代码核心写法

const newArr = arr.reduce ((prev,current)=>{

if (!prev.includes (current)) prev.push (current)

return prev

},[])

原理:reduce 初始化空数组作为累加器,遍历原数组,判断累加器里面有没有当前元素,没有就追加,这个方案优势是可以自定义判断规则,后续改造方便。

方案五 双重 for 循环 极致兼容

原理:外层循环取出元素,内层循环对比后面所有元素,如果相等,就用 splice 删除重复项,优点是可以运行在非常古老的浏览器,缺点双重循环时间复杂度是 O (n 平方),数组数据量大的时候性能很差,并且同样无法识别 NaN。

对象数组去重补充重点

如果数组里面是对象,比如用户列表,不能直接用 Set 去重,因为对象比较是引用比较,需要自定义去重规则,一般根据对象里面唯一字段,比如 id 来去重,使用 reduce 或者 Map,以 id 作为键,实现根据属性值去重,这个属于进阶场景。

选型操作步骤

第一步确认数组元素类型,是基本类型还是对象数组,第二步确认项目浏览器兼容要求,是否需要支持老旧浏览器,第三步确认是否需要对 NaN 进行去重,第四步根据需求挑选对应的 js 数组去重方法,第五步测试结果,确认顺序和去重结果是否符合预期,大数据量优先选择 Set 或者 Map 方案,性能更优。

综合来说现代项目优先推荐 Set 展开运算符实现 js 数组去重,写法简洁性能好,如果需要 ES5 兼容就使用 filter 加 indexOf,对象数组需要自定义字段去重,不能直接套用基本类型的去重代码。

【常见问题】

问题 1 js 数组去重 Set 方法为什么可以去除 NaN

回答 1 js 数组去重 Set 内部使用 SameValueZero 比较规则,可以正确识别 NaN 相等,传统 indexOf 方法不能识别 NaN,所以 indexOf 实现的 js 数组去重无法去掉重复 NaN。

问题 2 js 数组去重的时候两个内容一样的对象为什么没有去掉

回答 1 js 数组去重基础方法是按照引用地址判断对象,两个对象即使内容完全相同,只要是不同引用,就会判定不重复,对象数组去重需要改成根据 id 这类唯一属性自定义逻辑。

问题 3 js 数组去重双重 for 循环适合大数据数组吗

回答 1 js 数组去重双重 for 循环时间复杂度高,不适合大数据数组,大数据场景优先选择 Set 或者 Map 实现 js 数组去重,运行性能更好。

【免责申明】

本文基于 JavaScript 标准语法整理,不同 JS 引擎对方法实现细节存在微小差异,仅作为前端学习参考,生产环境需要根据目标浏览器做兼容性测试。