ES5 方式
在 ES5 中,我们可以使用 for
循环配合数组方法来实现对象数组的去重。
function uniqueArrayByProperty(array, property) {
var seen = {};
return array.filter(function(item) {
var val = item[property];
return seen.hasOwnProperty(val) ? false : (seen[val] = true);
});
}
var arr = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice' }, // 重复
{ id: 3, name: 'Charlie' }
];
var uniqueArr = uniqueArrayByProperty(arr, 'id');
console.log(uniqueArr);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
ES6 及之后的方式
随着 ES6 的引入,有了更多简洁的方式来处理数组和对象。
使用 Set
和 JSON.stringify / JSON.parse
这种方法适用于简单对象,但需要注意 JSON.stringify
会丢失原型链上的属性,而且对于包含循环引用的对象会抛出错误。
function uniqueArrayByPropertyES6(array, property) {
const seen = new Set();
return array.filter(item => {
const val = JSON.stringify(item[property]);
return seen.has(val) ? false : seen.add(val);
});
}
var uniqueArrES6 = uniqueArrayByPropertyES6(arr, 'id');
console.log(uniqueArrES6);
使用 Map
对于更复杂的对象去重,可以使用 Map
来存储已经见过的对象。
function uniqueArrayByPropertyWithMap(array, property) {
const map = new Map();
return array.filter(item => {
const val = item[property];
if (!map.has(val)) {
map.set(val, true);
return true;
}
return false;
});
}
var uniqueArrWithMap = uniqueArrayByPropertyWithMap(arr, 'id');
console.log(uniqueArrWithMap);
使用 Map
结合自定义比较逻辑
这种方法适用于对象具有多个属性的情况,可以自定义比较逻辑。
function uniqueArrayByProperties(array, properties) {
const seen = new Map();
return array.filter(item => {
const key = properties.map(prop => item[prop]).join('|');
if (!seen.has(key)) {
seen.set(key, true);
return true;
}
return false;
});
}
const arr = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice' }, // 重复
{ id: 3, name: 'Charlie' }
];
const uniqueArr = uniqueArrayByProperties(arr, ['id', 'name']);
console.log(uniqueArr);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
使用 Lodash 库
Lodash 提供了一个方便的函数 _.uniqBy
,可以轻松实现去重。
const _ = require('lodash');
const uniqueArr = _.uniqBy(arr, 'id');
console.log(uniqueArr);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
使用 WeakMap
WeakMap
可以用来存储对象引用,而不会阻止这些对象被垃圾回收。虽然 WeakMap
的键必须是对象,但它可以用来存储已经处理过的对象。
function uniqueArrayByPropertyWithWeakMap(array, property) {
const seen = new WeakMap();
return array.filter(item => {
const val = item[property];
if (!seen.has(val)) {
seen.set(val, true);
return true;
}
return false;
});
}
const uniqueArrWithWeakMap = uniqueArrayByPropertyWithWeakMap(arr, 'id');
console.log(uniqueArrWithWeakMap);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
使用 Set
和 WeakRef
(实验性)
在最新的 JavaScript 版本中,WeakRef
可以用来存储对象的弱引用,这可以用来辅助对象的去重,但请注意 WeakRef
是一个实验性功能,可能在未来的版本中有所变化。
const { WeakRef } = require('weakref'); // 假设这是一个支持 WeakRef 的环境
function uniqueArrayByPropertyWithWeakRef(array, property) {
const seen = new Set();
return array.filter(item => {
const ref = new WeakRef(item[property]);
if (!seen.has(ref)) {
seen.add(ref);
return true;
}
return false;
});
}
const uniqueArrWithWeakRef = uniqueArrayByPropertyWithWeakRef(arr, 'id');
console.log(uniqueArrWithWeakRef);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
使用 Set
结合 JSON.stringify
对于简单对象,可以使用 JSON.stringify
来生成对象的字符串表示,然后使用 Set
进行去重。
function uniqueArrayByPropertyWithSet(array, property) {
const seen = new Set();
return array.filter(item => {
const val = JSON.stringify(item[property]);
return seen.has(val) ? false : seen.add(val);
});
}
const uniqueArrWithSet = uniqueArrayByPropertyWithSet(arr, 'id');
console.log(uniqueArrWithSet);
// 输出:[ { id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' } ]
总结
以上列出了一些实现 JavaScript 对象数组去重的不同方法(项目中经常出现这样的需求数组对象去重)。选择哪种方法取决于你的具体需求和环境。对于简单的对象,使用 Set
和 JSON.stringify
可能是最简单的方式;而对于更复杂的情况,使用 Map
或者 WeakMap
可能更合适。如果使用第三方库,Lodash 的 _.uniqBy
函数提供了便捷的解决方案。对于实验性的功能,如 WeakRef
,则需要考虑兼容性和稳定性问题。