WeakSet

WeakSet 是垃圾可回收值的集合,包括对象和 非注册符号WeakSet 中的值只能出现一次。它在 WeakSet 系列中是独一无二的。

¥A WeakSet is a collection of garbage-collectable values, including objects and non-registered symbols. A value in the WeakSet may only occur once. It is unique in the WeakSet's collection.

描述

¥Description

WeakSet 的值必须是可垃圾回收的。大多数 primitive data types 可以任意创建并且没有生命周期,因此无法存储。对象和 非注册符号 可以被存储,因为它们是垃圾可收集的。

¥Values of WeakSets must be garbage-collectable. Most primitive data types can be arbitrarily created and don't have a lifetime, so they cannot be stored. Objects and non-registered symbols can be stored because they are garbage-collectable.

Set 对象的主要区别是:

¥The main differences to the Set object are:

  • WeakSet 仅是对象和符号的集合。它们不能像 Set 那样包含任何类型的任意值。
  • WeakSet 是弱的,这意味着对 WeakSet 中对象的引用是弱保存的。如果不存在对存储在 WeakSet 中的值的其他引用,则可以对这些值进行垃圾收集。

    注意:这也意味着集合中没有存储当前值的列表。WeakSets 不可枚举。

    ¥Note: This also means that there is no list of current values stored in the collection. WeakSets are not enumerable.

使用案例:检测循环引用

¥Use case: Detecting circular references

递归调用自身的函数需要一种通过跟踪哪些对象已被处理来防止循环数据结构的方法。

¥Functions that call themselves recursively need a way of guarding against circular data structures by tracking which objects have already been processed.

WeakSet 非常适合此目的:

¥WeakSets are ideal for this purpose:

js
// Execute a callback on everything stored inside an object
function execRecursively(fn, subject, _refs = new WeakSet()) {
  // Avoid infinite recursion
  if (_refs.has(subject)) {
    return;
  }

  fn(subject);
  if (typeof subject === "object" && subject) {
    _refs.add(subject);
    for (const key in subject) {
      execRecursively(fn, subject[key], _refs);
    }
    _refs.delete(subject);
  }
}

const foo = {
  foo: "Foo",
  bar: {
    bar: "Bar",
  },
};

foo.bar.baz = foo; // Circular reference!
execRecursively((obj) => console.log(obj), foo);

此处,WeakSet 在第一次运行时创建,并与每个后续函数调用一起传递(使用内部 _refs 参数)。

¥Here, a WeakSet is created on the first run, and passed along with every subsequent function call (using the internal _refs parameter).

对象的数量或其遍历顺序并不重要,因此 WeakSetSet 更适合(且性能更高)来跟踪对象引用,特别是在涉及大量对象的情况下。

¥The number of objects or their traversal order is immaterial, so a WeakSet is more suitable (and performant) than a Set for tracking object references, especially if a very large number of objects is involved.

构造函数

¥Constructor

WeakSet()

创建一个新的 WeakSet 对象。

实例属性

¥Instance properties

这些属性在 WeakSet.prototype 上定义并由所有 WeakSet 实例共享。

¥These properties are defined on WeakSet.prototype and shared by all WeakSet instances.

WeakSet.prototype.constructor

创建实例对象的构造函数。对于 WeakSet 实例,初始值为 WeakSet 构造函数。

WeakSet.prototype[@@toStringTag]

@@toStringTag 属性的初始值为字符串 "WeakSet"。该属性在 Object.prototype.toString() 中使用。

实例方法

¥Instance methods

WeakSet.prototype.add()

value 附加到 WeakSet 对象。

WeakSet.prototype.delete()

WeakSet 中删除 value。之后 WeakSet.prototype.has(value) 将返回 false

WeakSet.prototype.has()

返回一个布尔值,断言 value 是否存在于 WeakSet 对象中。

示例

¥Examples

使用 WeakSet 对象

¥Using the WeakSet object

js
const ws = new WeakSet();
const foo = {};
const bar = {};

ws.add(foo);
ws.add(bar);

ws.has(foo); // true
ws.has(bar); // true

ws.delete(foo); // removes foo from the set
ws.has(foo); // false, foo has been removed
ws.has(bar); // true, bar is retained

请注意,foo !== bar。虽然它们是相似的对象,但它们不是同一个对象。因此它们都被添加到集合中。

¥Note that foo !== bar. While they are similar objects, they are not the same object. And so they are both added to the set.

规范

Specification
ECMAScript Language Specification
# sec-weakset-objects

¥Specifications

浏览器兼容性

BCD tables only load in the browser

¥Browser compatibility

也可以看看