Js WeakMap and WeakSet(弱映射和弱集合)

可达性

通常,当对象、数组之类的数据结构在内存中时,它们的子元素,如对象的属性、数组的元素都被认为是可达的。
如果使用对象作为常规 Map 的键,那么当 Map 存在时,该对象也将存在。它会占用内存,并且不会被(垃圾回收机制)回收。

例如:

let john = {name: "John”};

let map = new Map();
map.set(john, '...');

//john 被存储在了 map 中,
//我们可以使用 map.keys() 来获取它

WeakMap 在这方面有着根本的不同。它不会阻止垃圾回收机制作为对键的对象(key object)的回收。

WeakMap

WeakMapMap 的第一个不同点就是,WeakMap 的键必须是对象,不能是原始值:

let weakMap = new WeakMap();

let obj = {};

weakMap.set(obj, "ok");  //正常工作(以对象为键)

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

现在,如果我们在 weakMap 中使用一个对象作为键,并且没有其他对这个对象的引用 —— 该对象将会被从内存(和map)中自动清除。

let john = {name: "John"};

let weakMap = new WeakMap();
weakMap.set(john, "...");

john = null;  //覆盖引用

//john 被从内存中删除了!

如果 john 仅仅是作为 WeakMap 的键而存在 —— 它将会从 map (和内存中)自动删除。

WeakMap 不支持迭代以及 keys()values()entries() 方法。所以没有办法获取 WeakMap 的所有键或值。

WeakMap 只有以下的方法:

  • `weakMap.get(key)
  • `weakMap.set(key, value)
  • `weakMap.delete(key)
  • `weakMap.has(key)

为什么会有这种限制呢?这是技术的原因。如果一个对象丢失了其它所有引用(就像上面示例中的 john),那么它就会被垃圾回收机制自动回收。但是在从技术的角度并不能准确知道 何时会被回收。

这些都是由 JavaScript 引擎决定的。JavaScript 引擎可能会选择立即执行内存清理,如果现在正在发生很多删除操作,那么 JavaScript 引擎可能就会选择等一等,稍后再进行内存清理。因此,从技术上讲,WeakMap 的当前元素的数量是未知的。JavaScript 引擎可能清理了其中的垃圾,可能没清理,也可能清理了一部分。因此,暂不支持访问 WeakMap 的所有键/值的方法。

那么,在哪里我们会需要这样的数据结构呢?

使用案例

WeakSet

WeakSet 的表现类似:

  • Set 类似,但是我们只能向 WeakSet 添加对象(而不是原始值)。
  • 对象只有在其它某个(些)地方被访问的时候,才能留在 set 中。
  • Set 一样, WeakSet 支持 addhasdelete 方法,但不支持 sizekeys()`,并且不可迭代。

变“弱(weak)”的同时,它也可以作为额外的存储空间。但并非针对任意数据,而是针对“是/否”的事实。WeakSet 的元素可能代表着有关该对象的某些信息。

例如,我们可以将用户添加到 WeakMap 中,以追踪访问过我们网站的用户:

let visitedSet = new WeakSet();

let john = {name: "John"};
let pete = {name: "Pete"};
let mary = {name: "Mary"};

visitedSet.add(john);  //John 访问了我们
visitedSet.add(pete);  //然后是 Pete
visitedSet.add(john);  //John 再次访问

//visitedSet 现在有两个用户了

//检查 John 是否来访过?
alert(visitedSet.has(john));  //true

//检查 Mary 是否来访过?
alert(visitedSet.has(mary));  //false

john = null;

//visitedSet 将被自动清理(即自动清理其中已失效的值 john)

WeakMapWeakSet 最明显的局限性就是不能迭代,并且无法获取所有当前内容。那样可能会造成不便,但是并不会阻止 WeakMap/WeakSet 完成其主要工作 —— 成为在其它地方管理/存储“额外”的对象数据。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容