在JavaScript中有没有创建对另一个对象的“弱引用”的方法? 这里是描述“弱引用”的维基页面。 这是另一篇介绍Java中“弱引用”的文章。 有人能想到在JavaScript中实现这种行为的方法吗?
在JavaScript中有没有创建对另一个对象的“弱引用”的方法? 这里是描述“弱引用”的维基页面。 这是另一篇介绍Java中“弱引用”的文章。 有人能想到在JavaScript中实现这种行为的方法吗?
更新:自2020年7月起,一些实现(Chrome、Edge、Firefox和Node.js)已经支持WeakRef
s,这是在2020年12月16日的“Stage 3 Draft”中定义的WeakRefs proposal。
JavaScript没有对弱引用提供语言支持。您可以使用手动引用计数来自己编写,但这并不是特别顺畅。您无法创建代理包装对象,因为在JavaScript中,对象永远不知道它们即将被垃圾回收。
因此,您的“弱引用”成为简单查找中的键(例如整数),具有添加引用和删除引用方法,当没有手动跟踪的引用时,条目可以被删除,从而使将来在该键上的查找返回null。
这不是真正的弱引用,但它可以解决一些相同的问题。它通常在复杂的Web应用程序中使用,以防止浏览器(通常是IE,特别是旧版本)中存在DOM节点或事件处理程序与与其关联的对象(如闭包)之间的引用循环时发生内存泄漏。在这些情况下,甚至可能不需要完整的引用计数方案。
目前还不能使用弱引用,但很可能很快就可以了,因为JavaScript中的弱引用正在进行中。详情见下文。
该提议现在处于第3阶段,这意味着它具有完整的规范,并且进一步的改进需要来自实现和用户的反馈。
WeakRef 提议包含两个主要的新功能:
弱引用的主要用途是实现保持大对象不占用内存的缓存或映射,当大对象仅出现在缓存或映射中时,不希望其占用内存。
终结处理是执行代码以清理程序不能访问的对象。用户定义的终结处理程序可以启用多种新用途,并在管理垃圾收集器不知道的资源时有助于防止内存泄漏。
https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references
2021 更新
WeakRef
现在已经在 Chrome、Edge 和 Firefox 中实现。仍在等待 Safari 和其他一些不支持的浏览器。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
2021年5月更新 现在可以在Safari和其他主要浏览器上使用。请参见上文。
真正的弱引用,目前还没有(但浏览器制造商正在研究此问题)。但是有一个想法可以模拟弱引用。
您可以构建一个缓存,通过它来驱动您的对象。当存储对象时,缓存会预测对象将占用多少内存。对于某些项目,例如存储图像,这很容易计算。对于其他项目,这可能更加困难。
当您需要一个对象时,然后向缓存请求它。如果缓存具有该对象,则返回该对象。如果不存在,则生成该项,存储并返回它。
当总预测内存达到一定水平时,缓存通过删除项目来模拟弱引用。它将根据检索频率和取出时间的权重预测最不常用的项。如果将创建该项的代码作为闭包传递给缓存,则还可以添加“计算”成本。这将允许缓存保留非常昂贵的构建或生成项目。
删除算法非常关键,因为如果做错了,就可能会删除最受欢迎的项目。这将导致可怕的性能问题。
只要缓存是存储对象的唯一对象,即具有永久引用,那么上述系统作为真正弱引用的替代方案应该可以很好地工作。
this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not
如果使用缓存,您会观察到:
this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts
提案和一些细节 https://github.com/tc39/proposal-weakrefs
Typescript 复制/粘贴版本
export class IterableWeakMap<T extends Object, V> {
weakMap = new WeakMap();
refSet = new Set<WeakRef<T>>();
finalizationGroup = new FinalizationRegistry(IterableWeakMap.cleanup);
static cleanup({ set, ref }: { set: Set<WeakRef<Object>>; ref: WeakRef<Object> }) {
set.delete(ref);
}
constructor(iterable?: Iterable<[T, V]>) {
if (!iterable) return;
for (const [key, value] of iterable) {
this.set(key, value);
}
}
set(key: T, value: V) {
const ref = new WeakRef<T>(key);
this.weakMap.set(key, { value, ref });
this.refSet.add(ref);
this.finalizationGroup.register(key, { set: this.refSet, ref }, ref);
}
get(key: T) {
const entry = this.weakMap.get(key);
return entry && entry.value;
}
delete(key: T) {
const entry = this.weakMap.get(key);
if (!entry) {
return false;
}
this.weakMap.delete(key);
this.refSet.delete(entry.ref);
this.finalizationGroup.unregister(entry.ref);
return true;
}
*[Symbol.iterator]() {
for (const ref of this.refSet) {
const key = ref.deref();
if (!key) continue;
const { value } = this.weakMap.get(key);
yield [key, value];
}
}
entries() {
return this[Symbol.iterator]();
}
*keys() {
for (const [key] of this) {
yield key;
}
}
*values() {
for (const [, value] of this) {
yield value;
}
}
}
WeakMap
不会提供对象的弱引用——在 WeakMap
中,弱引用是针对 键 而非 值 的。弱引用存在于该映射中只是为了防止内存泄漏,否则用户无法观察到它们。请注意,不要改变原文的意思。 - EyasSHweakmap.get(new String('任何可能已经存在或将来会存在的键'))
将始终为undefined
。这是不有用的。 下投票! - user3338098