Skip to main content

WeakMap

WeakMap 是可被 垃圾回收 的值的集合,WeakMap 允许将数据与对象相关联。

WeakMap其中的 必须是 对象非全局注册的符号, 值可以使用任意的Javascript 数据类型。

初始化

可以给 WeakMap 构造函数 传入一个 Array 或者 可迭代对象

const key1 = { id: 1 };
const key2 = { id: 2 };
const key3 = { id: 3 };

const weakMap = new WeakMap();

weakMap.set(key1, "value1").set(key2, "value2").set(key3, "value3");

console.log(weakMap.get(key1));
console.log(weakMap.get(key2));
console.log(weakMap.get(key3));

如果尝试使用 非对象设置 , 会抛出 TypeError

const weakMap = new WeakMap();

weakMap.set("key1", "value1");
// Uncaught TypeError: Invalid value used as weak map key

基本 API

可以使用 set() 在添加 键值对。 set() 方法返回 WeakMap 实例, 因此 可以把 多个操作 连接 起来。

可以使用 get()has() 进行查询。可以通过 size 属性获取 WeakMap 中键值对的数量。

可以使用 delete()clear() 删除值。

const key1 = { id: 1 };
const key2 = { id: 2 };

const weakMap = new WeakMap();

console.log(weakMap.has(key1)); // false
console.log(weakMap.get(key2)); // undefined

weakMap.set(key1, "Matt");
weakMap.set(key2, "Frisbie");

console.log(weakMap.has(key1)); // true
console.log(weakMap.get(key2)); // Matt

weakMap.delete(key1);

console.log(weakMap.has(key1)); // false
console.log(weakMap.has(key2)); // true

弱键

一个对象作为 WeakMap 存在 , 不会阻止垃圾回收。

如果一个对象作为 被回收, 那么在 WeakMap 中相应的值便成为了进行 垃圾回收 的候选对象。

set 方法() 初始化了一个新对象 , 并将它作用一个字符串的键。

因为没有指向这个对象的其他引用 , 所以当这段代码执行后 , 这个对象 就会被当作垃圾回收。

然后 这个键值对 就从 WeakMap中消失了。

const weakMap = new WeakMap();

weakMap.set({}, "value");

container 对象维护着一个 的引用, 因此这个对象 不会成为垃圾回收的目标。

但是如果调用removeReference(), 就会摧毁对象的最后一个引用, 垃圾回收就会把这个键值对清理掉。

const weakMap = new WeakMap();

const container = {
key: {},
};

weakMap.set(container.key, "value");

function removeReference() {
container.key = null;
}

不可迭代

因为 WeakMap 中的 任何时候都有可能会被销毁,所以没有必要提供迭代键值对的能力。

使用 WeakMap

私有数据存储

const privateData = new WeakMap();

class MyClass {
constructor() {
privateData.set(this, { secret: 42 });
}

getSecret() {
return privateData.get(this).secret;
}
}

const instance = new MyClass();

console.log(instance.getSecret()); // 42

DOM 节点关联数据

const nodeData = new WeakMap();

const node = document.getElementById("__docusaurus");
nodeData.set(node, 0);

node.addEventListener("click", () => {
let clicks = nodeData.get(node);
nodeData.set(node, ++clicks);
console.log(`Clicked ${clicks} times`);
});