用Map去重的核心思路是利用其键的唯一性和支持任意类型(如对象、NaN)作键的特性,通过遍历数组并用Map记录已见元素来实现;相比Object更健壮,相比Set可附加元数据。

用 Map 去重的核心思路是:把数组元素作为 Map 的键,利用其键的唯一性来判断是否已出现过。相比对象,Map 支持任意类型作键(如对象、函数、NaN),且插入顺序可保证,更健壮可靠。
基本写法:遍历 + Map.has() 判断
一边遍历原数组,一边用 Map 记录“见过谁”,只保留首次出现的项:
function uniqueByMap(arr) {
const seen = new Map();
const result = [];
for (const item of arr) {
if (!seen.has(item)) {
seen.set(item, true);
result.push(item);
}
}
return result;
}
// 示例
console.log(uniqueByMap([1, 2, 2, 3, 'a', 'a', NaN, NaN]));
// → [1, 2, 3, 'a', NaN] ✅ NaN 能正确去重(Object 不行)
支持复杂类型:用 JSON.stringify 或自定义 key
原始值(数字、字符串、boolean、null、undefined、NaN)可直接作 Map 键;但对象、数组等引用类型默认按内存地址比较,相同结构也会被当作不同键。需手动转换为唯一字符串 key:
- 简单场景(纯对象/数组,无函数、undefined、循环引用):用
JSON.stringify生成 key - 更安全方式:使用第三方库(如
fast-deep-equal)或自定义哈希函数
示例(对象数组去重):
function uniqueObjects(arr) {
const seen = new Map();
return arr.filter(obj => {
const key = JSON.stringify(obj);
if (seen.has(key)) return false;
seen.set(key, true);
return true;
});
}
uniqueObjects([{a:1}, {b:2}, {a:1}]);
// → [{a:1}, {b:2}]
一行式写法(配合 reduce)
适合简洁表达,逻辑不变,但可读性略低,注意 reduce 初始值要设为空数组并传入空 Map 作为累加器的额外状态:
const uniqueByMap = arr =>
arr.reduce(
([result, map], item) =>
map.has(item)
? [result, map]
: [result.concat(item), map.set(item, 1)],
[[], new Map()]
)[0];
⚠️ 注意:这种写法每次新建数组(concat),大数据量时不推荐;生产环境建议用传统 for 循环提升性能。
和 Set 对比:何时选 Map?
Set 更轻量,去重原始值时首选它:
[...new Set([1,2,2,3])] // 简洁高效
但 Map 的优势在于:你不仅需要去重,还需要附带状态或元数据,比如:
- 记录某元素第几次出现(
map.set(item, count+1)) - 关联额外信息(
map.set(item, { firstIndex: i, count: 1 })) - 后续要查“某个值是否在数组中出现过”且需复用该状态
这时候 Map 就不只是去重工具,而是状态管理容器。


















