news 2026/2/9 17:23:24

JavaScript 常用数组去重方法及性能对比(附:扩展运算符...总结)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JavaScript 常用数组去重方法及性能对比(附:扩展运算符...总结)

JavaScript 数组去重有多种方法,性能差异显著。

以下是常用方法及其性能对比:


1. ES6 Set(推荐)

javascript

// 最快,代码最简洁 function uniqueSet(arr) { return [...new Set(arr)]; // 或 Array.from(new Set(arr)) }

2. Filter + indexOf

javascript

function uniqueFilter(arr) { return arr.filter((item, index) => arr.indexOf(item) === index); }

3. Reduce

javascript

function uniqueReduce(arr) { return arr.reduce((acc, cur) => { if (!acc.includes(cur)) { acc.push(cur); } return acc; }, []); }

4. 双层循环

javascript

function uniqueDoubleLoop(arr) { const result = []; for (let i = 0; i < arr.length; i++) { let isDuplicate = false; for (let j = 0; j < result.length; j++) { if (arr[i] === result[j]) { isDuplicate = true; break; } } if (!isDuplicate) result.push(arr[i]); } return result; }

5. Object键值(仅字符串)

javascript

function uniqueObject(arr) { const obj = {}; const result = []; for (let i = 0; i < arr.length; i++) { if (!obj[arr[i]]) { obj[arr[i]] = true; result.push(arr[i]); } } return result; }

性能对比测试

javascript

// 生成测试数据 const testArray = []; for (let i = 0; i < 10000; i++) { testArray.push(Math.floor(Math.random() * 1000)); } // 性能测试函数 function testPerformance(fn, arr, name) { const start = performance.now(); fn([...arr]); // 避免修改原数组 const end = performance.now(); console.log(`${name}: ${(end - start).toFixed(2)}ms`); } // 测试 console.log('10000个元素的数组去重性能对比:'); testPerformance(uniqueSet, testArray, 'Set'); testPerformance(uniqueFilter, testArray, 'Filter'); testPerformance(uniqueReduce, testArray, 'Reduce'); testPerformance(uniqueDoubleLoop, testArray, '双层循环'); testPerformance(uniqueObject, testArray, 'Object键值');

性能排名(从快到慢)

  1. Set- O(n) - 最快,代码最简洁

  2. Object键值- O(n) - 较快,但仅适用于字符串或可转字符串的值

  3. Filter + indexOf- O(n²) - 中等,代码简洁但性能随数据量下降

  4. Reduce- O(n²) - 中等偏慢

  5. 双层循环- O(n²) - 最慢


特殊场景考虑

处理复杂对象

javascript

// 对象数组去重(基于某个属性) function uniqueByKey(arr, key) { const map = new Map(); return arr.filter(item => { if (!map.has(item[key])) { map.set(item[key], true); return true; } return false; }); } // 使用JSON.stringify(性能较差) function uniqueObjects(arr) { const set = new Set(); return arr.filter(obj => { const str = JSON.stringify(obj); if (set.has(str)) return false; set.add(str); return true; }); }

保持顺序

大多数方法(Set、Filter、Reduce)都能保持原始顺序,但Object键值不保证顺序。


总结建议

方法推荐度适用场景
Set⭐⭐⭐⭐⭐绝大多数场景,ES6环境
Object键值⭐⭐⭐简单值且不关心类型转换
Filter⭐⭐小数组,简洁代码优先
Reduce⭐⭐需要复杂处理逻辑
双层循环学习算法时,实际开发不推荐

最佳实践:

  • 现代项目直接使用[...new Set(arr)]

  • 需要考虑兼容性时,使用polyfill或lodash的_.uniq()

  • 大型数组优先考虑时间复杂度O(n)的方法


扩展运算符(Spread Operator)...总结

类别语法描述示例
基本概念...iterable将可迭代对象展开为独立元素...array,...string
数组操作
复制数组const newArr = [...arr]浅拷贝数组const arr1 = [1,2,3]; const arr2 = [...arr1]
合并数组[...arr1, ...arr2]合并多个数组[1,2, ...arr, 4,5]
数组去重[...new Set(arr)]配合Set快速去重[...new Set([1,2,2,3])] // [1,2,3]
插入元素[first, ...rest]结合解构分离首元素const [first, ...others] = [1,2,3,4]
对象操作
复制对象const newObj = {...obj}浅拷贝对象属性const obj1 = {a:1}; const obj2 = {...obj1}
合并对象{...obj1, ...obj2}合并对象,后者覆盖前者{...defaults, ...options}
添加属性{...obj, newProp: value}添加新属性{...user, age: 25}
覆盖属性{...obj, prop: newValue}修改已有属性值{...user, name: 'Bob'}
函数应用
函数参数func(...args)将数组展开为函数参数Math.max(...[1,2,3])
剩余参数function(...args){}收集剩余参数为数组function sum(...nums){...}
字符串操作
字符串转数组[...str]正确处理Unicode字符[...'hello'] // ['h','e','l','l','o']
表情符号处理[...'👨‍👩‍👧']正确处理组合emoji[...'👍🏽'] // ['👍🏽']
可迭代对象
NodeList转数组[...document.querySelectorAll('div')]类数组转真正数组const divs = [...document.querySelectorAll('div')]
Arguments转数组[...arguments]函数arguments转数组function f(){ return [...arguments]; }
Map/Set转数组[...map],[...set]Map/Set转为数组[...new Set([1,2,2])] // [1,2]
组合使用
数组+解构[first, ...rest] = arr提取首元素和剩余数组const [head, ...tail] = [1,2,3,4]
对象+解构{a, ...rest} = obj提取指定属性和剩余属性const {id, ...data} = obj
嵌套展开[...arr1, mid, ...arr2]在任意位置展开数组[0, ...middle, 9]
注意事项
浅拷贝{...obj},[...arr]只拷贝一层,嵌套对象引用共享{...obj}不会深拷贝嵌套对象
不可迭代错误...123数字等不可迭代对象会报错...123 // TypeError
性能考虑大数组展开大数组展开可能影响性能避免在循环中频繁展开大数组
特殊技巧
条件展开{...obj, ...(cond && {prop: val})}条件添加属性{...obj, ...(show && {visible: true})}
移除属性{propToRemove, ...rest} = obj结合解构移除属性const {password, ...safeUser} = user
默认值+覆盖{...defaults, ...overrides}设置默认值并允许覆盖const config = {...defaultConfig, ...userConfig}

关键特点总结

  1. 浅拷贝:只复制一层,嵌套对象是引用

  2. 可迭代性:只能用于可迭代对象(数组、字符串、Set、Map等)

  3. 不可变操作:创建新对象/数组,不修改原数据

  4. 顺序重要:在对象合并中,后面的属性覆盖前面的

  5. ES6+特性:需要Babel转译以支持旧浏览器


实用示例

javascript

// 1. 快速数组合并去重 const uniqueMerge = [...new Set([...arr1, ...arr2])]; // 2. 带默认值的对象配置 const createConfig = (userConfig) => ({ port: 3000, host: 'localhost', ...userConfig }); // 3. 安全的删除属性 const removePassword = ({password, ...user}) => user; // 4. 数组插入元素 const insertAt = (arr, index, ...items) => [ ...arr.slice(0, index), ...items, ...arr.slice(index) ];

扩展运算符是现代JavaScript开发中最常用、最简洁的特性之一,极大简化了数组和对象的操作

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/5 23:15:52

TypedArray 详解

TypedArray 详解一、什么是 TypedArrayTypedArray 是 JavaScript 中处理二进制数据的对象&#xff0c;它提供了类似数组的视图来访问原始二进制缓冲区中的数据。核心特点&#xff1a;类型化&#xff1a;每个元素都有固定的数据类型&#xff08;如 Int8、Uint32、Float64 等&…

作者头像 李华
网站建设 2026/2/9 11:37:39

JavaScript 中常用排序方法的性能对比和分析

一、原生数组排序方法 1. Array.prototype.sort() javascript // 默认排序&#xff08;按字符串Unicode码点&#xff09; arr.sort()// 自定义比较函数 arr.sort((a, b) > a - b) // 数字升序 时间复杂度&#xff1a; V8引擎&#xff1a;使用Timsort&#xff08;归并插入…

作者头像 李华
网站建设 2026/2/7 14:00:46

实力见证 | 尚医云·小济医生入选2025广州市“隐形冠军”企业名单

10月28日&#xff0c;以“冠军力量澎湃动能”为主题的2025广州市“隐形冠军”企业新质发展招商投资大会隆重召开。在这场汇聚产业精英的盛会上&#xff0c;尚医云小济医生凭借在人工智能超声筛查领域的源头创新与落地成果&#xff0c;成功入选2025广州市“隐形冠军”企业。图源…

作者头像 李华
网站建设 2026/2/8 12:24:24

Cordova与OpenHarmony施肥记录管理

欢迎大家加入开源鸿蒙跨平台开发者社区&#xff0c;一起共建开源鸿蒙跨平台生态。 施肥管理系统概述 施肥记录管理系统用于记录和追踪植物的施肥历史。在Cordova框架与OpenHarmony系统的结合下&#xff0c;我们需要实现一个完整的施肥管理系统&#xff0c;包括施肥记录的创建、…

作者头像 李华
网站建设 2026/1/29 11:27:43

娱乐or办公?何必二选一!移远云平板解决方案, 解锁智能终端新体验

在数字化生活与办公深度融合的今天&#xff0c;人们对于智能终端的需求日益多元——既希望拥有平板的便携与娱乐性&#xff0c;又需要电脑的高效生产力&#xff0c;同时追求性能、续航与体验的全面均衡。针对这一核心需求&#xff0c;移远通信重磅推出全新云平板解决方案。方案…

作者头像 李华