JavaScript 中是否有任何方法可以创建对另一个对象的“弱引用”?这是描述什么是弱引用的 wiki 页面。 这是另一篇用 Java 描述它们的文章。谁能想到在 JavaScript 中实现这种行为的方法?
10 回答
更新:自 2020 年 7 月以来,一些实现(Chrome、Edge、Firefox 和 Node.js)已支持WeakRefs 提案WeakRef
中定义的 s,该提案是截至 2020 年 12 月 16 日的“第 3 阶段草案”。
JavaScript 中没有对弱引用的语言支持。您可以使用手动引用计数自己滚动,但不是特别顺利。您不能创建代理包装对象,因为在 JavaScript 中,对象永远不知道它们何时将被垃圾收集。
因此,您的“弱引用”成为简单查找中的键(例如整数),具有添加引用和删除引用方法,并且当不再有手动跟踪的引用时,可以删除条目,留下未来的查找该键返回null。
这并不是真正的弱引用,但它可以解决一些相同的问题。当 DOM 节点或事件处理程序与与其关联的对象(例如闭包)之间存在引用循环时,通常在复杂的 Web 应用程序中执行此操作,以防止浏览器(通常是 IE,尤其是旧版本)发生内存泄漏。在这些情况下,甚至可能不需要完整的引用计数方案。
在 NodeJS 上运行 JS 时,可以考虑https://github.com/TooTallNate/node-weak。
更新:2019 年 9 月
目前还不可能使用弱引用,但很可能很快就会有可能,因为JavaScript 中的WeakRefs正在进行中。详情如下。
提议
提案现在处于第 3 阶段,这意味着它具有完整的规范,并且进一步细化将需要实现和用户的反馈。
WeakRef提案包含两个主要的新功能:
- 使用WeakRef 类创建对对象的弱引用
- 在对象被垃圾回收后运行用户定义的终结器,使用FinalizationGroup 类
用例
弱引用的主要用途是实现包含大对象的缓存或映射,其中不希望大对象仅仅因为它出现在缓存或映射中而保持活动状态。
终结是在程序执行无法访问的对象之后执行代码以进行清理。用户定义的终结器启用了几个新的用例,并且可以在管理垃圾收集器不知道的资源时帮助防止内存泄漏。
来源和进一步阅读
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 上使用,因此可以在所有主要浏览器上使用。往上看。
仅供参考;JavaScript 没有,但 ActionScript 3(也是 ECMAScript)有。查看Dictionary 的构造函数参数。
他们终于来了。尚未在浏览器中实现,但很快就会实现。
真正的弱引用,不,还没有(但浏览器制造商正在研究这个主题)。但这里有一个关于如何模拟弱引用的想法。
您可以构建一个缓存来驱动您的对象。存储对象时,缓存会预测该对象将占用多少内存。对于某些项目,例如存储图像,这很容易解决。对于其他人来说,这将更加困难。
当你需要一个对象时,你就向缓存请求它。如果缓存有对象,则返回。如果不存在,则生成、存储并返回项目。
当预测的内存总量达到一定水平时,通过缓存删除项来模拟弱引用。它将根据检索的频率预测哪些物品使用最少,并根据它们被取出的时间加权。如果创建项目的代码作为闭包传递到缓存中,则还可以添加“计算”成本。这将允许缓存保留构建或生成非常昂贵的项目。
删除算法是关键,因为如果你弄错了,那么你最终可能会删除最受欢迎的项目。这将导致糟糕的表现。
只要缓存是唯一对存储的对象具有永久引用的对象,那么上述系统应该可以很好地替代真正的弱引用。
正如上面JL235建议的那样,使用缓存机制来模拟弱引用是合理的。如果弱引用本来就存在,你会观察到这样的行为:
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
作为引用的持有者,你不应该对它何时引用一个值做出任何假设,这与使用缓存没有什么不同
http://www.jibbering.com/faq/faq_notes/closures.html
ECMAScript 使用自动垃圾回收。规范没有定义细节,将其留给实现者进行整理,并且已知一些实现对其垃圾收集操作给予非常低的优先级。但是一般的想法是,如果一个对象变得不可引用(通过没有剩余的对它的引用可供执行代码访问),它就可以用于垃圾收集,并且在将来的某个时候将被销毁,并且它正在消耗的任何资源都被释放并返回到系统重复使用。
退出执行上下文时通常会出现这种情况。作用域链结构、Activation/Variable 对象和在执行上下文中创建的任何对象(包括函数对象)将不再可访问,因此可用于垃圾回收。
这意味着没有弱者,只有那些不再可用的。