JS对象数组去重是前端开发中非常常见的需求,由于对象属于引用类型,直接使用Set或者数组的filter、indexOf方法无法实现去重,需要结合对象的唯一标识属性来处理。常见的去重维度可以是对象的某个唯一id,也可以是多个属性组合后的唯一值。

方法一:使用reduce结合Map实现去重
reduce方法可以遍历数组并累积处理结果,配合Map存储已经出现过的唯一标识,能够高效完成去重。Map的查找时间复杂度为O(1),整体去重性能较好。
// 待去重的对象数组,按id去重
const arr = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 1, name: '张三' },
{ id: 3, name: '王五' }
];
const result = arr.reduce((map, current) => {
// 如果Map中不存在当前id,就存入Map
if (!map.has(current.id)) {
map.set(current.id, current);
}
return map;
}, new Map());
// 将Map的值转为数组
const uniqueArr = Array.from(result.values());
console.log(uniqueArr);
// 输出:[{ id: 1, name: '张三' }, { id: 2, name: '李四' }, { id: 3, name: '王五' }]
方法二:使用Set结合JSON.stringify去重
如果需要按照对象的完整内容去重,而不是某个单一属性,可以先将对象转为JSON字符串,再用Set存储字符串,最后转回对象数组。不过这种方法要求对象的属性顺序一致,否则相同内容的对象可能因为属性顺序不同被判定为不同。
const arr = [
{ id: 1, name: '张三', age: 20 },
{ id: 2, name: '李四', age: 22 },
{ id: 1, name: '张三', age: 20 },
{ age: 20, id: 1, name: '张三' } // 属性顺序不同,JSON字符串不同,无法去重
];
// 先转JSON字符串再用Set去重
const strSet = new Set(arr.map(item => JSON.stringify(item)));
// 转回对象数组
const uniqueArr = Array.from(strSet).map(item => JSON.parse(item));
console.log(uniqueArr);
方法三:使用filter结合findIndex去重
filter方法可以过滤数组元素,结合findIndex查找当前元素在数组中第一次出现的位置,如果当前索引等于第一次出现的索引,说明是首次出现,保留该元素即可。这种方法逻辑比较直观,但是findIndex每次都需要遍历查找,性能比reduce加Map的方式稍差。
const arr = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' },
{ id: 1, name: '张三' },
{ id: 3, name: '王五' }
];
const uniqueArr = arr.filter((item, index) => {
// 查找当前id第一次出现的索引
const firstIndex = arr.findIndex(el => el.id === item.id);
// 如果当前索引等于第一次出现的索引,保留该元素
return index === firstIndex;
});
console.log(uniqueArr);
不同方法的选择建议
如果去重维度是对象的某个唯一属性,优先选择reduce结合Map的方式,性能最优;如果需要按对象完整内容去重,且能保证属性顺序一致,可以使用Set结合JSON.stringify的方式;如果对性能要求不高,希望逻辑更简单直观,也可以选择filter结合findIndex的方式。
| 去重方法 | 适用场景 | 性能 |
|---|---|---|
| reduce + Map | 按单一属性去重 | 高 |
| Set + JSON.stringify | 按对象完整内容去重,属性顺序一致 | 中 |
| filter + findIndex | 简单场景,对性能要求不高 | 低 |