❤ 写在前面
如果觉得对你有帮助的话,点个小❤❤ 吧,你的支持是对我最大的鼓励~
个人独立开发wx小程序,感谢支持!
前言:为什么需要数组去重?
想象一下,你正在整理一个装满各种颜色袜子的抽屉。你会发现有很多双相同颜色的袜子,为了节省空间,你会把重复的袜子拿出来。在前端开发中,处理数据时也会遇到类似情况——数组中的重复元素会浪费资源、影响性能,甚至导致数据错误。
今天,我们就来探索前端开发中数组去重的七种方法,每种方法都有其独特的“武器特性”!
方法一:Set大法(ES6推荐)
这是目前最简洁、最高效的方法,就像一把锋利的瑞士军刀!
const arr = [1, 2, 2, 3, 4, 4, 5];
const uniqueArr = [...new Set(arr)];
console.log(uniqueArr); // [1, 2, 3, 4, 5]
原理图:
原始数组 → Set容器(自动去重) → 展开为数组 → 去重后的数组
优点: 代码简洁,性能优秀 缺点: 无法处理特殊对象去重(如:对象、NaN等特殊情况需注意)
方法二:Filter + IndexOf(经典组合)
这种方法像是侦探办案,检查每个元素是否是第一次出现:
function unique(arr) {
return arr.filter((item, index) => {
return arr.indexOf(item) === index;
});
}
const arr = ['苹果', '香蕉', '苹果', '橙子', '香蕉'];
console.log(unique(arr)); // ['苹果', '香蕉', '橙子']
流程图:
开始
↓
遍历数组每个元素
↓
检查当前元素首次出现位置是否等于当前位置
↓
是 → 保留元素
↓
否 → 过滤掉
↓
返回新数组
方法三:Reduce累积器
使用reduce像是用漏斗过滤,只保留第一次遇到的元素:
const arr = [1, 2, 2, 3, 3, 3, 4];
const uniqueArr = arr.reduce((acc, current) => {
if (!acc.includes(current)) {
acc.push(current);
}
return acc;
}, []);
console.log(uniqueArr); // [1, 2, 3, 4]
方法四:双层循环(最原始的方法)
这是最基础的实现方式,就像手动检查每双袜子:
function unique(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;
}
方法五:Object键值法
利用对象的键名不可重复的特性:
function unique(arr) {
const obj = {};
const result = [];
arr.forEach(item => {
if (!obj[item]) {
obj[item] = true;
result.push(item);
}
});
return result;
}
⚠️ 注意: 这种方法会将数字和字符串视为相同键,如 1 和 '1' 会被认为是重复的。
方法六:Map数据结构
Map比Object更适合处理复杂类型的去重:
function unique(arr) {
const map = new Map();
const result = [];
arr.forEach(item => {
if (!map.has(item)) {
map.set(item, true);
result.push(item);
}
});
return result;
}
// 可以处理对象引用去重
const obj1 = {name: '张三'};
const obj2 = {name: '张三'};
const arr = [obj1, obj2, obj1];
console.log(unique(arr).length); // 2(obj1只出现一次,obj2是不同引用)
方法七:排序相邻去重法
先排序,然后比较相邻元素:
function unique(arr) {
const sortedArr = [...arr].sort();
const result = [sortedArr[0]];
for (let i = 1; i < sortedArr.length; i++) {
if (sortedArr[i] !== sortedArr[i - 1]) {
result.push(sortedArr[i]);
}
}
return result;
}
特殊场景处理
1. 对象数组去重
// 根据对象的某个属性去重
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;
});
}
const users = [
{id: 1, name: 'Alice'},
{id: 2, name: 'Bob'},
{id: 1, name: 'Alice'}, // 重复ID
];
console.log(uniqueByKey(users, 'id')); // 前两个对象
2. 处理NaN的重复
// Set可以正确处理NaN去重
const arr = [NaN, NaN, 1, 2, 1];
console.log([...new Set(arr)]); // [NaN, 1, 2]
性能对比实验
让我们通过一个简单的性能测试来看看各种方法的效率差异:
// 生成测试数据
const testArray = [];
for (let i = 0; i < 10000; i++) {
testArray.push(Math.floor(Math.random() * 1000));
}
// 测试函数执行时间
function testPerformance(fn, arr) {
const start = performance.now();
fn(arr);
const end = performance.now();
return end - start;
}
// 测试结果通常如下(时间从短到长):
// 1. Set方法 √
// 2. Object键值法
// 3. Map方法
// 4. Filter + IndexOf
// 5. Reduce方法
// 6. 排序相邻法
// 7. 双层循环
选择合适的方法:决策流程图
开始选择去重方法
↓
需要考虑性能吗? → 是 → 使用Set方法(最快)
↓否
数组中有对象吗? → 是 → 使用Map或根据属性去重
↓否
需要兼容老浏览器吗? → 是 → 使用Filter+indexOf或Object键值法
↓否
代码简洁更重要吗? → 是 → 使用Set或Reduce
↓否
使用Filter+indexOf(平衡选择)
总结与最佳实践
- 现代项目首选:
[...new Set(arr)]- 简洁高效 - 对象数组去重:使用Map或根据特定属性去重
- 兼容性要求:Filter + IndexOf或Object键值法
- 性能敏感场景:Set方法最快,其次是Object键值法
- 代码可读性:Reduce方法语义清晰,适合函数式编程
实战小挑战
试试这个综合题目:
// 有一个混合类型的数组,如何去除所有类型的重复?
const mixedArray = [
1, '1', 1,
true, 'true', true,
null, undefined, null,
{a: 1}, {a: 1}, // 注意:这两个对象看起来一样,但引用不同
[1, 2], [1, 2]
];
// 你的去重策略是什么?
提示: 可能需要结合多种方法,或者自定义比较函数!
结语
数组去重是前端开发中的基础但重要技能。不同的场景需要不同的方法,就像工具箱里的不同工具,各有各的用途。掌握这些方法,不仅能提高代码效率,还能让你的解决方案更加优雅。
希望这篇博客能帮助你在下次遇到数组去重问题时,能够自信地选择最合适的方法!