JavaScript WeakMap
外观
WeakMap 是 JavaScript 中的一种特殊集合类型,用于存储键值对,其中键必须是对象(非原始值),且对键的引用是“弱引用”。这意味着当键对象不再被其他部分引用时,它会被垃圾回收机制自动清除,从而避免内存泄漏。WeakMap 是 ES6(ECMAScript 2015)引入的现代特性之一,适用于需要管理对象关联数据的场景。
基本介绍[编辑 | 编辑源代码]
WeakMap 与普通的 Map 类似,但有以下几个关键区别:
- 键必须是对象:WeakMap 的键只能是对象(包括数组、函数等),不能是原始值(如字符串、数字等)。
- 弱引用:WeakMap 对键的引用是弱引用,不会阻止垃圾回收机制回收键对象。
- 不可枚举:WeakMap 没有方法可以直接遍历其键或值(如 `keys()`、`values()`、`entries()`)。
- 无大小属性:WeakMap 没有 `size` 属性,因为其内容可能随时被垃圾回收。
WeakMap 的主要用途是存储与对象关联的私有或临时数据,而无需手动管理内存。
语法与基本用法[编辑 | 编辑源代码]
WeakMap 的构造函数和基本方法如下:
// 创建一个空的 WeakMap
const weakMap = new WeakMap();
// 键必须是对象
const key1 = { id: 1 };
const key2 = function() {};
// 设置键值对
weakMap.set(key1, "value associated with key1");
weakMap.set(key2, "value associated with key2");
// 获取值
console.log(weakMap.get(key1)); // 输出: "value associated with key1"
// 检查键是否存在
console.log(weakMap.has(key1)); // 输出: true
// 删除键值对
weakMap.delete(key1);
console.log(weakMap.has(key1)); // 输出: false
注意事项[编辑 | 编辑源代码]
- 如果尝试使用原始值作为键(如 `weakMap.set("stringKey", "value")`),会抛出 `TypeError`。
- 如果键对象被垃圾回收,对应的值也会从 WeakMap 中自动移除。
实际应用场景[编辑 | 编辑源代码]
WeakMap 的弱引用特性使其特别适合以下场景:
1. 私有数据存储[编辑 | 编辑源代码]
在类或模块中,WeakMap 可用于存储私有数据,避免污染对象的公共接口:
const privateData = new WeakMap();
class Person {
constructor(name, age) {
privateData.set(this, { name, age });
}
getName() {
return privateData.get(this).name;
}
getAge() {
return privateData.get(this).age;
}
}
const person = new Person("Alice", 30);
console.log(person.getName()); // 输出: "Alice"
// 外部无法直接访问 privateData 中的数据
2. 缓存系统[编辑 | 编辑源代码]
WeakMap 可用于缓存计算结果,当缓存键不再需要时自动清理:
const cache = new WeakMap();
function computeExpensiveValue(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = /* 复杂计算 */ obj.someProperty * 2;
cache.set(obj, result);
return result;
}
const data = { someProperty: 42 };
console.log(computeExpensiveValue(data)); // 计算并缓存
console.log(computeExpensiveValue(data)); // 从缓存读取
3. DOM 节点元数据[编辑 | 编辑源代码]
在操作 DOM 时,WeakMap 可以存储与 DOM 节点关联的元数据,当节点被移除时自动清理:
const nodeMetadata = new WeakMap();
function setNodeData(node, data) {
nodeMetadata.set(node, data);
}
function getNodeData(node) {
return nodeMetadata.get(node);
}
const div = document.createElement("div");
setNodeData(div, { clicked: false });
console.log(getNodeData(div)); // 输出: { clicked: false }
// 当 div 被移除时,元数据会自动清除
WeakMap 与 Map 的对比[编辑 | 编辑源代码]
特性 | WeakMap | Map |
---|---|---|
键类型 | 仅对象 | 任意值 |
键引用类型 | 弱引用 | 强引用 |
可遍历性 | 不可遍历 | 可遍历 |
内存管理 | 自动清理 | 需手动清理 |
数学背景(可选)[编辑 | 编辑源代码]
WeakMap 的弱引用特性可以用数学关系描述: 其中:
- 是所有对象的集合。
- 是所有可能值的集合。
- 当 不再可达时, 会从 WeakMap 中移除。
总结[编辑 | 编辑源代码]
WeakMap 是 JavaScript 中一种高效的内存管理工具,特别适合以下场景:
- 需要存储对象关联数据且不希望干扰垃圾回收。
- 实现私有属性或模块内部状态。
- 缓存系统或 DOM 节点元数据管理。
由于其不可枚举和弱引用的特性,WeakMap 不适用于需要频繁遍历或长期保留键的场景。正确使用 WeakMap 可以显著减少内存泄漏的风险。