如何获得javascript对象引用或引用计数?
如何获得一个对象的引用计数
- 是否有可能确定一个JavaScript对象有多个引用 ?
- 或者,如果除了我正在访问的引用之外还有引用?
- 甚至只是为了得到引用计数本身?
- 我可以从javascript本身find这些信息,还是需要跟踪我自己的引用计数器。
显然,对于我的代码访问对象,必须至less有一个引用。 但是我想知道的是,如果有任何其他的引用,或者我的代码是唯一被访问的地方。 我希望能够删除对象,如果没有别的引用它。
如果你知道答案,就没有必要读这个问题的其余部分。 下面只是一个例子,使事情更清楚。
用例
在我的应用程序中,我有一个名为contacts
的Repository
对象实例,其中包含所有我的联系人数组。 还有多个Collection
对象实例,如friends
集合和coworkers
集合。 每个集合包含一个数组,其中包含来自contacts
Repository
一组不同的项目。
示例代码
为了使这个概念更具体,请考虑下面的代码。 Repository
对象的每个实例都包含特定types的所有项目的列表。 您可能有一个联系人存储库和一个单独的事件存储库。 为了简单起见,您可以获取,添加和删除项目,并通过构造函数添加许多项目。
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
请注意coworkers.remove(2)
如何将contact 2从contactRepo中删除? 这是因为它仍然参考friends.items
。 但是, friends.remove(4)
会导致id 4从contactRepo
被移除,因为没有其他的集合正在引用它。
概要
以上是我想要做的。 我敢肯定,我可以通过跟踪自己的参考指标等来做到这一点。 但是,如果有一种方法使用JavaScript的内置参考pipe理,我想知道如何使用它。
不不不不; 是的,如果你真的需要数引用,你将不得不手动。 JS没有这个接口,GC或弱引用。
虽然您可以实现一个手动引用计数的对象列表,但所有额外开销(在性能方面,但更重要的是代码复杂度)是否值得这个问题是值得怀疑的。
在您的示例代码中,忘记Repository
似乎更简单,为您的列表使用普通Array
,并让标准垃圾回收处理丢弃未使用的人员。 如果你需要列出所有正在使用的人,你只需要concat
friends
和coworkers
列表(如果需要,可以对它们进行sorting/分类)。
您可能有兴趣查看reduce函数和array.map函数。 地图可以用来帮助识别你的collections相交的地方,或者如果有交集。 用户定义的reduce函数可以像合并一样使用(有点像覆盖加法运算符,以便您可以将操作应用于对象,或者将所有集合合并到“id”上(如果您是如何定义reduce函数的话) – 然后将结果分配给你的主引用数组,我build议保留一个阴影数组,以保存所有的根对象/值,以防你想要REWIND或其他东西)。 注意:减less对象或数组时,必须小心原型链。 在这种情况下,map函数将非常有用。
我build议不要删除您的存储库中的对象或logging,因为您可能希望稍后再引用它。 我的方法是创build一个能够反映至less有一个“引用”的所有logging/对象的ShadowRepository。 从你在这里的描述和代码看来,你正在初始化所有的数据,并存储对代码中出现的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) ]);
从存储库和集合的初始化,你所要求的“如果没有对它的引用,从存储库中删除项目”,项目3将立即需要被删除。 但是,您可以通过几种不同的方式跟踪参考。
我曾考虑过使用Object.observe类似的情况。 但是,Object.observe在所有浏览器中都不起作用。 我最近转向WatchJS
我正在理解Watch.JS后面的代码,以允许dynamic创build一个对象的观察者列表,这将允许也删除一个不再被观察的项目,虽然我build议删除参考点访问 – 我的意思是一个variables,分享立即词汇范围与一个对象,已经给予了一个单一的参考,它的兄弟可以被删除,使其不再可访问的对象之外已经暴露了logging/项目/财产/它的兄弟姐妹的对象。 引用所有其他引用取决于对基础数据的移除访问都将停止。 我为原始引用生成唯一的ID,以避免意外重复使用同一个ID。
感谢您分享您的问题和您正在使用的结构,这帮助我考虑了自己的具体情况之一,我正在生成一个词汇兄弟姐妹的唯一标识的引用这些独特的ID保存在有对象的ONE对象,阅读在这里,我已经重新考虑并决定只公开一个引用,然后将该引用赋值给一个variables名称,比如在创build观察者或观察者或其他集合时。