在 JavaScript 中,Map 和 WeakMap 都是用于存储键值对的数据结构,它们都允许使用对象作为键,这是与普通 Object 不同的地方。但两者在键的类型、垃圾回收机制、可操作性等方面存在显著差异。
✅ 一句话总结
Map是一个通用的键值对集合,键可以是任意类型;WeakMap则只能使用对象作为键,并且键是弱引用的,不会阻止垃圾回收,适用于临时存储对象元数据。
✅ 一、基础对比表格
| 特性 | Map | WeakMap |
|---|---|---|
| 键的类型 | 任意类型(对象、基本类型、函数) | 只能是对象(不能是 null 以外的基本类型) |
| 弱引用机制 | 不具备弱引用 | 键是弱引用,不影响垃圾回收 |
| 是否可迭代 | 可迭代(支持 forEach、entries() 等) | 不可迭代 |
| clear() 方法 | 有 | 无(已弃用) |
| size 属性 | 有 | 无 |
| 用途 | 存储任意键值对,适合长期存储 | 存储对象的临时数据,防止内存泄漏 |
✅ 二、详细对比说明
🔹 1. 键的类型
Map:
- 键可以是任意类型,包括:
- 基本类型(字符串、数字、布尔值)
- 对象
- 函数
Symbol
const map = new Map();
map.set('string', 'value');
map.set(123, 'number');
map.set(true, 'boolean');
map.set({ key: 'obj' }, 'object');
map.set(() => {}, 'function');
WeakMap:
- 只能使用对象作为键(包括
null),不能使用原始类型(如数字、字符串)。
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'value'); // ✅ 正确
weakMap.set('string', 'value'); // ❌ 报错:Invalid value used as weak map key
🔹 2. 弱引用机制(核心区别)
Map:
- 如果你把一个对象作为键存入
Map,那么这个对象将不会被垃圾回收机制回收,即使你不再使用它。
let obj = {};
const map = new Map();
map.set(obj, 'value');
obj = null; // 试图释放内存
console.log(map.get(obj)); // undefined,但 obj 仍被 map 引用,无法回收
WeakMap:
- 如果键对象没有其他引用,它将被垃圾回收机制回收,
WeakMap中对应的键值对也会被自动清除。
let obj = {};
const weakMap = new WeakMap();
weakMap.set(obj, 'value');
obj = null; // obj 没有其他引用,会被回收
console.log(weakMap.get(obj)); // undefined
📌 说明:
WeakMap的键是“弱引用”,不会阻止垃圾回收;- 适用于临时存储对象元数据,如缓存、私有属性等,防止内存泄漏。
🔹 3. 是否可迭代
Map:
- 是可迭代对象,支持:
map.forEach()map.keys()map.values()map.entries()
map.forEach((value, key) => {
console.log(key, value);
});
WeakMap:
- 不可迭代,不支持上述方法;
- 也不能获取键或值的集合;
- 不支持
size属性; - 不支持
clear()(有些环境已弃用);
for (let key of weakMap.keys()) { // ❌ 报错:weakMap.keys is not a function
}
🔹 4. 用途与适用场景
| 场景 | 推荐使用 |
|---|---|
| 需要存储任意类型的键 | Map |
| 需要遍历、统计键值对数量 | Map |
| 需要清除所有键值对 | Map |
| 为对象存储元数据、缓存 | WeakMap |
| 防止内存泄漏 | WeakMap |
| 键对象可能被垃圾回收 | WeakMap |
✅ 三、代码示例对比
示例 1️⃣:Map 的使用
const map = new Map();
const obj = {};
map.set(obj, 'value');
console.log(map.get(obj)); // 'value'
console.log(map.size); // 1
map.forEach((value, key) => {
console.log(key, value); // 输出对象和值
});
示例 2️⃣:WeakMap 的使用
const weakMap = new WeakMap();
const obj = {};
weakMap.set(obj, 'value');
console.log(weakMap.get(obj)); // 'value'
// 删除引用后,键值对会自动被回收
obj = null;
console.log(weakMap.get(obj)); // undefined
✅ 四、一句话总结
Map是功能完整、通用性强的键值对结构,适合长期存储和遍历;WeakMap是轻量级的、键为弱引用的结构,适合临时存储对象元数据,避免内存泄漏。根据使用场景选择合适的数据结构,是写出高效、安全代码的关键。
💡 进阶建议
- 在 React/Vue 中,
WeakMap常用于组件实例的私有状态管理; - 使用
WeakMap可以实现“私有属性”或“元数据绑定”; Map可用于缓存、计数器、字典等场景;- 使用 TypeScript 时,
Map和WeakMap都支持类型标注;