如何获取javascript对象引用或引用计数?

时间:2010-05-30 00:45:49

标签: javascript garbage-collection reference

如何获取对象的引用计数

  • 是否可以确定javascript对象是否具有多个引用
  • 或者除了我用访问它之外还有引用
  • 甚至只是为了获得引用次数本身?
  • 我可以从javascript本身找到这些信息,还是需要跟踪自己的参考计数器。

显然,我的代码访问对象时必须至少有一个引用。但我想知道的是,是否有任何其他引用,或者我的代码是唯一访问它的地方。如果没有其他内容引用它,我希望能够删除该对象。

如果您知道答案,则无需阅读本问题的其余部分。以下只是一个让事情更加清晰的示例。


用例

在我的应用程序中,我有一个名为Repository的{​​{1}}对象实例,其中包含一系列 ALL 我的联系人。还有多个contacts对象实例,例如Collection集合和friends集合。每个集合都包含一个数组,其中包含coworkers contacts中的一组不同项。

示例代码

为了使这个概念更具体,请考虑下面的代码。 Repository对象的每个实例都包含特定类型的所有项的列表。您可能拥有联系人的存储库以及事件的单独存储库。为了简单起见,您可以获取,添加和删除项目,并通过构造函数添加许多项目。

Repository

请注意var Repository = function(items) { this.items = items || []; } Repository.prototype.get = function(id) { for (var i=0,len=this.items.length; i<len; i++) { if (items[i].id === id) { return this.items[i]; } } } Repository.prototype.add = function(item) { if (toString.call(item) === "[object Array]") { this.items.concat(item); } else { this.items.push(item); } } Repository.prototype.remove = function(id) { for (var i=0,len=this.items.length; i<len; i++) { if (items[i].id === id) { this.removeIndex(i); } } } Repository.prototype.removeIndex = function(index) { if (items[index]) { if (/* items[i] has more than 1 reference to it */) { // Only remove item from repository if nothing else references it this.items.splice(index,1); return; } } } 中带注释的行。如果没有其他对象具有对该项的引用,我只想从我的主对象库中删除该项。这是remove

Collection

然后此代码使用var Collection = function(repo,items) { this.repo = repo; this.items = items || []; } Collection.prototype.remove = function(id) { for (var i=0,len=this.items.length; i<len; i++) { if (items[i].id === id) { // Remove object from this collection this.items.splice(i,1); // Tell repo to remove it (only if no other references to it) repo.removeIndxe(i); return; } } } Repository

Collection

请注意var contactRepo = new Repository([ {id: 1, name: "Joe"}, {id: 2, name: "Jane"}, {id: 3, name: "Tom"}, {id: 4, name: "Jack"}, {id: 5, name: "Sue"} ]); var friends = new Collection( contactRepo, [ contactRepo.get(2), contactRepo.get(4) ] ); var coworkers = new Collection( contactRepo, [ contactRepo.get(1), contactRepo.get(2), contactRepo.get(5) ] ); contactRepo.items; // contains item ids 1, 2, 3, 4, 5 friends.items; // contains item ids 2, 4 coworkers.items; // contains item ids 1, 2, 5 coworkers.remove(2); contactRepo.items; // contains item ids 1, 2, 3, 4, 5 friends.items; // contains item ids 2, 4 coworkers.items; // contains item ids 1, 5 friends.remove(4); contactRepo.items; // contains item ids 1, 2, 3, 5 friends.items; // contains item ids 2 coworkers.items; // contains item ids 1, 5 如何从contactRepo中删除id 2?这是因为它仍然是coworkers.remove(2)引用的。但是,friends.items导致id {4}从friends.remove(4)中删除,因为没有其他集合引用它。

摘要

以上是我想要做的。我确信通过跟踪我自己的参考计数器等,我可以做到这一点。但如果有办法使用javascript的内置参考管理,我想听听如何使用它。

2 个答案:

答案 0 :(得分:16)

不,不,不,不;是的,如果你真的需要计算参考,你必须手动完成。 JS没有与此,GC或弱引用的接口。

虽然可以实现手动引用计数对象列表,但是所有额外开销(性能方面,但更重要的是代码复杂性)是否值得,这是值得怀疑的。

在您的示例代码中,忘记Repository似乎更简单,对您的列表使用普通Array,并让标准垃圾收集处理丢弃未使用的人员。如果您需要获取所有正在使用的人员的列表,您只需concat friendscoworkers列表(如果需要,可以对其进行排序/统一)。

答案 1 :(得分:1)

您可能会关注reduce函数和array.map函数。 map可用于帮助识别集合的交叉位置,或者是否存在交集。用户定义的reduce函数可以像合并一样使用(有点像覆盖加法运算符,以便您可以对对象应用操作,或者合并所有集合&#34; id&#34;如果这是您定义reduce函数的方式 - 然后将结果分配给主引用数组,我建议保留一个包含所有根对象/值的影子数组,以防你想要REWIND或其他东西)。注意:在减少对象或数组时,必须注意原型链。在这种情况下,map函数将非常有用。

我建议删除存储库中的对象或记录,因为您可能希望稍后再次引用它。我的方法是创建一个ShadowRepository,它将反映所有至少有一个&#34; Reference&#34;的记录/对象。根据您在此处提供的说明和代码,您似乎正在初始化所有数据并将参考存储在1,2,4,5中,如代码中所示。

var contactRepo = new Repository([
    {id: 1, name: "Joe"},
    {id: 2, name: "Jane"},
    {id: 3, name: "Tom"},
    {id: 4, name: "Jack"},
    {id: 5, name: "Sue"}
]);
var friends = new Collection(contactRepo,[
    contactRepo.get(2),
    contactRepo.get(4)
]);

var coworkers = new Collection(contactRepo,[
    contactRepo.get(1),
    contactRepo.get(2),
    contactRepo.get(5)
]);

从存储库和集合的初始化开始,您要问的是什么&#34;如果没有对它的引用,则从存储库中删除项目&#34;第3项需要立即删除。但是,您可以通过几种不同的方式跟踪参考。

我考虑过使用Object.observe来处理类似情况。但是,Object.observe不适用于所有浏览器。 I have recently turned to WatchJS

我正在努力理解Watch.JS背后的代码,允许动态创建对象上的观察者列表,这样就可以删除不再被监视的项目,但我建议删除引用访问点 - 我的意思是一个变量,它与一个对象提供直接的词法范围,该对象给它一个单一的引用点可以删除它的兄弟,使它不再可以在暴露的对象之外访问它的兄弟姐妹的记录/项目/财产/对象。引用所有其他引用依赖于对基础数据的已删除访问权限的引用已停止。我正在为原始引用生成唯一ID,以避免意外重用相同的ID。

感谢您分享您的问题和您正在使用的结构,它帮助我考虑了我自己的特定情况之一,我生成了唯一标识的词汇兄弟的引用这些独特的ID保存在具有范围的ONE对象上在阅读完之后,我已经重新考虑并决定只公开一个引用,然后将引用分配给需要的变量名称,例如创建观察者或观察者或其他集合。