Map和Set是解决键值映射与自动去重问题的专用工具:Map支持对象作键、插入顺序遍历、O(1)查存;Set提供O(1)去重与存在性判断;小规模静态场景仍宜用对象和数组。

Map 和 Set 不是“比对象和数组强”,而是解决不同问题的专用工具——当你需要键值映射且键可能是对象、或需要自动去重+快速查存时,它们就是更安全、更快、更少出错的选择。
用 Map 替代对象做键值映射:为什么 obj[{}] 总是失效?
普通对象把所有键强制转成字符串,{id: 1} 和 {id: 2} 都变成 "[object Object]",结果互相覆盖。Map 没这问题,它认的是引用本身。
- ✅ 正确做法:
const userMap = new Map();
const user1 = { id: 1 };
const user2 = { id: 2 };
userMap.set(user1, "Alice");
userMap.set(user2, "Bob");
console.log(userMap.get(user1)); // "Alice" - ❌ 错误写法:
obj[{}] = "Alice"→ 实际是obj["[object Object]"] = "Alice",第二次赋值就覆盖了 - 遍历时顺序稳定:
for (const [key, val] of map)严格按插入顺序;对象的for...in在数字键上会升序排列,不可靠 - 获取数量直接用
map.size;对象得写Object.keys(obj).length,还可能误算原型链上的属性
用 Set 替代数组去重:别再写 filter((v, i) => arr.indexOf(v) === i)
数组去重本质是 O(n²) 查找,10 万条数据时卡顿明显;Set 底层哈希实现,插入/判断存在性都是平均 O(1)。
- ✅ 一行去重:
const uniqueIds = [...new Set([1, 2, 2, 3, 3])]; // [1, 2, 3]
- ✅ 判断是否存在快:
set.has(x)比arr.includes(x)或arr.indexOf(x) > -1快一个数量级(尤其大数据量) - ⚠️ 注意:
Set用 SameValueZero 规则判等,所以NaN === NaN成立,而数组indexOf(NaN)返回 -1 - 不支持下标访问:
set[0]是undefined,要转数组才可索引:[...set][0]
什么时候不该用 Map/Set?别为了“新”而换
它们不是银弹。小规模、静态、结构简单时,对象和数组反而更直观、更轻量。
立即学习“Java免费学习笔记(深入)”;
- 配置项、API 响应字段映射、HTML 属性名 → 用
const config = { timeout: 5000, retries: 3 }更自然 - 需要随机访问第 N 个元素、频繁按索引增删 → 数组仍是首选,
arr.push()/arr.splice()语义清晰 - JSON 序列化必须原生支持 →
JSON.stringify()不认 Map/Set,得手动转:Object.fromEntries(map)或[...set] - 弱引用场景(如缓存 DOM 元素,又不想阻止 GC)→ 改用
WeakMap/WeakSet,它们不能遍历,但内存更友好
真正容易被忽略的点是:Map/Set 的「语义明确性」——当你写出 new Map(),别人立刻知道这是动态键值关系;写出 new Set(),就知道这个集合必须唯一。这种意图表达,比任何注释都可靠。











