WeakMap и WeakSet: слабые ссылки на объекты
Зачем нужны WeakMap и WeakSet? 🧐
В JavaScript обычные Map и Set хранят элементы жёстко — даже если объект больше нигде не используется, он останется в коллекции, пока вы его явно не удалите. Это может привести к утечкам памяти, особенно в сложных приложениях.
WeakMap и WeakSet решают эту проблему с помощью слабых ссылок (weak references). Если объект существует только внутри WeakMap или WeakSet, он может быть автоматически удалён сборщиком мусора (Garbage Collector, GC).
let user = { name: "Alex" };
const weakMap = new WeakMap();
weakMap.set(user, "secret data"); // Добавляем объект в WeakMap
user = null; // Теперь объект { name: "Alex" } может быть удалён GC
💡 Совет: Используйте
WeakMap, когда нужно хранить дополнительные данные для объектов, время жизни которых вы не контролируете (например, DOM-элементы или сторонние библиотеки).
Особенности WeakMap 🗝️
- Ключи — только объекты. Примитивы (числа, строки и т.д.) не допускаются.
- Не поддерживает перебор. Нет методов
keys(),values(),entries()илиforEach(). - Нельзя узнать размер. Свойство
sizeотсутствует.
const weakMap = new WeakMap();
const obj = { id: 1 };
weakMap.set(obj, "value"); // ✅ Работает
weakMap.set("key", "value"); // ❌ Ошибка: ключ должен быть объектом
Практический пример: кеширование результатов 🏎️
Допустим, у нас есть функция, которая выполняет сложные вычисления. Чтобы не считать одно и то же несколько раз, сохраним результаты в WeakMap.
const cache = new WeakMap();
function computeExpensiveValue(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = /* ...тяжёлые вычисления... */;
cache.set(obj, result);
return result;
}
Когда объект obj больше не нужен, он и связанные с ним данные автоматически удалятся из кеша.
WeakSet: коллекция уникальных объектов 🧩
WeakSet похож на Set, но:
- Хранит только объекты.
- Не поддерживает перебор и метод size.
const weakSet = new WeakSet();
const user1 = { name: "Alice" };
const user2 = { name: "Bob" };
weakSet.add(user1).add(user2);
console.log(weakSet.has(user1)); // true
user1 = null; // Теперь { name: "Alice" } может быть удалён GC
🔥 Идея: Используйте
WeakSet, чтобы отмечать объекты (например, проверенные или обработанные), не мешая их удалению.
Где это применяется в реальности? 🌍
1. Дополнительные данные для DOM-элементов
Храните метаданные для элементов, не влияя на их удаление.
const domData = new WeakMap();
const button = document.querySelector("#myButton");
domData.set(button, { clicks: 0 });
button.addEventListener("click", () => {
const data = domData.get(button);
data.clicks++;
});
2. Отслеживание объектов без утечек памяти
Например, список активных пользователей, который не должен мешать GC.
Итог: когда выбирать WeakMap/WeakSet? 🏆
| Ситуация | Выбор | Почему? |
|---|---|---|
| Нужно хранить данные для объектов | WeakMap |
Автоматическая очистка |
| Отметка объектов (без дублей) | WeakSet |
Лёгкость и автоматическое удаление |
| Требуется перебор коллекции | Обычный Map/Set |
Weak-коллекции не поддерживают итерацию |
// Финал: сравнение Map и WeakMap
const map = new Map();
const weakMap = new WeakMap();
let obj = { data: "test" };
map.set(obj, true); // Объект останется в памяти, пока не удалён из Map
weakMap.set(obj, true); // Объект удалится GC, когда станет недостижим
Теперь вы знаете, как работать с WeakMap и WeakSet эффективно и без утечек памяти! 🎉