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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2937120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:34:45  来源:igfitidea点击:

How to get javascript object references or reference count?

javascriptgarbage-collectionreference

提问by Tauren

How to get reference count for an object

如何获取对象的引用计数

  • Is it possible to determine if a javascript object has multiple referencesto it?
  • Or if it has references besides the one I'm accessing it with?
  • Or even just to get the reference countitself?
  • Can I find this information from javascript itself, or will I need to keep track of my own reference counters.
  • 是否可以确定一个 javascript 对象是否有多个引用
  • 或者,如果它除了我正在访问的引用之外还有其他引用?
  • 或者甚至只是为了获得引用计数本身?
  • 我可以从 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 Repositoryobject instance called contactsthat contains an array of ALLmy contacts. There are also multiple Collectionobject instances, such as friendscollection and a coworkerscollection. Each collection contains an array with a different set of items from the contactsRepository.

在我的应用程序中,我有一个Repository名为的对象实例contacts,其中包含我所有联系人的数组。还有多个Collection对象实例,例如 friends集合和coworkers集合。每个集合都包含一个数组,其中包含来自contactsRepository.

Sample Code

示例代码

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

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

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 removewith 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:

请注意注释中的行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;
    }
  }
}

And then this code uses Repositoryand Collection:

然后这段代码使用RepositoryCollection

var contactRepo = new Repository([
    {id: 1, name: "Joe"},
    {id: 2, name: "Jane"},
    {id: 3, name: "Tom"},
    {id: 4, name: "Hyman"},
    {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.

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

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 的内置引用管理来做到这一点,我想听听如何使用它。

采纳答案by bobince

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 没有与 this、GC 或弱引用的接口。

Whilst you couldimplement 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 Arrayfor 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 concatthe friendsand coworkerslists (and sort/uniquify them if you needed to).

在您的示例代码中,忘记RepositoryArray为您的列表使用普通代码似乎更简单,并让标准垃圾收集处理丢弃未使用的人。如果你需要得到使用的所有的人的名单,你只是concatfriendscoworkers列表(和排序/ uniquify他们,如果你需要的)。

回答by alignedfibers

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 函数和 array.map 函数。地图可用于帮助确定您的集合在哪里相交,或者是否有相交。用户定义的reduce函数可以像合并一样使用(有点像覆盖加法运算符,以便您可以将操作应用于对象,或者合并“id”上的所有集合,如果这是您定义reduce函数的方式 - 然后将结果分配给您的主参考数组,我建议保留一个包含所有根对象/值的阴影数组,以防您想要倒带或其他东西)。注意:在减少对象或数组时必须小心原型链。在这种情况下,地图功能将非常有用。

I would suggest notto 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.

我建议不要删除存储库中的对象或记录,因为您可能想稍后再次引用它。我的方法是创建一个 ShadowRepository 来反映至少有一个“参考”的所有记录/对象。从此处提供的描述和代码看来,您正在初始化所有数据并存储对代码中显示的 1,2,4,5 的引用。

var contactRepo = new Repository([
    {id: 1, name: "Joe"},
    {id: 2, name: "Jane"},
    {id: 3, name: "Tom"},
    {id: 4, name: "Hyman"},
    {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.observe。但是,Object.observe 并不适用于所有浏览器。我最近转向 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 背后的代码,以允许动态创建对象上的观察者列表,这将允许一个人也删除不再被监视的项目,尽管我建议删除引用点访问 - 我的意思是一个变量与一个对象共享直接的词法范围,该对象提供了一个指向它的兄弟的单点引用可以被删除,使其不再能够在暴露记录/项目/属性的对象之外访问它的兄弟对象。随着所有其他引用依赖于对基础数据的删除访问的引用被停止。我正在为原始引用生成唯一 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 保存在具有作用域的 ONE 对象上,阅读后在这里,我重新考虑并决定只公开一个引用,然后将该引用分配给需要它的变量名称,例如在创建观察者或观察者或其他集合时。