您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

ES6+ WeakSet

上一节我们学习了 Set 数据结构,本节将学习与它类似的数据结构 WeakSet,不同的是 WeakSet 存放的数据是类型。在 JavaScript 中,对象的引用是强保留的,这意味着只要持有对象的引用,它就不会被回收。JavaScript 属于高级语言, 存在 GC 机制,不需要直接地去操作内存,避免了很多问题。同时也让一些内存泄漏的问题变得更加不易察觉,所以 ES6 引入了 WeakSet 和 WeakMap 这样存储类型的数据结构,是不会阻止它被回收的。

WeakSet 对象允许你将对象报错在集合中。和 Set 一样,它们都是构造,都需要实例化才能使用。WeakSet 可以接收可迭代对象作为参数,则该对象的所有迭代值都会被进的 WeakSet 对象中。null 被认为是 undefined。

const ws = new WeakSet([iterable]);

WeakSet 对数据的操作相对 Set 是比较少的,只有、和查找,而且不能被遍历。

WeakSet 存放的一般都是对象的引用,如下实例:

var ws = new WeakSet();
var obj1 = {};
var obj2 = {};

ws.add(obj1);
ws.add(obj2);

ws.has(obj1);    // true
ws.has(obj2);   // true

ws.delete(obj1); // 从 set 中 obj1 对象
ws.has(obj1);    // false, obj1 对象已经被了
ws.has(obj2);    // true, obj2 依然存在

WeakSet 对象是一些对象值的集合,并且其中的每个对象值都只能出现一次。在 WeakSet 的集合中是唯一的,这和 Set 对象是一样的。

WeakSetSet 还是有明显的区别的,主要区别有两点:

当我们去取对象进行操作时,外界必然存在对这个对象的引用,否则我们不可能取到这个对象。而到底是做什么的呢?

首先我们要知道对象的生命周期是,只有对象存在引用就不会被 GC 回收。但有时候我们只是需要这个集合去判断一些逻辑,如果使用 Set 对象的话,就会存在引用,这样实例化的就不会被回收。这时,使用 WeakMap 就是有必要的事了。让我们来看下面的这个实例:

const requests = new WeakSet();
class ApiRequest {
  constructor() {
    requests.add(this);
  }

  makeRequest() {
    if(!request.has(this)) throw new Error("Invalid access");
    // do work
  }
}

上面的中,ApiRequest 想验证一下 this 的来源,使用 WeakMap 来存储这个 this 对象,并在 makeRequest 执行时去验证一下是否是 ApiRequest 这个类。这里的 requests 实例并不想参与到 ApiRequest 类中的生命周期中去,它只是作为使用的。如果使用 Set 对象的话,这个实例就会在 ApiRequest 类中存在引用关系,并一直保存在实例中,内存的开销,也可能会发生内存泄漏。而使用 WeakMap 则不同它是,只有在劫持的时候才会被到。

本节学习了 WeakMap 对象,它用了存储对象的值,存储的值都是类型。其实,就是将对象键到 WeakSet 上,而 WeakSet 对对象的引用不会影响回收,也就是说,你持有对象的引用,就可以元数据。一旦不再持有对象的引用,即使你仍持有并了该对象的引用,也会被回收。


联系我
置顶