103

JavaScript 中是否有任何方法可以创建对另一个对象的“弱引用”?这是描述什么是弱引用的 wiki 页面。 这是另一篇用 Java 描述它们的文章。谁能想到在 JavaScript 中实现这种行为的方法?

4

10 回答 10

42

更新:自 2020 年 7 月以来,一些实现(Chrome、Edge、Firefox 和 Node.js)已支持WeakRefs 提案WeakRef中定义的 s,该提案是截至 2020 年 12 月 16 日的“第 3 阶段草案”。

JavaScript 中没有对弱引用的语言支持。您可以使用手动引用计数自己滚动,但不是特别顺利。您不能创建代理包装对象,因为在 JavaScript 中,对象永远不知道它们何时将被垃圾收集。

因此,您的“弱引用”成为简单查找中的键(例如整数),具有添加引用和删除引用方法,并且当不再有手动跟踪的引用时,可以删除条目,留下未来的查找该键返回null。

这并不是真正的弱引用,但它可以解决一些相同的问题。当 DOM 节点或事件处理程序与与其关联的对象(例如闭包)之间存在引用循环时,通常在复杂的 Web 应用程序中执行此操作,以防止浏览器(通常是 IE,尤其是旧版本)发生内存泄漏。在这些情况下,甚至可能不需要完整的引用计数方案。

于 2008-11-05T21:59:43.163 回答
15

在 NodeJS 上运行 JS 时,可以考虑https://github.com/TooTallNate/node-weak

于 2012-08-11T02:02:58.847 回答
13

更新:2019 年 9 月

目前还不可能使用弱引用,但很可能很快就会有可能,因为JavaScript 中的WeakRefs正在进行中。详情如下。

提议

提案现在处于第 3 阶段,这意味着它具有完整的规范,并且进一步细化将需要实现和用户的反馈。

WeakRef提案包含两个主要的新功能:

  • 使用Wea​​kRef 类创建对对象的弱引用
  • 在对象被垃圾回收后运行用户定义的终结器,使用FinalizationGroup 类

用例

弱引用的主要用途是实现包含大对象的缓存或映射,其中不希望大对象仅仅因为它出现在缓存或映射中而保持活动状态。

终结是在程序执行无法访问的对象之后执行代码以进行清理。用户定义的终结器启用了几个新的用例,并且可以在管理垃圾收集器不知道的资源时帮助防止内存泄漏。

来源和进一步阅读

https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references

于 2019-09-19T10:43:18.447 回答
4

2021 更新

WeakRef现在已在 Chrome、Edge 和 Firefox 中实现。仍在等待 Safari 和其他一些坚持。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef

2021 年 5 月更新 它现在可以在 Safari 上使用,因此可以在所有主要浏览器上使用。往上看。

于 2021-01-03T16:38:26.980 回答
3

仅供参考;JavaScript 没有,但 ActionScript 3(也是 ECMAScript)有。查看Dictionary 的构造函数参数

于 2010-03-23T18:12:18.917 回答
3

他们终于来了。尚未在浏览器中实现,但很快就会实现。

https://v8.dev/features/weak-references

于 2019-07-10T08:30:54.477 回答
2

真正的弱引用,不,还没有(但浏览器制造商正在研究这个主题)。但这里有一个关于如何模拟弱引用的想法。

您可以构建一个缓存来驱动您的对象。存储对象时,缓存会预测该对象将占用多少内存。对于某些项目,例如存储图像,这很容易解决。对于其他人来说,这将更加困难。

当你需要一个对象时,你就向缓存请求它。如果缓存有对象,则返回。如果不存在,则生成、存储并返回项目。

当预测的内存总量达到一定水平时,通过缓存删除项来模拟弱引用。它将根据检索的频率预测哪些物品使用最少,并根据它们被取出的时间加权。如果创建项目的代码作为闭包传递到缓存中,则还可以添加“计算”成本。这将允许缓存保留构建或生成非常昂贵的项目。

删除算法是关键,因为如果你弄错了,那么你最终可能会删除最受欢迎的项目。这将导致糟糕的表现。

只要缓存是唯一对存储的对象具有永久引用的对象,那么上述系统应该可以很好地替代真正的弱引用。

于 2011-09-03T07:58:26.910 回答
2

正如上面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

作为引用的持有者,你不应该对它何时引用一个值做出任何假设,这与使用缓存没有什么不同

于 2017-02-08T17:16:36.693 回答
-5

EcmaScript 6 (ES Harmony) 有一个WeakMap对象。现代浏览器中的浏览器支持非常好(最近 3 个版本的 Firefox、chrome 甚至即将推出的 IE 版本都支持它)。

于 2015-02-17T17:37:17.310 回答
-6

http://www.jibbering.com/faq/faq_notes/closures.html

ECMAScript 使用自动垃圾回收。规范没有定义细节,将其留给实现者进行整理,并且已知一些实现对其垃圾收集操作给予非常低的优先级。但是一般的想法是,如果一个对象变得不可引用(通过没有剩余的对它的引用可供执行代码访问),它就可以用于垃圾收集,并且在将来的某个时候将被销毁,并且它正在消耗的任何资源都被释放并返回到系统重复使用。

退出执行上下文时通常会出现这种情况。作用域链结构、Activation/Variable 对象和在执行上下文中创建的任何对象(包括函数对象)将不再可访问,因此可用于垃圾回收。

这意味着没有弱者,只有那些不再可用的。

于 2008-11-05T21:28:26.953 回答