WeakMap

  1. WeakMapMap 的第一个不同点就是,WeakMap必须是对象不能是原始值: ```javascript let weakMap = new WeakMap(); let obj = {};

weakMap.set(obj, “ok”); // 正常工作(以对象作为键) // 不能使用字符串作为键 weakMap.set(“test”, “Whoops”); // Error,因为 “test” 不是一个对象

  1. 如果在 weakMap 中使用一个对象作为键,并且**没有其他对这个对象的引用** —— 该对象将会被从内存(和map)中自动清除。<br />一个对象若**只被****弱引用**所引用,则被认为是**不可访问(或弱可访问)**的,并因此可能**在任何时刻被回收。**<br />**<br />在**深拷贝**中, 如果我们要**拷贝的对象**非常庞大时,使用Map会对**内存造成非常大的额外消耗**,而且我们**需要手动清除Map的属性**才能释放这块内存,而WeakMap会帮我们巧妙化解这个问题。
  2. ```javascript
  3. let john = { name: "John" };
  4. let weakMap = new WeakMap();
  5. weakMap.set(john, "...");
  6. john = null; // 覆盖引用
  7. // john 仅仅是作为 WeakMap 的键而存在, 因此 john 被从内存中删除了!
  1. WeakMap 不支持迭代以及 keys()values()entries() 方法。所以没有办法获取 WeakMap 的所有键或值。WeakMap 只有以下的方法
    • weakMap.get(key)
    • weakMap.set(key, value)
    • weakMap.delete(key)
    • weakMap.has(key)


为什么?
从技术的角度并不能准确知道这些未引用值
何时会被回收**。

  • JavaScript 引擎可能会选择立即执行内存清理
  • 但如果现在正在发生很多删除操作,那么 JavaScript 引擎可能就会选择等一等,稍后再进行内存清理。

因此,从技术上讲,WeakMap 的当前元素的数量是未知的。JavaScript 引擎可能清理了其中的垃圾,可能没清理,也可能清理了一部分。

应用场景

额外数据的存储
假如我们正在处理一个“属于”另一个代码的一个对象,也可能是第三方库,并想存储一些与之相关的数据,那么这些数据就应该与这个对象共存亡

  • 将这些数据放到 WeakMap 中,并使用该对象作为这些数据的键
    1. weakMap.set(john, "secret documents");
    2. // 如果 john 消失,secret documents 将会被自动清除

缓存

  1. // 📁 cache.js
  2. let cache = new WeakMap();
  3. // 计算并记结果
  4. function process(obj) {
  5. if (!cache.has(obj)) {
  6. let result = /* calculate the result for */ obj;
  7. cache.set(obj, result);
  8. }
  9. return cache.get(obj);
  10. }
  11. // 📁 main.js
  12. let obj = {/* some object */};
  13. let result1 = process(obj);
  14. let result2 = process(obj);
  15. // ……稍后,我们不再需要这个对象时:
  16. obj = null;
  17. // 无法获取 cache.size,因为它是一个 WeakMap,
  18. // 要么是 0,或即将变为 0
  19. // 当 obj 被垃圾回收,缓存的数据也会被清除

WeakSet

WeakSet 的表现类似:

  • Set 类似,但是我们只能向 WeakSet 添加对象(而不能是原始值)。
  • 对象只有在其它某个(些)地方能被访问的时候,才能留在 set 中。

Set 一样,WeakSet 支持 addhasdelete 方法,但不支持 sizekeys(),并且不可迭代。