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

时间:2022-02-04 16:54:18

How to get reference count for an object

  • Is it possible to determine if a javascript object has multiple references to it?
  • 是否可以确定一个javascript对象是否有多个引用?
  • Or if it has references besides the one I'm accessing it with?
  • 或者如果它除了我正在访问的那个以外还有引用?
  • Or even just to get the reference count itself?
  • 或者仅仅是为了获取引用计数本身?
  • Can I find this information from javascript itself, or will I need to keep track of my own reference counters.
  • 我是否可以从javascript本身找到这些信息,或者我是否需要跟踪我自己的引用计数器。

Obviously, there must be at least one reference to it for my code access the object. But what I want to know is if there are any other references to it, or if my code is the only place it is accessed. I'd like to be able to delete the object if nothing else is referencing it.

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

If you know the answer, there is no need to read the rest of this question. Below is just an example to make things more clear.

如果你知道答案,就没有必要去读这个问题的其余部分。下面只是一个让事情更清楚的例子。


Use Case

In my application, I have a Repository object instance called contacts that contains an array of ALL my contacts. There are also multiple Collection object instances, such as friends collection and a coworkers collection. Each collection contains an array with a different set of items from the contacts Repository.

在我的应用程序中,我有一个名为contacts的存储库对象实例,它包含我所有联系人的数组。还有多个集合对象实例,如friends集合和一个mates集合。每个集合包含一个数组,其中包含来自contacts存储库的一组不同的项。

Sample Code

To make this concept more concrete, consider the code below. Each instance of the Repository object contains a list of all items of a particular type. You might have a repository of Contacts and a separate repository of Events. To keep it simple, you can just get, add, and remove items, and add many via the constructor.

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

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;
    }
  }
}  

Note the line in remove with the comment. I only want to remove the item from my master repository of objects if no other objects have a reference to the item. Here's 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;
    }
  }
}

And then this code uses Repository and 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

Notice how coworkers.remove(2) didn't remove id 2 from contactRepo? This is because it was still referenced from friends.items. However, friends.remove(4) causes id 4 to be removed from contactRepo, because no other collection is referring to it.

注意同事们是如何操作的。删除(2)没有从contactRepo删除id 2 ?这是因为它仍然是从friends.items中引用的。但是,删除(4)会导致从contactRepo中删除id 4,因为没有其他集合引用它。

Summary

The above is what I want to do. I'm sure there are ways I can do this by keeping track of my own reference counters and such. But if there is a way to do it using javascript's built-in reference management, I'd like to hear about how to use it.

以上就是我想做的。我确信有一些方法可以通过跟踪我自己的引用计数器来实现这一点。但是如果有一种方法可以使用javascript的内置引用管理来实现它,我很想知道如何使用它。

2 个解决方案

#1


15  

No, no, no, no; and yes, if you really need to count references you will have to do it manually. JS has no interface to this, GC, or weak references.

不,不,不,不,是的,如果你真的需要计算引用数,你就必须手动去做。JS没有这个、GC或弱引用的接口。

Whilst you could implement a manual reference-counted object list, it's questionable whether all the extra overhead (in performance terms but more importantly code complexity) is worth it.

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

In your example code it would seem simpler to forget the Repository, use a plain Array for your lists, and let standard garbage collection take care of dropping unused people. If you needed to get a list of all people in use, you'd just concat the friends and coworkers lists (and sort/uniquify them if you needed to).

在示例代码中,忘记存储库、为列表使用普通数组并让标准的垃圾收集处理未使用的人员。如果你需要列出所有使用过的人的名单,你只需要询问朋友和同事的名单(如果你需要的话,可以对他们进行分类或统一)。

#2


1  

You may interest to look into reduce functions, and array.map functions. map could be used to help identify where your collections intersect, or if there is an intersection at all. A user defined reduce function could be used like a merge (kinda like overriding the addition operator so that you can apply operation to objects, or merge all collections on "id" if that is how you define your reduce function - then assign the result to your master reference array, I recommend keeping a shadow array that holds all of the root object/values in case you would like to REWIND or something). Note: one must be careful of prototype chains when reducing an object or array. The map function will be very helpful in this case.

您可能对reduce函数和数组感兴趣。地图功能。地图可以用来帮助确定你的收藏品在哪里相交,或者是否有一个十字路口。reduce函数定义的用户可以使用像合并(有点像压倒一切的加法操作符,这样您就可以申请操作对象,或合并所有集合在“id”如果你如何定义你的reduce函数,然后将结果分配给你的主人引用数组,我建议保持一个影子数组保存所有的根对象/值如果你想倒带之类的)。注意:在减少对象或数组时,必须小心原型链。map函数在这种情况下非常有用。

I would suggest not to remove the object or record that is in your Repository as you may want to reference it again later. My approach would be to create a ShadowRepository that would reflect all records/objects that have at least one "Reference". From your description and code presented here it appears you are initializing all of the data and storing reference to 1,2,4,5 as appears in your code.

我建议不要删除存储库中的对象或记录,因为您可能希望稍后再次引用它。我的方法是创建一个影子存储库,它将反映至少有一个“引用”的所有记录/对象。从这里提供的描述和代码可以看出,您正在初始化所有的数据,并存储对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)
]);

From the initialization of the Repository and the collections, what you are asking "Remove item from repository if there are no references to it" item 3 would need to be removed immediatly. You can however track the references in a few different ways.

在初始化存储库和集合时,需要立即删除“如果没有对它的引用,请从存储库中删除项”项3。但是,您可以用几种不同的方式跟踪引用。

I have considered using Object.observe for a similar situation. However, Object.observe does not work in all browsers. I have recently turned to WatchJS

我考虑过使用Object。观察类似的情况。然而,对象。观察不能在所有浏览器中工作。我最近求助于WatchJS

I am working on understanding the code behind Watch.JS to allow a list of observers on an object to be created dynamically this would allow one to also remove an item that is no longer watched, though I suggest to remove the reference at the point of access - What I mean is a variable that shares the immediate lexical scope with an object that has given a single point of reference to it's sibling can be removed making it no longer accessable outside of the object that had exposed the record/item/property/object of it's sibling. With the reference that all of your other references depended on removed access to the underlying data is stopped. I am generating unique id for origin references to avoid accidentally reusing the same one.

我正在努力理解Watch背后的代码。JS允许观察者对象的列表创建动态这将允许一个还删除一个条目,不再看了,不过我建议删除访问的参考点——我的意思是一个变量,股价立即词法作用域的对象赋予一个单点的引用它的兄弟姐妹可以删除不再accessable之外的对象,暴露了记录/物品/属性/对象的兄弟姐妹。通过引用,您的所有其他引用都依赖于对底层数据的删除访问被停止。我正在为源引用生成唯一的id,以避免意外地重用同一个id。

Thank you for sharing your question and the structure you are using, it has helped me consider one of my own specific cases where I was generating uniquely identified references to a lexical sibling these unique ids were kept on the ONE object that had scope, After reading here I have reconsidered and decided to expose only one reference then assign that reference to a variable name where ever it is needed such as in creating a watcher or observer or other Collection.

谢谢你分享你的问题和你使用的结构,它帮助了我考虑自己的具体情况我是生成唯一标识引用词法兄弟这些独特的id被保存在一个对象的范围,在阅读这里有重新考虑然后决定只暴露一个引用引用分配给一个变量名称等是否需要在创建一个观察者或观察者或其他集合。

#1


15  

No, no, no, no; and yes, if you really need to count references you will have to do it manually. JS has no interface to this, GC, or weak references.

不,不,不,不,是的,如果你真的需要计算引用数,你就必须手动去做。JS没有这个、GC或弱引用的接口。

Whilst you could implement a manual reference-counted object list, it's questionable whether all the extra overhead (in performance terms but more importantly code complexity) is worth it.

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

In your example code it would seem simpler to forget the Repository, use a plain Array for your lists, and let standard garbage collection take care of dropping unused people. If you needed to get a list of all people in use, you'd just concat the friends and coworkers lists (and sort/uniquify them if you needed to).

在示例代码中,忘记存储库、为列表使用普通数组并让标准的垃圾收集处理未使用的人员。如果你需要列出所有使用过的人的名单,你只需要询问朋友和同事的名单(如果你需要的话,可以对他们进行分类或统一)。

#2


1  

You may interest to look into reduce functions, and array.map functions. map could be used to help identify where your collections intersect, or if there is an intersection at all. A user defined reduce function could be used like a merge (kinda like overriding the addition operator so that you can apply operation to objects, or merge all collections on "id" if that is how you define your reduce function - then assign the result to your master reference array, I recommend keeping a shadow array that holds all of the root object/values in case you would like to REWIND or something). Note: one must be careful of prototype chains when reducing an object or array. The map function will be very helpful in this case.

您可能对reduce函数和数组感兴趣。地图功能。地图可以用来帮助确定你的收藏品在哪里相交,或者是否有一个十字路口。reduce函数定义的用户可以使用像合并(有点像压倒一切的加法操作符,这样您就可以申请操作对象,或合并所有集合在“id”如果你如何定义你的reduce函数,然后将结果分配给你的主人引用数组,我建议保持一个影子数组保存所有的根对象/值如果你想倒带之类的)。注意:在减少对象或数组时,必须小心原型链。map函数在这种情况下非常有用。

I would suggest not to remove the object or record that is in your Repository as you may want to reference it again later. My approach would be to create a ShadowRepository that would reflect all records/objects that have at least one "Reference". From your description and code presented here it appears you are initializing all of the data and storing reference to 1,2,4,5 as appears in your code.

我建议不要删除存储库中的对象或记录,因为您可能希望稍后再次引用它。我的方法是创建一个影子存储库,它将反映至少有一个“引用”的所有记录/对象。从这里提供的描述和代码可以看出,您正在初始化所有的数据,并存储对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)
]);

From the initialization of the Repository and the collections, what you are asking "Remove item from repository if there are no references to it" item 3 would need to be removed immediatly. You can however track the references in a few different ways.

在初始化存储库和集合时,需要立即删除“如果没有对它的引用,请从存储库中删除项”项3。但是,您可以用几种不同的方式跟踪引用。

I have considered using Object.observe for a similar situation. However, Object.observe does not work in all browsers. I have recently turned to WatchJS

我考虑过使用Object。观察类似的情况。然而,对象。观察不能在所有浏览器中工作。我最近求助于WatchJS

I am working on understanding the code behind Watch.JS to allow a list of observers on an object to be created dynamically this would allow one to also remove an item that is no longer watched, though I suggest to remove the reference at the point of access - What I mean is a variable that shares the immediate lexical scope with an object that has given a single point of reference to it's sibling can be removed making it no longer accessable outside of the object that had exposed the record/item/property/object of it's sibling. With the reference that all of your other references depended on removed access to the underlying data is stopped. I am generating unique id for origin references to avoid accidentally reusing the same one.

我正在努力理解Watch背后的代码。JS允许观察者对象的列表创建动态这将允许一个还删除一个条目,不再看了,不过我建议删除访问的参考点——我的意思是一个变量,股价立即词法作用域的对象赋予一个单点的引用它的兄弟姐妹可以删除不再accessable之外的对象,暴露了记录/物品/属性/对象的兄弟姐妹。通过引用,您的所有其他引用都依赖于对底层数据的删除访问被停止。我正在为源引用生成唯一的id,以避免意外地重用同一个id。

Thank you for sharing your question and the structure you are using, it has helped me consider one of my own specific cases where I was generating uniquely identified references to a lexical sibling these unique ids were kept on the ONE object that had scope, After reading here I have reconsidered and decided to expose only one reference then assign that reference to a variable name where ever it is needed such as in creating a watcher or observer or other Collection.

谢谢你分享你的问题和你使用的结构,它帮助了我考虑自己的具体情况我是生成唯一标识引用词法兄弟这些独特的id被保存在一个对象的范围,在阅读这里有重新考虑然后决定只暴露一个引用引用分配给一个变量名称等是否需要在创建一个观察者或观察者或其他集合。