Подтвердить что ты не робот

Как получить ссылки на объекты javascript или количество ссылок?

Как получить счетчик ссылок для объекта

  • Можно ли определить, имеет ли объект 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;
    }
  }
}  

Обратите внимание на строку в 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) не удалил id 2 из contactRepo? Это связано с тем, что он по-прежнему ссылается на friends.items. Тем не менее, friends.remove(4) вызывает удаление id 4 из contactRepo, потому что никакой другой коллекции не ссылается на него.

Резюме

Выше было то, что я хочу сделать. Я уверен, что есть способы сделать это, отслеживая мои собственные счетчики ссылок и т.д. Но если есть способ сделать это с помощью встроенного управления ссылками javascript, я бы хотел узнать, как его использовать.

4b9b3361

Ответ 1

Нет, нет, нет, нет; и да, если вам действительно нужно подсчитать ссылки, вам придется делать это вручную. JS не имеет интерфейса с этим, GC или слабыми ссылками.

В то время как вы можете реализовать список объектов с подсчетом ссылок вручную, сомнительно, стоит ли все дополнительные накладные расходы (в плане производительности, но, что более важно, сложность кода).

В вашем примере кода было бы проще забыть Repository, используйте простой Array для ваших списков и пусть стандартная сборка мусора позаботится о том, чтобы удалить неиспользуемых людей. Если вам нужен список всех пользователей, вы просто concat списки friends и coworkers (и отсортируйте/определите их, если вам нужно).

Ответ 2

Вам может потребоваться изучить функции сокращения и функции array.map. карта может использоваться, чтобы помочь определить, где пересекаются ваши коллекции, или если есть пересечение вообще. Пользовательская функция сокращения может использоваться как слияние (вроде переопределения оператора сложения, чтобы вы могли применить операцию к объектам или объединить все коллекции в "id", если это то, как вы определяете функцию сокращения), затем присвойте результат ваш основной массив ссылок, я рекомендую хранить теневой массив, который содержит все корневые объекты/значения в случае, если вы хотите REWIND или что-то еще). Примечание. При уменьшении объекта или массива нужно быть осторожным с цепями прототипов. В этом случае функция отображения будет очень полезна.

Я бы предложил не удалить объект или запись, находящуюся в вашем репозитории, так как вы можете захотеть ссылаться на него позже. Мой подход состоял бы в создании 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, чтобы позволить динамически создавать список наблюдателей на объекте, что позволит удалить элемент, который больше не просматривается, хотя я предлагаю удалить ссылку в точка доступа. То, что я имею в виду, - это переменная, которая разделяет непосредственную лексическую область с объектом, который предоставил единственную ссылку на него, может быть удален, что делает его более недоступным вне объекта, который выставил запись/элемент/property/object of this sibling. С ссылкой на то, что все ваши другие ссылки зависят от удаленного доступа к базовым данным, останавливается. Я генерирую уникальный идентификатор исходных ссылок, чтобы избежать случайного повторного использования одного и того же.

Благодарим вас за то, что вы делитесь своим вопросом и структурой, которую используете, это помогло мне рассмотреть один из моих конкретных случаев, когда я создавал уникально идентифицированные ссылки на лексический брат, эти уникальные идентификаторы хранились на объекте ONE, который имел область, После прочтения здесь я передумал и решил разоблачить только одну ссылку, а затем назначить эту ссылку на имя переменной, где она когда-либо понадобится, например, при создании наблюдателя или наблюдателя или другой коллекции.