Set和Map是原生集合类型,非语法糖:Set强制唯一且O(1)查重(Object.is判等),Map支持任意类型键(含对象、NaN)并严格按插入序迭代,二者不可被数组/对象可靠模拟。

JavaScript 的 Set 和 Map 不是语法糖,而是原生集合类型——它们解决的是数组/对象做不到的事:前者强制唯一、后者允许任意类型作键。
为什么不能用数组去“模拟”Set?
数组本身不阻止重复,filter((v, i, a) => a.indexOf(v) === i) 或 [...new Set(arr)] 看似等价,但性能和语义完全不同:
-
Set插入、删除、查重都是 O(1) 平均时间复杂度;数组去重是 O(n²) -
Set用Object.is()判等(0和-0不同,NaN === NaN为false但Set视为相同) -
Array.from(new Set([0, -0, NaN, NaN]))→[0, NaN],而数组手动去重极易漏掉这类边界
Map 的键可以是函数、对象、Symbol,但不能是普通字符串“伪装”的引用
这是最常踩的坑:把对象当 key 存进 Map,却每次 new 一个新对象去取——永远取不到。
const map = new Map();
const key = { id: 1 };
map.set(key, 'user1');
map.get({ id: 1 }); // undefined ← 错!不是同一个引用
map.get(key); // 'user1' ← 对
- 只认内存地址,不深比较结构
- 若需按内容查,得自己序列化(如
JSON.stringify(obj)),但注意函数、undefined、Date 等会丢失 -
Map中NaN作键是合法且可检索的,而对象属性名会被强制转成字符串({[NaN]: 1}→{'NaN': 1})
Set 和 Map 的迭代顺序与插入顺序严格一致
这点和对象不同——Object.keys() 在 ES2015+ 虽也保持插入顺序,但只对字符串/数字键有效;而 Set 和 Map 对所有值类型都保证 FIFO。
立即学习“Java免费学习笔记(深入)”;
-
Set.prototype.values()、keys()、entries()返回的迭代器顺序一致 -
Map的for (const [key, val] of map)一定按set()的先后执行 - 可用于实现 LRUCache:靠
Map迭代首尾操作(map.keys().next().value取最老,map.delete()+map.set()刷新最新)
真正难的不是 API 记忆,而是判断什么时候该用 Set 而不是 filter + includes,或者该用 Map 而不是嵌套对象——关键看是否需要动态增删、是否依赖原始值相等性、是否要求稳定遍历序。这些在高频更新或大数据量时,会直接暴露为性能断崖或逻辑 bug。











