用 Map 实现对象数组去重最推荐按唯一字段(如 id)操作,核心是利用其键唯一性与任意类型键支持,时间复杂度 O(n),优于 filter+findIndex 的 O(n²);保留首次出现项需配合 filter 与 Map.has 判断,避免 JSON.stringify 因属性顺序和类型限制导致误判。

用 Map 实现对象数组去重,核心是利用它的键唯一性和任意类型键支持,比遍历+includes 或 filter+findIndex 更快,尤其在大数据量时优势明显。
按某个字段(如 id)去重 —— 最常用也最推荐
这是业务中最典型的场景:用户列表、商品列表等,重复由唯一标识字段决定。
- 创建一个空 Map,以目标字段(如 item.id)为键,整个对象为值
- 重复的 id 会自动覆盖旧值,只保留最后一次出现的对象
- 最后调用 Array.from(map.values()) 提取去重后的数组
示例代码:
const arr = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
{ id: 1, name: 'Alice (updated)' },
{ id: 3, name: 'Charlie' }
];
const uniqueArr = Array.from(
new Map(arr.map(item => [item.id, item])).values()
);
// 结果:[{ id: 1, name: 'Alice (updated)' }, { id: 2, name: 'Bob' }, { id: 3, name: 'Charlie' }]
保持首次出现的对象(而非最后)
上面方法默认保留最后一次,若需保留第一次,可改用 filter + Map.has 方式:
- 初始化一个空 Map 记录已见过的 key
- 遍历原数组,遇到未出现过的 id 就存入 Map 并返回 true,否则跳过
- 这样能天然保序且保留首项
示例代码:
const seen = new Map();
const uniqueArr = arr.filter(item => {
if (seen.has(item.id)) return false;
seen.set(item.id, true);
return true;
});
注意属性顺序与 JSON.stringify 的坑
别用 JSON.stringify(item) 当 Map 键来“按内容去重”——看似能处理任意对象,但有硬伤:
- 对象属性顺序不一致会导致字符串不同,比如
{a:1,b:2}和{b:2,a:1}序列化结果不同 - 函数、undefined、Symbol、Date、RegExp 等无法被正确序列化
- 性能差:每次都要 stringify,时间复杂度升为 O(n×m),m 是平均对象深度
真要按完整结构去重,应先标准化对象(如排序 key、转日期为字符串),再 stringify;但多数业务场景只需按 id、sku、email 等明确字段,Map 已足够。
为什么比其他方法快?
Map 的 .has() 和 .set() 平均时间复杂度是 O(1),而 findIndex / includes 在数组中查找是 O(n)。整体下来:
- Map 方案:O(n)
- filter + findIndex:O(n²)
- reduce + some:O(n²)
当数组长度超过 1 万,性能差距会非常明显,页面卡顿感可感知。











