嵌套对象数组去重需按唯一字段(如id)或深比对实现,不可用Set/===等引用比较;推荐用filter+findIndex按唯一字段O(n)去重,无唯一键时用lodash.isEqual深比较,多字段组合可用字符串拼接或JSON.stringify归一化。

嵌套对象数组去重不能靠 === 或 Set 直接处理,因为对象比较的是引用地址,两个结构一模一样的对象仍被视为不同。关键在于明确“什么是重复”——是字段值完全一致(深比对),还是仅按某个唯一标识(如 id)判重。
按唯一字段快速去重(推荐多数业务场景)
如果每个对象都有稳定、可信赖的唯一标识(比如 id、sku、email),这是最高效、语义最清晰的方式:
- 用
Set记录已见过的字段值,配合filter一次遍历完成 - 代码简洁,时间复杂度 O(n),不依赖序列化,支持任意类型字段(数字、字符串、布尔)
- 示例:const unique = arr.filter((item, i, self) => self.findIndex(v => v.id === item.id) === i)
按完整内容深比对去重(需严格一致)
当没有天然唯一字段,且必须判断所有属性名+值是否完全相等时,需深比较。直接 JSON.stringify 简单但有局限:
- 属性顺序不同会导致字符串不同(
{a:1,b:2}≠{b:2,a:1}) - 无法处理
undefined、函数、Symbol、循环引用 - 更稳妥的做法是引入
lodash.isEqual:import { uniqWith, isEqual } from 'lodash'; const unique = uniqWith(arr, isEqual);
按多字段组合构造唯一 key
有些场景唯一性由多个字段共同决定(如 userId + actionType + timestamp),或需忽略某些字段:
- 手动拼接成稳定字符串作为判重依据,例如:`${item.userId}-${item.actionType}`
- 或用数组归一化后再
JSON.stringify:JSON.stringify([item.category, item.status]) - 避免用
item.toString()—— 所有对象默认返回[object Object],完全失效
哪些方法一定不能用?
以下方式在嵌套对象数组中基本无效:
-
[...new Set(arr)]:Set 比较引用,两个相同结构对象仍被保留 -
arr.filter((v, i) => arr.indexOf(v) === i):indexOf内部用===,同样只认引用 -
arr.reduce((acc, cur) => acc.includes(cur) ? acc : [...acc, cur], []):includes对象也走引用比较


















