本文介绍如何在 javascript 中对对象数组执行多字段联合去重(如 name + lastname + city),保留首次出现的元素,剔除后续重复项,适用于真实业务中复杂的去重场景。
本文介绍如何在 javascript 中对对象数组执行多字段联合去重(如 name + lastname + city),保留首次出现的元素,剔除后续重复项,适用于真实业务中复杂的去重场景。
在实际开发中,单纯依据 id 或 eventUid 去重往往无法满足业务需求——例如用户导入数据时,需根据「姓名+姓氏+城市」组合判断是否为同一人,即使 eventUid 不同也应视为重复。此时,标准的 Set + JSON.stringify 或 Map 单键方案容易因字段冗余、大小写/空格差异或性能问题而失效。
推荐采用 filter() + findLastIndex() 组合方案,逻辑清晰、兼容性好(需 ES2023+ 支持 findLastIndex;若需兼容旧环境,可降级为 findIndex 配合 slice().reverse()),且天然支持任意字段组合比对。
✅ 核心实现
const input = [
{
"eventUid": "0fdb73d9-629f-4151-acab-7b48c24ef2D0",
"name": "John",
"lastName": "Doe",
"city": "Ukraine"
},
{
"eventUid": "0fdb73d9-629f-4151-aBab-7b48c24ef2e0",
"name": "Marcel",
"lastName": "Pilate",
"city": "Ukraine"
},
{
"eventUid": "0fcc73d9-629f-4151-aBab-7b48c24ef2e0",
"name": "John",
"lastName": "Doe",
"city": "Ukraine"
}
];
const filtered = input.filter((item, index) =>
input.findLastIndex(innerItem =>
innerItem.name === item.name &&
innerItem.lastName === item.lastName &&
innerItem.city === item.city
) === index
);
console.log(filtered);
// 输出两个对象:John Doe(Ukraine)仅保留第一个,Marcel Pilate 保留? 原理说明
- filter() 遍历每个元素,并传入当前 item 和其索引 index;
- 对每个 item,调用 findLastIndex() 在整个数组中查找最后一个满足字段组合相等的元素位置;
- 若该位置恰好等于当前 index,说明这是该组合最后一次出现 → 即首次出现的位置(因为后续重复项的 findLastIndex 结果会指向更前的索引,不等于自身 index);
- 因此,filter 仅保留“自己就是该组合最后一次出现”的元素——等价于保留首次出现项(因数组顺序固定,最后一个匹配项若为当前项,意味着它前面无相同项)。
? 小技巧:该逻辑本质是「反向保底」——不是找第一个,而是排除所有非末位匹配项,从而自然留下首次项。
⚠️ 注意事项与增强建议
-
大小写与空格敏感:上述示例严格区分大小写(如 "Ukraine" ≠ "ukraine")。生产环境建议标准化处理:
立即学习“Java免费学习笔记(深入)”;
const normalize = str => String(str).trim().toLowerCase(); // 替换比较逻辑为: normalize(innerItem.city) === normalize(item.city)
-
空值/undefined 安全:添加存在性校验,避免 undefined === undefined 误判:
innerItem.name != null && item.name != null && innerItem.name === item.name && // ... 其他字段
-
兼容旧浏览器(:
findLastIndex 可替换为:const lastIndex = [...input].reverse() .findIndex(innerItem => innerItem.name === item.name && innerItem.lastName === item.lastName && innerItem.city === item.city ); const actualLastIndex = lastIndex === -1 ? -1 : input.length - 1 - lastIndex; return actualLastIndex === index; -
性能考量:时间复杂度为 O(n²),适用于千级以内数据。超大数据量建议使用 Map 构建复合键缓存:
const seen = new Map(); const filtered = input.filter(item => { const key = `${item.name}|${item.lastName}|${item.city}`; if (seen.has(key)) return false; seen.set(key, true); return true; });
✅ 总结
基于多字段的对象数组去重,关键在于定义明确的「唯一性标识」。filter + findLastIndex 方案简洁、语义直观、无需额外依赖,是现代 JavaScript 的推荐实践。结合标准化处理与边界防护后,可稳健落地于表单去重、数据清洗、事件聚合等高频场景。










