是否可以在javascript中创建“弱引用”?


97

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


4
正在为ES6讨论弱引用。睁大眼睛。
瑞安·史密斯

2
*官方规范Wiki /讨论在wiki.ecmascript.org/doku.php?id=strawman:weak_refs上,当前“最后修改时间:2013/02/02 22:25” *其他规范讨论在esdiscuss.org/topic/what是弱引用的状态,当前最新发布时间为“ 2013年3月3日星期日PST 2013”
Destiny Architect

在大多数情况下,WR试图解决“ 监听器不足”问题,在此处进行了讨论:[ stackoverflow.com/questions/43758217/…。如果该问题的答案很好,我认为WR的需求将不大。
詹姆斯,

@supercat我已经发布了已解决的听众问题答案
詹姆斯

Answers:


39

JavaScript不支持弱引用。您可以使用手动参考计数来滚动自己的页面,但并不是特别顺畅。您无法创建代理包装器对象,因为在JavaScript对象中,它们永远不知道何时将被垃圾回收。

因此,您的“弱引用”在使用add-reference和remove-reference方法的简单查找中就成为键(例如,整数),并且当不再有手动跟踪的引用时,可以删除条目,从而保留将来的查找该键返回null。

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


2
我没有仔细检查(或使用)代码,但是es-lab有一个提供基本WeakMap仿真的脚本。Aurora 6(Mozilla)具有非标准的WeakMap实现
theazureshadow 2011年

2
使用ES6,此答案不再正确。请参阅下面的答案stackoverflow.com/a/28567560/745190
thelastshadow

9
这仍然是正确的,因为ES6 WeakMap不是真正的弱引用。WeakMap仅将对象作为键接受,并且对这些对象的引用被弱保留。见stackoverflow.com/questions/32397729/...
CodeManX

我编写了一个模拟弱地图的类并将其张贴在这里:stackoverflow.com/a/47017206/491553
Ryan Shillington


11

更新:2019年9月

目前尚不能使用弱引用,但很可能很快就可以使用,因为JavaScript中的WeakRefs正在开发中。详细信息如下。

提案

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

WeakRef提案涵盖的功能两大新作品:

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

用例

一个主要用途为弱引用是实现高速缓存或映射举办大型的物体,在它的希望,因为它出现在高速缓存或映射一个大对象没有保持活着只。

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

资料来源和进一步阅读

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


1
Firefox Nightly已添加对WeakRef的实验性支持。这是使用它创建WeakSet的可迭代版本的示例实现:gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley

3

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

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

当您需要一个对象时,您可以向缓存查询。如果缓存中有对象,则将其返回。如果不存在,则将生成,存储并返回该项目。

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

删除算法很关键,因为如果弄错了,那么最终可能会删除最受欢迎的商品。这将导致糟糕的性能。

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


25
您所说的大部分内容是否与弱引用无关?
埃里克·卡普伦

22
@ JL235-弱引用的重要用途不是高速缓存,而是事件处理程序。我有一个对象,尽管它存在,但应该观察到其他事件-但我不希望它在通知列表中构成用于GC的引用。
马尔沃里奥

7
弱引用与缓存无关。弱引用意味着您想跟踪某些内容,但是如果没有剩余的被跟踪对象的引用,则允许将其删除。
fabspro

8
显然有一个使用弱引用来自动过期的缓存构建用例。
Phil Freeman

5
传统上,缓存是引用弱的主要原因。事件处理程序DOM只是一些IE Explorer越野车。
axkibe


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

作为引用的持有人,您不应对其何时引用值进行任何假设,使用缓存也没有什么不同



-4

EcmaScript 6(ES和声)具有WeakMap对象。现代浏览器对浏览器的支持非常好(Firefox的最后3个版本,Chrome和即将发布的IE版本都支持它)。


29
这不完全一样。A WeakMap不会对对象提供弱引用- 在WeakMap中,弱引用不是,而是keys。映射中存在弱引用的事实仅仅是防止内存泄漏的机制,否则用户将无法观察到。
EyasSH 2015年

1
您是正确的,而不是值是键,这是正确的。但是使用弱引用的整个目的是允许对引用对象进行垃圾回收。OP发布了两个链接,其中第二个链接是向无法扩展的对象添加ID,实际上,它建议使用WeakHashMap,Java与JavaScript的WeakMap等效。
thelastshadow 2015年

12
使用WeakMap实施弱参考weakmap.get(new String('any possible key that has ever existed or ever will exist'))会带来好运,因为永远undefined没有用 不赞成投票!
user3338098 2016年

-5

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

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

退出执行上下文后通常就是这种情况。作用域链结构,激活/变量对象以及在执行上下文中创建的任何对象(包括函数对象)将不再可访问,因此将可用于垃圾回收。

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


10
避免引用循环不是使用弱引用的唯一原因。它们非常适合对象实例池/缓存等。
蓬松的

WeakReference的定义不是问题。也同意上面的评论。
尤里·亚里舍夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.