键控集合是按“键”来存取数据的集合,典型代表是 Map/WeakMap 与 Set/WeakSet。它们都按插入顺序可迭代,并使用 SameValueZero 作为相等性判断(NaN 等于自身,0 与 -0 视为相等)。
参考:Map/Set 的指南与对比来自 MDN Keyed collections(见文末参考)。
Map 是键值对集合(key → value),键可以是任意类型(对象、原始值、非注册 Symbol 都可)。
const sayings = new Map();sayings.set("dog", "woof");sayings.set("cat", "meow");sayings.set("elephant", "toot");
console.log(sayings.size); // 3console.log(sayings.get("dog")); // "woof"console.log(sayings.get("fox")); // undefinedconsole.log(sayings.has("bird")); // false
sayings.delete("dog");console.log(sayings.has("dog")); // false
for (const [key, value] of sayings) { console.log(`${key} goes ${value}`);}// "cat goes meow"// "elephant goes toot"
sayings.clear();console.log(sayings.size); // 0常用迭代接口:
map.keys(); // 可迭代的键map.values(); // 可迭代的值map.entries(); // 可迭代的 [key, value]map.forEach((value, key) => { /* ... */});Object 的键只能是字符串或 Symbol;Map 的键可为任意值。Map.size 即可得元素个数;Object 需手动统计。Map 按插入顺序;Object 的属性顺序有规则但不用于通用映射。Object 有原型链;可用 Object.create(null) 规避。选择建议:
Map。NaN)→ 用 Map。Map。Object。WeakMap 的键必须是对象或“非注册 Symbol”,且对键是“弱引用”(不会阻止垃圾回收)。它不可枚举(无 keys/values/entries/forEach),也没有 size、clear。
const privates = new WeakMap();
function Public() { const secret = { token: crypto.randomUUID() }; privates.set(this, secret);}
Public.prototype.getToken = function () { return privates.get(this).token; // 访问“私有”数据};用途:
注意:类的 #private 字段已能覆盖部分私有场景,但 WeakMap 仍适合跨实例、弱引用缓存等。
Set 是唯一值集合(无重复)。按插入顺序可迭代。
const mySet = new Set();mySet.add(1);mySet.add("some text");mySet.add("foo");
console.log(mySet.has(1)); // truemySet.delete("foo");console.log(mySet.size); // 2
for (const item of mySet) { console.log(item);}// 1// "some text"// Array → Set(自动去重)const s = new Set([1, 2, 2, 3]); // {1,2,3}
// Set → Arrayconst arr1 = Array.from(s);const arr2 = [...s];
// 快速去重const unique = [...new Set([1, 1, 2, 3, 3])]; // [1,2,3]const A = new Set([1, 2, 3]);const B = new Set([3, 4]);
// 并集const union = new Set([...A, ...B]); // {1,2,3,4}
// 交集const intersection = new Set([...A].filter((x) => B.has(x))); // {3}
// 差集(A-B)const difference = new Set([...A].filter((x) => !B.has(x))); // {1,2}Set.delete(value) O(1);数组需 indexOf + splice,通常更慢。NaN:数组 indexOf(NaN) 无法命中;Set.has(NaN) 可命中。Set 天生去重;数组需手动去重。仅存放对象的集合,元素为弱引用;不可枚举,无 size。常用于:
const visited = new WeakSet();function traverse(node) { if (visited.has(node)) return; // 避免重复处理 visited.add(node); // ... 处理 node 的子节点}Map 与 Set 使用 SameValueZero 判断相等:
NaN 等于自身(可作为键或集合成员正常命中)。0 与 -0 被视为相等。const m = new Map();m.set(NaN, "value");console.log(m.get(NaN)); // "value"
const s = new Set([0]);console.log(s.has(-0)); // trueMap/WeakMap 将输入对象映射到计算结果。WeakMap)。Set 去重、做集合运算;避免用数组手动去重。Map/Set 保存其“存在性”;选 WeakMap/WeakSet。Map/Set + for...of。Map / Set / WeakMap / WeakSet)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections