JavaScript中的Map、Set、WeakMap、WeakSet详解
字数 847 2025-11-12 15:53:41
JavaScript中的Map、Set、WeakMap、WeakSet详解
在JavaScript中,Map、Set、WeakMap和WeakSet是ES6引入的四种新的集合类型,用于存储和操作数据集合。它们提供了比传统对象和数组更强大的功能,特别是在处理键值对和唯一值方面。
1. Map(映射)
Map是一种键值对集合,其中键可以是任意类型(包括对象、函数等),而普通对象的键只能是字符串或Symbol。
创建与基本操作:
// 创建Map
const map = new Map();
// 添加键值对 - 使用set()方法
map.set('name', 'John');
map.set(1, '数字键');
map.set({id: 1}, '对象键');
// 获取值 - 使用get()方法
console.log(map.get('name')); // 'John'
// 检查键是否存在 - 使用has()方法
console.log(map.has(1)); // true
// 删除键值对 - 使用delete()方法
map.delete('name');
// 获取大小 - 使用size属性
console.log(map.size); // 2
// 清空Map - 使用clear()方法
map.clear();
Map的迭代方法:
const map = new Map([
['a', 1],
['b', 2],
['c', 3]
]);
// 使用keys()获取所有键
for (let key of map.keys()) {
console.log(key); // 'a', 'b', 'c'
}
// 使用values()获取所有值
for (let value of map.values()) {
console.log(value); // 1, 2, 3
}
// 使用entries()获取所有键值对(默认迭代器)
for (let [key, value] of map) {
console.log(key, value);
}
// 使用forEach方法
map.forEach((value, key) => {
console.log(key, value);
});
2. Set(集合)
Set是一种值的集合,其中每个值都是唯一的(不会重复),值的类型可以是任意的。
创建与基本操作:
// 创建Set
const set = new Set();
// 添加值 - 使用add()方法
set.add(1);
set.add(2);
set.add(2); // 重复值不会被添加
set.add('hello');
set.add({name: 'John'});
// 检查值是否存在 - 使用has()方法
console.log(set.has(1)); // true
// 删除值 - 使用delete()方法
set.delete(2);
// 获取大小 - 使用size属性
console.log(set.size); // 3
// 清空Set - 使用clear()方法
set.clear();
Set的实用场景:
// 数组去重
const numbers = [1, 2, 2, 3, 4, 4, 5];
const uniqueNumbers = [...new Set(numbers)];
console.log(uniqueNumbers); // [1, 2, 3, 4, 5]
// 字符串去重
const str = 'hello world';
const uniqueChars = [...new Set(str)].join('');
console.log(uniqueChars); // 'helo wrd'
3. WeakMap(弱映射)
WeakMap与Map类似,也是键值对集合,但有重要区别:
- 键必须是对象类型(不能是原始值)
- 键是弱引用,不会阻止垃圾回收
- 不可迭代,没有size属性和清空方法
WeakMap的使用:
const weakMap = new WeakMap();
let obj1 = {name: 'John'};
let obj2 = {name: 'Jane'};
// 设置键值对
weakMap.set(obj1, '私有数据1');
weakMap.set(obj2, '私有数据2');
// 获取值
console.log(weakMap.get(obj1)); // '私有数据1'
// 检查键是否存在
console.log(weakMap.has(obj1)); // true
// 删除键值对
weakMap.delete(obj1);
// 当obj2不再被引用时,对应的键值对会被自动垃圾回收
obj2 = null;
4. WeakSet(弱集合)
WeakSet与Set类似,但:
- 值必须是对象类型
- 值是弱引用,不会阻止垃圾回收
- 不可迭代,没有size属性
WeakSet的使用:
const weakSet = new WeakSet();
let obj1 = {id: 1};
let obj2 = {id: 2};
// 添加值
weakSet.add(obj1);
weakSet.add(obj2);
// 检查值是否存在
console.log(weakSet.has(obj1)); // true
// 删除值
weakSet.delete(obj1);
// 当obj2不再被引用时,会自动从集合中移除
obj2 = null;
5. 四种集合的对比总结
| 特性 | Map | Set | WeakMap | WeakSet |
|---|---|---|---|---|
| 键/值类型 | 任意类型 | 任意类型 | 对象类型 | 对象类型 |
| 可迭代 | 是 | 是 | 否 | 否 |
| 有size属性 | 是 | 是 | 否 | 否 |
| 垃圾回收 | 强引用 | 强引用 | 弱引用 | 弱引用 |
| 使用场景 | 需要任意类型键的映射 | 需要唯一值的集合 | 对象关联的元数据 | 对象存在的标记 |
6. 实际应用场景
Map的典型应用:
// 缓存计算结果
const cache = new Map();
function expensiveOperation(key) {
if (cache.has(key)) {
return cache.get(key);
}
const result = /* 复杂计算 */;
cache.set(key, result);
return result;
}
// DOM节点关联数据
const domData = new Map();
const button = document.querySelector('button');
domData.set(button, {clickCount: 0});
button.addEventListener('click', () => {
const data = domData.get(button);
data.clickCount++;
});
WeakMap的典型应用:
// 私有属性实现
const privateData = new WeakMap();
class Person {
constructor(name) {
privateData.set(this, {name});
}
getName() {
return privateData.get(this).name;
}
}
// DOM节点监听器管理
const listenerMap = new WeakMap();
function addListener(element, event, handler) {
if (!listenerMap.has(element)) {
listenerMap.set(element, new Map());
}
listenerMap.get(element).set(event, handler);
element.addEventListener(event, handler);
}
理解这些集合类型的特性和适用场景,可以帮助你在实际开发中选择最合适的数据结构,写出更高效、更安全的代码。