WeakRef

Baseline 广泛可用 *

此特性已得到良好支持,可在多种设备和浏览器版本上使用。自 2021 年 4 月起,所有浏览器均已支持此特性。

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

WeakRef 对象允许您持有对另一个对象的弱引用,而不会阻止该对象被垃圾回收。

描述

WeakRef 对象包含一个对对象的弱引用,该对象被称为其目标被引用对象。对对象的弱引用是一种不会阻止对象被垃圾回收器回收的引用。相比之下,普通(或)引用会将对象保留在内存中。当一个对象不再有任何强引用指向它时,JavaScript 引擎的垃圾回收器可能会销毁该对象并回收其内存。如果发生这种情况,您将无法再从弱引用中获取该对象。

由于未注册的 Symbol 也可以被垃圾回收,因此它们也可以用作 WeakRef 对象的 [目标](#target_object)。然而,这种用例是有限的。

尽可能避免使用

正确使用 WeakRef 需要仔细考虑,最好能避免就避免。同样重要的是,要避免依赖规范未保证的任何特定行为。垃圾回收何时、如何发生以及是否发生取决于任何给定 JavaScript 引擎的实现。您在一个引擎中观察到的任何行为,在另一个引擎、同一引擎的另一个版本,甚至在同一引擎的同一版本中的一个略有不同的情况下,都可能有所不同。垃圾回收是一个棘手的问题,JavaScript 引擎的实现者们正在不断完善和改进他们的解决方案。

以下是引入 WeakRef提案中作者提出的一些具体要点:

垃圾回收器很复杂。如果应用程序或库依赖于 GC 以及时、可预测的方式清理 WeakRef 或调用最终项 [清理回调],它可能会感到失望:清理可能比预期发生得晚得多,甚至根本不发生。导致不确定性的因素包括:

  • 一个对象可能比另一个对象更早被垃圾回收,即使它们同时变得不可达,例如,由于分代收集。
  • 可以使用增量和并发技术将垃圾回收工作分解到一段时间内。
  • 可以使用各种运行时启发式方法来平衡内存使用和响应能力。
  • JavaScript 引擎可能持有对看起来是不可达内容的引用(例如,在闭包或内联缓存中)。
  • 不同的 JavaScript 引擎可能以不同的方式处理这些问题,或者同一引擎可能在其版本之间更改其算法。
  • 复杂因素可能导致对象被意外地长时间保持活动状态,例如与某些 API 一起使用。

关于 WeakRef 的注意事项

  • 如果您的代码刚刚为目标对象创建了一个 WeakRef,或者通过 WeakRefderef 方法获取了一个目标对象,那么该目标对象将不会被回收,直到当前 JavaScript 任务(包括在脚本任务结束时运行的任何 Promise 反应任务)结束。也就是说,您只能在事件循环的轮次之间“看到”对象被回收。这主要是为了避免让任何给定 JavaScript 引擎的垃圾回收器行为在代码中变得明显——因为如果它变得明显,人们就会编写依赖于该行为的代码,而当垃圾回收器的行为发生变化时,这些代码就会中断。(垃圾回收是一个棘手的问题;JavaScript 引擎的实现者们正在不断完善和改进其工作方式。)
  • 如果多个 WeakRefs 指向同一个目标,它们之间是保持一致的。在一个任务中,调用其中一个的 deref 所得到的结果将与调用另一个的 deref 所得到的结果匹配,您不会从一个中得到目标对象,而从另一个中得到 undefined
  • 如果 WeakRef 的目标也位于一个 FinalizationRegistry 中,那么 WeakRef 的目标会在任何与注册表相关的清理回调被调用时或之前被清除;如果您的清理回调调用了目标对象的 WeakRefderef,它将收到 undefined
  • 您无法更改 WeakRef 的目标,它始终只会是原始目标对象,或者在目标对象被回收后为 undefined
  • 即使没有任何强引用指向目标对象,WeakRefderef 的调用也可能永远不会返回 undefined,因为垃圾回收器可能永远不会决定回收该对象。

构造函数

WeakRef()

创建一个新的 WeakRef 对象。

实例属性

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

WeakRef.prototype.constructor 可选

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

注意:此属性在规范中被标记为“规范可选”,这意味着符合规范的实现可能不会暴露 constructor 属性。这可以防止任意代码获取 WeakRef 构造函数并能够观察垃圾回收。然而,所有主流引擎默认都会暴露它。

WeakRef.prototype[Symbol.toStringTag]

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

实例方法

WeakRef.prototype.deref()

返回 WeakRef 对象的目标对象,如果目标对象已被回收,则返回 undefined

示例

使用 WeakRef 对象

此示例启动一个在 DOM 元素中显示的计数器,当元素不再存在时停止。

js
class Counter {
  constructor(element) {
    // Remember a weak reference to the DOM element
    this.ref = new WeakRef(element);
    this.start();
  }

  start() {
    if (this.timer) {
      return;
    }

    this.count = 0;

    const tick = () => {
      // Get the element from the weak reference, if it still exists
      const element = this.ref.deref();
      if (element) {
        element.textContent = ++this.count;
      } else {
        // The element doesn't exist anymore
        console.log("The element is gone.");
        this.stop();
        this.ref = null;
      }
    };

    tick();
    this.timer = setInterval(tick, 1000);
  }

  stop() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = 0;
    }
  }
}

const counter = new Counter(document.getElementById("counter"));
setTimeout(() => {
  document.getElementById("counter").remove();
}, 5000);

规范

规范
ECMAScript® 2026 语言规范
# sec-weak-ref-objects

浏览器兼容性

另见