set与map目的不同:set用于去重,map用于映射;正确做法是先map转换再用set去重并转回数组;误区是在map回调中操作set导致无效值;set基于samevaluezero比较,对象需提取键去重。

Set 和 Array.prototype.map 本身目的不同:Set 用于去重,map 用于映射转换。直接“组合”它们并不能天然实现去重——因为 map 不改变数组长度,也不会自动过滤重复项。但你可以**先用 map 转换数据,再用 Set 去重,最后转回数组**,这是常见且合理的链式操作。
✅ 正确做法:map 后用 Set 去重(推荐)
适用于你想对原数组每一项做变换(比如取对象的某个属性、格式化字符串),再对变换结果去重:
- 先用
map得到新值数组 - 用
new Set(...)自动剔除重复值 - 用
Array.from()或展开运算符[...set]转回数组
示例:从用户列表中提取并去重城市名
const users = [
{ name: '张三', city: '北京' },
{ name: '李四', city: '上海' },
{ name: '王五', city: '北京' },
{ name: '赵六', city: '广州' }
];
const uniqueCities = [...new Set(users.map(u => u.city))];
// → ['北京', '上海', '广州']
❌ 常见误区:在 map 回调里操作 Set(不推荐)
有人试图在 map 的回调中维护一个外部 Set 并返回条件值,比如:
const seen = new Set();
const result = arr.map(x => {
if (!seen.has(x)) {
seen.add(x);
return x;
}
return undefined; // 或 null、跳过?
});
// → [x, undefined, x, undefined] —— 长度没变,还混着 undefined
这会导致数组长度不变、出现空洞或无效值,**不是真正去重**,后续还需 filter(Boolean) 等额外处理,可读性差且易出错。
⚠️ 注意:Set 去重基于 SameValueZero 比较
这意味着:
- 基本类型(string/number/boolean)按值去重 ✅
- 对象、数组、函数即使内容相同,也被视为不同引用 ❌
例如:new Set([[1], [1]])包含两个数组 - NaN 和 NaN 被认为相等(Set 中只保留一个)✅
如需对象级去重(如按 id),应先 map 提取唯一标识,再用 Set 处理该标识,而非直接塞对象。
? 进阶:一行实现对象数组按字段去重(无副作用)
结合 map + filter + Set,可安全去重对象数组:
const uniqueBy = (arr, key) => {
const seen = new Set();
return arr.filter(item => {
const val = typeof key === 'function' ? key(item) : item[key];
return seen.has(val) ? false : seen.add(val);
});
};
// 用法
const uniqueUsers = uniqueBy(users, 'city');
// 或用箭头函数提取:uniqueBy(users, u => u.city)
这个方案不依赖 map 主动去重,而是用 filter 配合 Set 控制逻辑,更清晰可靠。











