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

瀏覽器相容性

另見