set 对象数组去重失效是因为其基于内存引用比较,而非内容相等;两个结构相同的对象因地址不同被视为不同元素,故 new set([{id:1}, {id:1}]).size 返回 2。

JavaScript 中 Set 本身无法直接对包含对象的数组去重,因为对象是引用类型,即使两个对象内容完全相同,Set 也会把它们视为不同元素。
为什么 Set 对象数组去重失效?
Set 判断重复靠的是「严格相等(===)」,而对象比较只看内存地址。例如:
const arr = [{id: 1}, {id: 1}];
console.log(new Set(arr).size); // 输出 2,不是 1
两个 {id: 1} 是不同对象,地址不同,Set 不认为它们重复。
按某个字段(如 id)去重:用 Map 或 reduce
最常用、清晰且高效的方式是借助 Map 或 reduce 提取唯一键(比如 id),再过滤:
- 用
Map保留首个出现的对象(推荐):
const arr = [{id: 1, name: 'a'}, {id: 2, name: 'b'}, {id: 1, name: 'c'}];
const unique = Array.from(
new Map(arr.map(item => [item.id, item])).values()
);
// → [{id: 1, name: 'a'}, {id: 2, name: 'b'}]
- 用
reduce手动累积(兼容性好):
const unique = arr.reduce((acc, cur) => {
if (!acc.some(item => item.id === cur.id)) {
acc.push(cur);
}
return acc;
}, []);
按对象内容全量去重:序列化 + Set
如果没固定 key,需判断整个对象是否“内容相同”,可转为 JSON 字符串再去重(注意限制):
- 仅适用于纯数据对象(无函数、undefined、Date、RegExp、循环引用)
- 属性顺序必须一致,否则 JSON.stringify 结果不同(可用
JSON.stringify(sortKeys(obj))预处理)
const arr = [{a: 1, b: 2}, {b: 2, a: 1}, {a: 1, b: 3}];
const seen = new Set();
const unique = arr.filter(obj => {
const str = JSON.stringify(obj);
if (seen.has(str)) return false;
seen.add(str);
return true;
});
更健壮的深比较去重(可选)
需要真正深比较时,不建议手写,可用 Lodash 的 uniqWith + isEqual:
import { uniqWith, isEqual } from 'lodash';
const unique = uniqWith(arr, isEqual);
或自己封装一个轻量版(适合简单嵌套):
const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b); const unique = arr.filter((cur, i) => arr.findIndex(item => deepEqual(item, cur)) === i );
实际选哪种方式,取决于你的对象结构和去重依据——有唯一标识字段就用 Map;纯内容比对且结构简单,用 JSON;复杂场景建议用成熟工具库。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











