WeakRef

この記事は翻訳が完了していません。 この記事の翻訳にご協力ください

WeakRef オブジェクトにより、ガベージコレクションが行われることを妨げない他のオブジェクトへの弱い参照を保持します。

解説

WeakRef オブジェクトはオブジェクトへの弱い参照を含み、これはターゲットまたはリファレントと呼ばれます。オブジェクトへの弱い参照は、ガベージコレクターによるオブジェクトの回収を妨げない参照です。対照的に、通常の (または強い) 参照はオブジェクトをメモリに保持します。オブジェクトが強い参照を持たなくなった場合、 JavaScript エンジンのガベージコレクターはオブジェクトを破棄してメモリを再取得することがあります。そうなると、弱い参照からオブジェクトを取得することはできなくなります。

注: 下記のできる限り避けるの節をご覧ください。正しい WeakRef の使用は注意深く考える必要があり、可能であれば避けるのが最良です。

コンストラクター

WeakRef()
新しい WeakRef オブジェクトを生成します。

インスタンスメソッド

WeakRef.prototype.deref()
WeakRef オブジェクトの対象オブジェクトを返すか、対象オブジェクトが既に回収されている場合は undefined を返します。

可能な限り避ける

WeakRef の正しい使用には慎重な検討が必要であり、可能であれば避けた方が良いでしょう。また、仕様で保証されていない特定の動作に依存しないことも重要です。ガベージコレクションがいつ、どのように、そしてどのように発生するかは、使用している JavaScript エンジンの実装に依存します。あるエンジンで観察した動作が、別のエンジン、同じエンジンの別のバージョン、あるいは同じエンジンの同じバージョンでも少し違う状況では異なる可能性があります。ガベージコレクションは、 JavaScript エンジンの実装者が常に解決策を改良している難しい問題です。

ここでは、 WeakRef の提案の著者がその説明文書に盛り込んだ具体的なポイントをいくつか紹介します。

Garbage collectors are complicated. If an application or library depends on GC cleaning up a WeakRef or calling a finalizer [cleanup callback] in a timely, predictable manner, it's likely to be disappointed: the cleanup may happen much later than expected, or not at all. Sources of variability include:

  • One object might be garbage-collected much sooner than another object, even if they become unreachable at the same time, e.g., due to generational collection.
  • Garbage collection work can be split up over time using incremental and concurrent techniques.
  • Various runtime heuristics can be used to balance memory usage, responsiveness.
  • The JavaScript engine may hold references to things which look like they are unreachable (e.g., in closures, or inline caches).
  • Different JavaScript engines may do these things differently, or the same engine may change its algorithms across versions.
  • Complex factors may lead to objects being held alive for unexpected amounts of time, such as use with certain APIs.

WeakRef における注意

Some notes on WeakRefs:

  • If your code has just created a WeakRef for a target object, or has gotten a target object from a WeakRef's deref method, that target object will not be reclaimed until the end of the current JavaScript job (including any promise reaction jobs that run at the end of a script job). That is, you can only "see" an object get reclaimed between turns of the event loop. This is primarily to avoid making the behavior of any given JavaScript engine's garbage collector apparent in code — because if it were, people would write code relying on that behavior, which would break when the garbage collector's behavior changed. (Garbage collection is a hard problem; JavaScript engine implementers are constantly refining and improving how it works.)
  • If multiple WeakRefs have the same target, they're consistent with one another. The result of calling deref on one of them will match the result of calling deref on another of them (in the same job), you won't get the target object from one of them but undefined from another.
  • If the target of a WeakRef is also in a FinalizationRegistry, the WeakRef's target is cleared at the same time or before any cleanup callback associated with the registry is called; if your cleanup callback calls deref on a WeakRef for the object, it will receive undefined.
  • You cannot change the target of a WeakRef, it will always only ever be the original target object or undefined when that target has been reclaimed.
  • A WeakRef might never return undefined from deref, even if nothing strongly holds the target, because the garbage collector may never decide to reclaim the object.

WeakRef オブジェクトの使用

This example starts a counter shown in a DOM element, stopping when the element doesn't exist anymore:

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"));
counter.start();
setTimeout(() => {
  document.getElementById("counter").remove();
}, 5000);

仕様書

仕様書
WeakRefs
WeakRef の定義

ブラウザーの互換性

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeAndroid 版 FirefoxAndroid 版 OperaiOSのSafariSamsung InternetNode.js
WeakMapChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6IE 完全対応 11Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.
WeakMap() constructorChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6IE 完全対応 11Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.
clear
非推奨非標準
Chrome 未対応 36 — 43Edge 未対応 なしFirefox 未対応 20 — 46IE 完全対応 11Opera 未対応 25 — 30Safari 未対応 8 — 9WebView Android 未対応 37 — 43Chrome Android 未対応 36 — 43Firefox Android 未対応 20 — 46Opera Android 未対応 25 — 30Safari iOS 未対応 8 — 9Samsung Internet Android 未対応 3.0 — 4.0nodejs 未対応 0.12 — 4.0.0
deleteChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
IE 完全対応 11Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.
getChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. However, the ES2015 specification specifies to return undefined instead. Furthermore, WeakMap.prototype.get accepted an optional second argument as a fallback value, which is not part of the standard. Both non-standard behaviors are removed in version 38 and higher.
IE 完全対応 11Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. However, the ES2015 specification specifies to return undefined instead. Furthermore, WeakMap.prototype.get accepted an optional second argument as a fallback value, which is not part of the standard. Both non-standard behaviors are removed in version 38 and higher.
Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.
hasChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
IE 完全対応 11Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.
setChrome 完全対応 36Edge 完全対応 12Firefox 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
IE 部分対応 11
補足
部分対応 11
補足
補足 Returns 'undefined' instead of the 'Map' object.
Opera 完全対応 23Safari 完全対応 8WebView Android 完全対応 37Chrome Android 完全対応 36Firefox Android 完全対応 6
補足
完全対応 6
補足
補足 Prior to Firefox 38, this method threw a TypeError when the key parameter was not an object. This has been fixed in version 38 and later to return false as per the ES2015 standard.
Opera Android 完全対応 24Safari iOS 完全対応 8Samsung Internet Android 完全対応 3.0nodejs 完全対応 0.12
完全対応 0.12
完全対応 0.10
無効
無効 From version 0.10: this feature is behind the --harmony runtime flag.

凡例

完全対応  
完全対応
部分対応  
部分対応
未対応  
未対応
非標準。ブラウザー間の互換性が低い可能性があります。
非標準。ブラウザー間の互換性が低い可能性があります。
非推奨。新しいウェブサイトでは使用しないでください。
非推奨。新しいウェブサイトでは使用しないでください。
実装ノートを参照してください。
実装ノートを参照してください。
ユーザーが明示的にこの機能を有効にしなければなりません。
ユーザーが明示的にこの機能を有効にしなければなりません。

関連情報