WeakSet

Baseline 广泛可用 *

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 2015 年 9 月以来,该特性已在各大浏览器中可用。

* 此特性的某些部分可能存在不同级别的支持。

WeakSet 是一种可垃圾回收的值的集合,包括对象和未注册的 SymbolWeakSet 中的值只能出现一次。在 WeakSet 的集合中是唯一的。

描述

WeakSet 的值必须是可垃圾回收的。大多数原始数据类型可以任意创建且没有生命周期,因此不能存储。对象和未注册的 Symbol 可以存储,因为它们是可垃圾回收的。

Set 对象的主要区别在于

  • WeakSet 仅包含对象和 Symbol。它们不能包含任意类型的值,而Set 可以。

  • WeakSet的,这意味着对 WeakSet 中对象的引用是弱引用。如果 WeakSet 中存储的值没有其他引用存在,这些值就可以被垃圾回收。

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

键的相等性

与常规 Set 一样,值相等性基于SameValueZero 算法,该算法与 === 运算符相同,因为 WeakSet 只能包含对象和 Symbol 值。这意味着对于对象值,相等性基于对象标识。它们是通过引用而不是值进行比较的。

构造函数

WeakSet()

创建一个新的 WeakSet 对象。

实例属性

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

WeakSet.prototype.constructor

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

WeakSet.prototype[Symbol.toStringTag]

[Symbol.toStringTag] 属性的初始值为字符串 "WeakSet"。此属性用于 Object.prototype.toString()

实例方法

WeakSet.prototype.add()

将指定值插入此集合,如果尚不存在。

WeakSet.prototype.delete()

如果指定值存在于此集合中,则将其从集合中移除。

WeakSet.prototype.has()

返回一个布尔值,指示指定值是否存在于此 WeakSet 中。

示例

使用 WeakSet 对象

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。虽然它们是相似的对象,但它们不是同一个对象。因此它们都被添加到了集合中。

检测循环引用

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

WeakSet 非常适合此目的

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 参数)传递。

对象的数量或它们的遍历顺序并不重要,因此 WeakSetSet 更适合(且性能更好)来跟踪对象引用,尤其是当涉及大量对象时。

规范

规范
ECMAScript® 2026 语言规范
# sec-weakset-objects

浏览器兼容性

另见