Як WeakMap і WeakSet допомагають збирачу сміття?
Нагадування: як працює збирач сміття (Garbage Collector)
JavaScript використовує автоматичне керування пам'яттю: розробник не очищає пам'ять вручну.
Об'єкт залишається в пам'яті поки на нього є хоча б одне посилання. Коли посилань не лишається → збирач сміття (GC) видаляє його.
Приклад:
let user = { name: "Tim" }; // об'єкт у пам'яті
user = null; // посилання втрачено → об'єкт видаляється GCПроблема звичайних колекцій (Map, Set)
Звичайні Map і Set утримують посилання на об'єкти жорстко (strong reference).
Навіть якщо об'єкт більше ніде не використовується,
GC не може його видалити, поки він є в Map чи Set.
let user = { name: "Tim" };
const map = new Map();
map.set(user, "дані");
user = null;
// об'єкт все ще зберігається в map!
// GC не може звільнити пам'ятьРезультат: витік пам'яті, якщо таких об'єктів стає багато.
Рішення: WeakMap і WeakSet
WeakMap
- Ключі - лише об'єкти (не рядки, не числа);
- Значення - будь-які;
- Посилання "слабкі" (weak references): якщо об'єкт більше ніде не використовується, він автоматично видаляється з WeakMap збирачем сміття.
let user = { name: "Tim" };
const weakMap = new WeakMap();
weakMap.set(user, "дані");
user = null; // об'єкт більше недосяжний
// GC видалить і ключ, і значення з WeakMap автоматичноПісля видалення об'єкта з пам'яті ключ зникає з WeakMap.
Жодного ручного delete() не потрібно.
WeakSet
- Зберігає лише об'єкти (без примітивів);
- Кожен запис - слабке посилання;
- Якщо об'єкт більше ніде не використовується, він видаляється з WeakSet автоматично.
let user = { name: "Tim" };
const weakSet = new WeakSet();
weakSet.add(user);
user = null; // об'єкт видалено GC
// weakSet автоматично втрачає це посиланняКлючові особливості WeakMap / WeakSet
| Властивість | WeakMap | WeakSet |
|---|---|---|
| Ключі | Лише об'єкти | Лише об'єкти |
| Значення | Будь-які | Немає значень |
| Посилання | Слабкі | Слабкі |
| GC очищає автоматично | Так | Так |
| Ітерування (for...of) | Не можна | Не можна |
| Методи | set, get, has, delete | add, has, delete |
Чому не можна ітерувати WeakMap / WeakSet
Тому що браузер не знає, коли GC видалить конкретний об'єкт. GC працює непередбачувано, і вміст таких колекцій може змінитися в будь-який момент.
Тому в WeakMap і WeakSet немає методів:
.size.keys().entries().values()forEach
Реальні приклади використання
1. Зберігання даних, "прив'язаних" до об'єкта
const cache = new WeakMap();
function getUserData(user) {
if (!cache.has(user)) {
cache.set(user, { name: user.name, time: Date.now() });
}
return cache.get(user);
}
let tim = { name: "Tim" };
console.log(getUserData(tim)); // кешуємо дані
tim = null; // GC видаляє об'єкт і його дані з кешуТут ми уникли витоку пам'яті: щойно користувач зникає з пам'яті, його кеш автоматично очищується.
2. Відстеження стану об'єктів
const visited = new WeakSet();
function process(obj) {
if (visited.has(obj)) return; // вже обробляли
visited.add(obj);
// ...робимо щось
}Після видалення obj з пам'яті він сам зникає з WeakSet.
Порівняння зі звичайними колекціями
| Тип | Зберігає об'єкти? | Автоочищення GC | Можна ітерувати |
|---|---|---|---|
Map | Так | Ні | Так |
WeakMap | Так | Так | Ні |
Set | Так | Ні | Так |
WeakSet | Так | Так | Ні |
Підсумок
| Пункт | Опис |
|---|---|
| Проблема | Звичайні колекції заважають GC видалити невикористовувані об'єкти |
| Рішення | WeakMap і WeakSet використовують слабкі посилання |
| Поведінка | Об'єкти видаляються з колекції автоматично під час збирання сміття |
| Обмеження | Не можна ітерувати, отримати розмір чи список елементів |
| Використання | Кеші, тимчасові дані, прапорці відвідування, зберігання метаданих |
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.