JavaScript中的Map、WeakMap、Set、WeakSet详解
字数 1387 2025-11-14 23:09:55
JavaScript中的Map、WeakMap、Set、WeakSet详解
1. 描述
Map、WeakMap、Set、WeakSet是ES6引入的四种集合类型,用于存储数据集合。它们与普通对象和数组不同,具有特定的用途和内存管理特性。理解它们的区别和适用场景是JavaScript开发中的重要知识点。
2. Map(映射)
定义:Map是一种键值对集合,键可以是任意类型(对象、函数、基本类型等),而普通对象的键只能是字符串或Symbol。
特点:
- 保持键的插入顺序。
- 可通过
size属性直接获取元素数量。 - 无需担心键名与原型属性冲突(如
toString等)。
常用方法:
const map = new Map();
map.set('key', 'value'); // 添加键值对
map.get('key'); // 获取值 → "value"
map.has('key'); // 检查键是否存在 → true
map.delete('key'); // 删除键值对
map.clear(); // 清空集合
map.size; // 返回元素数量
与Object的区别:
- Map的键可以是任意类型,Object的键只能是字符串或Symbol。
- Map直接支持迭代(
for...of、forEach),Object需要先获取键数组。 - Map在频繁增删键值对的场景下性能更好。
3. WeakMap(弱映射)
定义:键必须是对象(非基本类型),值可以是任意类型。
核心特性:弱引用——如果键对象没有被其他引用,则会被垃圾回收(即使WeakMap中仍存在该键)。
限制:
- 不可迭代(没有
keys()、values()、forEach等方法)。 - 没有
size属性(因垃圾回收可能导致大小动态变化)。
适用场景:
- 存储与对象关联的私有数据(避免内存泄漏):
const privateData = new WeakMap();
class Person {
constructor(name) {
privateData.set(this, { name }); // 以实例为键存储数据
}
getName() {
return privateData.get(this).name;
}
}
// 当实例被销毁时,关联数据自动被回收
4. Set(集合)
定义:存储唯一值的集合,值可以是任意类型。
特点:
- 值不会重复(基于
SameValueZero算法,类似===,但认为NaN === NaN)。 - 保持插入顺序。
常用方法:
const set = new Set();
set.add(1); // 添加值
set.add(2);
set.has(1); // 检查值是否存在 → true
set.delete(1); // 删除值
set.size; // 元素数量 → 1
应用场景:
- 数组去重:
[...new Set([1, 2, 2, 3])] // [1, 2, 3] - 记录已处理过的对象(避免重复操作)。
5. WeakSet(弱集合)
定义:值必须是对象,且弱引用(对象无其他引用时会被回收)。
限制:
- 不可迭代,无
size属性。 - 仅支持
add()、has()、delete()方法。
适用场景:
- 标记对象(如检查对象是否已处理过):
const markedItems = new WeakSet();
const obj = {};
markedItems.add(obj);
if (markedItems.has(obj)) {
// 对象已被标记
}
// 当obj被销毁时,自动从WeakSet中移除
6. 关键区别总结
| 类型 | 键/值要求 | 是否可迭代 | 垃圾回收特性 |
|---|---|---|---|
| Map | 任意类型键 | 是 | 强引用(可能内存泄漏) |
| WeakMap | 键必须是对象 | 否 | 弱引用(自动回收) |
| Set | 任意类型值 | 是 | 强引用 |
| WeakSet | 值必须是对象 | 否 | 弱引用 |
7. 内存管理示例
// 强引用示例(Map可能导致内存泄漏)
let obj = { id: 1 };
const map = new Map();
map.set(obj, "data");
obj = null; // obj仍被Map引用,不会被垃圾回收
// 弱引用示例(WeakMap自动回收)
let obj2 = { id: 2 };
const weakMap = new WeakMap();
weakMap.set(obj2, "data");
obj2 = null; // obj2无其他引用,将被垃圾回收
8. 实践建议
- 需要存储键值对且键类型多样时,用Map。
- 需要关联对象与数据且避免内存泄漏时,用WeakMap。
- 需要存储唯一值列表时,用Set。
- 需要标记对象状态且避免干扰回收时,用WeakSet。