WeakMap и WeakSet в JavaScript

от автора

Привет, Хабр!

Когда дело доходит до коллекций данных в JavaScript, большинство разработчиков сразу вспоминают про массивы, объекты, Map или Set. Но есть и другие, менее известные структуры данных, которые можно назвать «инструментами для особых случаев» — это WeakMap и WeakSet.

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

Однако их область применения не ограничивается только управлением памятью. WeakMap и WeakSet позволяют:

  1. Хранить данные, которые исчезают сами, без явного удаления.

  2. Создавать скрытые хранилища для приватных данных, не изменяя сам объект.

  3. Автоматическое удаление временных данных, связанных с объектами, например, кэшей.

WeakMap

WeakMap — это коллекция пар ключ‑значение, где:

  • Ключами могут быть только объекты.

  • Значениями могут быть любые данные, от строк до функций.

  • Ключи имеют слабую ссылку, что позволяет сборщику мусора удалять их, если они больше нигде не используются.

Основное отличие от обычного Map в том, что WeakMap заботится о памяти самостоятельно. Не нужно вручную удалять данные, когда объект становится ненужным — это происходит автоматически.

С WeakMap работают всего четыре метода:

  1. set(key, value) — добавляет пару ключ‑значение.

  2. get(key) — возвращает значение, связанное с ключом.

  3. has(key) — проверяет наличие ключа.

  4. delete(key) — удаляет пару ключ‑значение.

Пример использования:

const weakMap = new WeakMap();  let user = { name: "Alice" }; weakMap.set(user, "Приватные данные пользователя");  console.log(weakMap.get(user)); // "Приватные данные пользователя"  user = null;  // После этого объект автоматически удаляется из WeakMap сборщиком мусора.

Примеры применения

WeakMap отлично подходит для хранения приватных данных внутри объектов, не изменяя их структуру.

const privateData = new WeakMap();  class User {   constructor(name) {     this.name = name;     privateData.set(this, { permissions: [] });   }    getPermissions() {     return privateData.get(this).permissions;   }    addPermission(permission) {     privateData.get(this).permissions.push(permission);   } }  const user = new User("Bob"); user.addPermission("admin"); console.log(user.getPermissions()); // ["admin"]  // Если объект user будет удалён, его данные из privateData также исчезнут.

А если ваш код обрабатывает объекты, и нужно сохранять результаты обработки, WeakMap позволяет это сделать без риска утечек памяти.

const cache = new WeakMap();  function processData(obj) {   if (cache.has(obj)) {     return cache.get(obj); // Используем закэшированные данные   }    // Сложные вычисления   const result = { processed: true };   cache.set(obj, result);    return result; }  let data = { id: 1 };  console.log(processData(data)); // { processed: true } console.log(processData(data)); // { processed: true }  data = null; // Кэш автоматически очищается.

WeakSet

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

Основное предназначение WeakSet — отслеживание уникальных объектов без риска их «залипания» в памяти.

Методов у WeakSet ещё меньше, чем у WeakMap:

  1. add(value) — добавляет объект.

  2. has(value) — проверяет наличие объекта.

  3. delete(value) — удаляет объект.

Пример использования:

const weakSet = new WeakSet();  let obj = { id: 1 };  weakSet.add(obj);  console.log(weakSet.has(obj)); // true  obj = null;  // Объект автоматически удаляется из WeakSet.

Примеры применения

Например, нужно гарантировать, что каждый объект обрабатывается только один раз:

const processed = new WeakSet();  function process(obj) {   if (processed.has(obj)) {     console.log("Объект уже обработан!");     return;   }    processed.add(obj);   console.log("Обрабатываю объект:", obj); }  let task = { id: 1 };  process(task); // "Обрабатываю объект" process(task); // "Объект уже обработан!"  task = null; // WeakSet автоматически очищается.

Так же, работая с DOM, можно использовать WeakSet для отслеживания элементов, которым уже назначены обработчики событий:

const elementsWithHandlers = new WeakSet();  function addClickHandler(element) {   if (!elementsWithHandlers.has(element)) {     elementsWithHandlers.add(element);     element.addEventListener("click", () => console.log("Клик!"));   } }  let div = document.createElement("div");  addClickHandler(div); // Привязываем обработчик addClickHandler(div); // Ничего не делаем, обработчик уже добавлен  div = null; // Обработчики удаляются автоматически.

Хотя использование этих инструментов может показаться ограниченным, они становятся незаменимыми, когда вы работаете с кэшами, приватными данными или сложными DOM‑структурами.

Если есть опыт применения этих инструментов, пишите в комментариях!

Все актуальные инструменты и лучшие практики веб‑разработки можно изучить на онлайн‑курсах в Otus. В каталоге можно посмотреть список всех программ, а в календаре мепроприятий — записаться на бесплатные открытые уроки.


ссылка на оригинал статьи https://habr.com/ru/articles/865512/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *