Привет, Хабр!
Когда дело доходит до коллекций данных в JavaScript, большинство разработчиков сразу вспоминают про массивы, объекты, Map или Set. Но есть и другие, менее известные структуры данных, которые можно назвать «инструментами для особых случаев» — это WeakMap и WeakSet.
WeakMap и WeakSet — это структуры, которые созданы для работы с объектами. Их основная фичи — слабые ссылки, благодаря которым можно избежать утечек памяти. Эти структуры подчищают за собой автоматически, когда объект, используемый в них, становится недостижимым.
Однако их область применения не ограничивается только управлением памятью. WeakMap и WeakSet позволяют:
-
Хранить данные, которые исчезают сами, без явного удаления.
-
Создавать скрытые хранилища для приватных данных, не изменяя сам объект.
-
Автоматическое удаление временных данных, связанных с объектами, например, кэшей.
WeakMap
WeakMap — это коллекция пар ключ‑значение, где:
-
Ключами могут быть только объекты.
-
Значениями могут быть любые данные, от строк до функций.
-
Ключи имеют слабую ссылку, что позволяет сборщику мусора удалять их, если они больше нигде не используются.
Основное отличие от обычного Map в том, что WeakMap заботится о памяти самостоятельно. Не нужно вручную удалять данные, когда объект становится ненужным — это происходит автоматически.
С WeakMap работают всего четыре метода:
-
set(key, value)— добавляет пару ключ‑значение. -
get(key)— возвращает значение, связанное с ключом. -
has(key)— проверяет наличие ключа. -
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:
-
add(value)— добавляет объект. -
has(value)— проверяет наличие объекта. -
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/
Добавить комментарий