WeakRef
Baseline 广泛可用 *
WeakRef 对象允许您持有对另一个对象的弱引用,而不会阻止该对象被垃圾回收。
描述
WeakRef 对象包含一个对对象的弱引用,该对象被称为其目标或被引用对象。对对象的弱引用是一种不会阻止对象被垃圾回收器回收的引用。相比之下,普通(或强)引用会将对象保留在内存中。当一个对象不再有任何强引用指向它时,JavaScript 引擎的垃圾回收器可能会销毁该对象并回收其内存。如果发生这种情况,您将无法再从弱引用中获取该对象。
由于未注册的 Symbol 也可以被垃圾回收,因此它们也可以用作 WeakRef 对象的 [目标](#target_object)。然而,这种用例是有限的。
尽可能避免使用
正确使用 WeakRef 需要仔细考虑,最好能避免就避免。同样重要的是,要避免依赖规范未保证的任何特定行为。垃圾回收何时、如何发生以及是否发生取决于任何给定 JavaScript 引擎的实现。您在一个引擎中观察到的任何行为,在另一个引擎、同一引擎的另一个版本,甚至在同一引擎的同一版本中的一个略有不同的情况下,都可能有所不同。垃圾回收是一个棘手的问题,JavaScript 引擎的实现者们正在不断完善和改进他们的解决方案。
以下是引入 WeakRef 的提案中作者提出的一些具体要点:
垃圾回收器很复杂。如果应用程序或库依赖于 GC 以及时、可预测的方式清理 WeakRef 或调用最终项 [清理回调],它可能会感到失望:清理可能比预期发生得晚得多,甚至根本不发生。导致不确定性的因素包括:
- 一个对象可能比另一个对象更早被垃圾回收,即使它们同时变得不可达,例如,由于分代收集。
- 可以使用增量和并发技术将垃圾回收工作分解到一段时间内。
- 可以使用各种运行时启发式方法来平衡内存使用和响应能力。
- JavaScript 引擎可能持有对看起来是不可达内容的引用(例如,在闭包或内联缓存中)。
- 不同的 JavaScript 引擎可能以不同的方式处理这些问题,或者同一引擎可能在其版本之间更改其算法。
- 复杂因素可能导致对象被意外地长时间保持活动状态,例如与某些 API 一起使用。
关于 WeakRef 的注意事项
- 如果您的代码刚刚为目标对象创建了一个
WeakRef,或者通过WeakRef的deref方法获取了一个目标对象,那么该目标对象将不会被回收,直到当前 JavaScript 任务(包括在脚本任务结束时运行的任何 Promise 反应任务)结束。也就是说,您只能在事件循环的轮次之间“看到”对象被回收。这主要是为了避免让任何给定 JavaScript 引擎的垃圾回收器行为在代码中变得明显——因为如果它变得明显,人们就会编写依赖于该行为的代码,而当垃圾回收器的行为发生变化时,这些代码就会中断。(垃圾回收是一个棘手的问题;JavaScript 引擎的实现者们正在不断完善和改进其工作方式。) - 如果多个
WeakRefs 指向同一个目标,它们之间是保持一致的。在一个任务中,调用其中一个的deref所得到的结果将与调用另一个的deref所得到的结果匹配,您不会从一个中得到目标对象,而从另一个中得到undefined。 - 如果
WeakRef的目标也位于一个FinalizationRegistry中,那么WeakRef的目标会在任何与注册表相关的清理回调被调用时或之前被清除;如果您的清理回调调用了目标对象的WeakRef的deref,它将收到undefined。 - 您无法更改
WeakRef的目标,它始终只会是原始目标对象,或者在目标对象被回收后为undefined。 - 即使没有任何强引用指向目标对象,
WeakRef对deref的调用也可能永远不会返回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 元素中显示的计数器,当元素不再存在时停止。
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 |
浏览器兼容性
加载中…