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

Tau*_*ren 54 javascript garbage-collection reference

如何获取对象的引用计数

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

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

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


用例

在我的应用程序中,我有一个Repository名为的对象实例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;
    }
  }
}  
Run Code Online (Sandbox Code Playgroud)

请注意注释中的行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;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

然后此代码使用RepositoryCollection:

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
Run Code Online (Sandbox Code Playgroud)

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

摘要

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

bob*_*nce 16

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

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

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

  • 感谢您的反馈意见.我担心没有原生的javascript方式来做到这一点.我意识到这可能看起来像是一个过多的膨胀,但我正在使用一个非常大的应用程序,这是一个过于简化的例子.在appl中,跟踪所有不同的"朋友","同事"和其他相关阵列几乎是不可能的.此外,还有许多不同类型的对象,而不仅仅是联系人.因此,为每种类型设置存储库实际上会使事情变得更简单.这都与数据绑定解决方案有关,该解决方案在模型发生变化时触发事件. (3认同)