На защитах материала у студентов по JavaScript я регулярно вижу один и тот же пробел: когда речь заходит про встроенные структуры данных, а именно Map, Set, WeakMap и WeakSet — большинство учеников не могут полноценно объяснить, зачем нужны слабые коллекции, какие у них есть ограничения и где их можно применять.
🟣 Что это такое?
WeakMap и WeakSet это специальные коллекции в JavaScript, которые позволяют хранить данные, связанные с объектами, не мешая сборщику мусора удалять их из памяти, когда они больше не используются.
Их применяют, когда данные должны существовать только до тех пор, пока существует связанный с ними объект.
WeakMap хранит пары «ключ - значение» и имеет методы:
➖
set — добавляет новую пару или перезаписывает значение ключа.➖
get — возвращает значение по переданному ключу, если его нет — undefined.➖
has — проверяет наличие ключа и возвращает true / false.➖
delete — удаляет пару по ключу и возвращает true, если запись была удалена, иначе false.WeakSet хранит только значения и имеет методы:
➖
add — добавляет новое значение и возвращает сам WeakSet.➖
has — проверяет наличие значения и возвращает true или false.➖
delete — удаляет значение и возвращает true, если оно существовало, иначе false.🟣 Что означает Weak?
Обычные Map и Set хранят сильную ссылку на объект, поэтому пока объект находится внутри коллекции — сборщик мусора не сможет удалить его из памяти.
А в WeakMap ссылка на ключ является «слабой». Если больше нигде на этот объект нет сильных ссылок, сборщик мусора может удалить и сам объект, и соответствующую запись в WeakMap.
WeakSet работает аналогично: если объект существует только внутри WeakSet и больше нигде не используется, сборщик мусора может удалить его.
При этом очистка происходит не сразу: JavaScript сам определяет момент запуска сборщика мусора, поэтому нельзя строить логику на ожидании удаления объекта.
🟣 Какие значения можно использовать?
Ключами WeakMap и значениями WeakSet не могут быть примитивы, а только объекты.
const users = new WeakMap();
users.set('user-1', true);
// Uncaught TypeError: WeakMap key "user-1" must be an object or an unregistered symbol
«Слабые» коллекции отслеживают жизненный цикл конкретного значения в памяти. У объектов есть собственные ссылки, а примитивы работают иначе.
Поэтому для примитивных значений нужно использовать обычные версии.
Также в актуальной спецификации есть исключение: слабые коллекции также принимают незарегистрированные Symbol'ы. Но основной сценарий их использования — работа именно с объектами.
🟣 Какие есть ограничения?
У WeakMap и WeakSet нет size, keys, values, entries и forEach. Также их нельзя перебрать через for...of.
Размер Weak-структур невозможно определить предсказуемо: он может измениться в любой момент после запуска сборщика мусора. Поэтому API, позволяющего узнать количество элементов или перебрать коллекцию, просто не существует.
Получить данные из WeakMap или проверить наличие объекта в WeakSet можно только если у вас уже есть ссылка на этот объект.
🟣 Применение WeakMap
Один из основных сценариев использования WeakMap — хранение дополнительных данных, связанных с конкретным объектом.
Например, можно хранить метаданные DOM-элемента отдельно, не добавляя служебные поля прямо в него (скрин 1). После удаления DOM-элемента - запись исчезнет автоматически, без необходимости вручную очищать коллекцию.
Также такой подход можно использовать для кэширования результатов, хранения приватных метаданных, состояния экземпляров классов и внутренних данных библиотек.
🟣 Применение WeakSet
Допустим, мы хотим проверить объект на наличие циклических ссылок (скрин 2).
Циклическая ссылка — это ситуация, когда объект прямо или косвенно ссылается сам на себя.
Если при обходе мы повторно встречаем объект, который уже находится в текущем пути обхода, значит обнаружена циклическая ссылка.
Такой подход может быть так же применим при валидации, сериализации, клонировании объектов и анализе сложных конфигураций.
✈️ Telegram | 🎓 Менторство | 📹YouTube | 👩💻 Roadmap

