WeakMap
WeakMap和Map的第一个不同点就是,WeakMap的键必须是对象,不能是原始值: ```javascript let weakMap = new WeakMap(); let obj = {};
weakMap.set(obj, “ok”); // 正常工作(以对象作为键) // 不能使用字符串作为键 weakMap.set(“test”, “Whoops”); // Error,因为 “test” 不是一个对象
如果在 weakMap 中使用一个对象作为键,并且**没有其他对这个对象的引用** —— 该对象将会被从内存(和map)中自动清除。<br />一个对象若**只被****弱引用**所引用,则被认为是**不可访问(或弱可访问)**的,并因此可能**在任何时刻被回收。**<br />**<br />在**深拷贝**中, 如果我们要**拷贝的对象**非常庞大时,使用Map会对**内存造成非常大的额外消耗**,而且我们**需要手动清除Map的属性**才能释放这块内存,而WeakMap会帮我们巧妙化解这个问题。```javascriptlet john = { name: "John" };let weakMap = new WeakMap();weakMap.set(john, "...");john = null; // 覆盖引用// john 仅仅是作为 WeakMap 的键而存在, 因此 john 被从内存中删除了!
WeakMap不支持迭代以及keys(),values()和entries()方法。所以没有办法获取WeakMap的所有键或值。WeakMap只有以下的方法:weakMap.get(key)weakMap.set(key, value)weakMap.delete(key)weakMap.has(key)
为什么?
从技术的角度并不能准确知道这些未引用值 何时会被回收**。
- JavaScript 引擎可能会选择立即执行内存清理,
- 但如果现在正在发生很多删除操作,那么 JavaScript 引擎可能就会选择等一等,稍后再进行内存清理。
因此,从技术上讲,WeakMap 的当前元素的数量是未知的。JavaScript 引擎可能清理了其中的垃圾,可能没清理,也可能清理了一部分。
应用场景
额外数据的存储
假如我们正在处理一个“属于”另一个代码的一个对象,也可能是第三方库,并想存储一些与之相关的数据,那么这些数据就应该与这个对象共存亡。
- 将这些数据放到
WeakMap中,并使用该对象作为这些数据的键weakMap.set(john, "secret documents");// 如果 john 消失,secret documents 将会被自动清除
缓存
// 📁 cache.jslet cache = new WeakMap();// 计算并记结果function process(obj) {if (!cache.has(obj)) {let result = /* calculate the result for */ obj;cache.set(obj, result);}return cache.get(obj);}// 📁 main.jslet obj = {/* some object */};let result1 = process(obj);let result2 = process(obj);// ……稍后,我们不再需要这个对象时:obj = null;// 无法获取 cache.size,因为它是一个 WeakMap,// 要么是 0,或即将变为 0// 当 obj 被垃圾回收,缓存的数据也会被清除
WeakSet
WeakSet 的表现类似:
- 与
Set类似,但是我们只能向WeakSet添加对象(而不能是原始值)。 - 对象只有在其它某个(些)地方能被访问的时候,才能留在 set 中。
跟 Set 一样,WeakSet 支持 add,has 和 delete 方法,但不支持 size 和 keys(),并且不可迭代。
