03. Weak Collections

Коллекции со слабыми ссылками (weak references) отличаются стратегией хранения объектов: если некий объект присутствует только в коллекции со слабыми ссылками, то сборщику мусора разрешается очищать из памяти данный объект. Ключами таких коллекций обязаны быть объекты, а значениями -- произвольные значения.

Классы WeakSet/WeakMap полезны для ситуаций в которых вы ассоциируете данные с объектами, чей жизненный цикл вы не собираетесь контролировать:

  • Кэширование промежуточных результатов

  • Сохранение временных приватных данных

WeakMap

WeakMap - это карта со слабыми ключами. WeakMap избавляет нас от необходимости вручную удалять вспомогательные данные (значения карты), когда удалён основной объект.

const wm = new WeakMap();

wm.set("abc", 123); // TypeError
wm.set({}, 123); // OK

У WeakMap есть ряд ограничений:

  • Ключами обязаны быть только объекты

  • Нет свойства size.

  • Нельзя узнать содержимое карты

  • Нельзя перебрать элементы итератором или forEach.

  • Нет метода clear().

  • Не является итерируемыми

WeakMap работает только на запись (set, delete) и чтение (get, has) элементов по конкретному ключу, а не как полноценная коллекция. Нельзя вывести всё содержимое WeakMap, нет соответствующих методов.

Содержимое WeakMap в произвольный момент, строго говоря, не определено. Может быть, сборщик мусора уже удалил какие-то записи, а может и нет. С этим, а также с требованиями к эффективной реализации WeakMap, и связано отсутствие методов, осуществляющих доступ ко всем записям. Содержимое WeakMap может быть модифицировано сборщиком мусора в любой момент, независимо от программиста. Сборщик мусора работает сам по себе. Он не гарантирует, что очистит объект сразу же, когда это стало возможным. В равной степени он не гарантирует и обратное. Нет какого-то конкретного момента, когда такая очистка точно произойдёт — это определяется внутренними алгоритмами сборщика и его сведениями о системе.

Пример:

const cache = new WeakMap();
function countOwnKeys(obj) {
  if (cache.has(obj)) {
    console.log("Cached");
    return cache.get(obj);
  } else {
    console.log("Computed");
    const count = Object.keys(obj).length;
    cache.set(obj, count);
    return count;
  }
}

WeakSet

WeakSet — особый вид Set не препятствующий сборщику мусора удалять свои элементы. Все ограничения, накладываемые на WeakMap, так же справедливы и для WeakSet. Можно добавлять элементы в WeakSet, проверять их наличие, но нельзя получить их список и даже узнать количество.

Example: class Foo can ensure that its methods are only applied to instances that were created by it:

const foos = new WeakSet();

class Foo {
  constructor() {
    foos.add(this);
  }

  method() {
    if (!foos.has(this)) {
      throw new TypeError("Incompatible object!");
    }
  }
}

Last updated