Skip to main content

Як WeakMap і WeakSet допомагають збирачу сміття?

Нагадування: як працює збирач сміття (Garbage Collector)

JavaScript використовує автоматичне керування пам'яттю: розробник не очищає пам'ять вручну.

Об'єкт залишається в пам'яті поки на нього є хоча б одне посилання. Коли посилань не лишається → збирач сміття (GC) видаляє його.

Приклад:

javascript
let user = { name: "Tim" }; // об'єкт у пам'яті user = null; // посилання втрачено → об'єкт видаляється GC

Проблема звичайних колекцій (Map, Set)

Звичайні Map і Set утримують посилання на об'єкти жорстко (strong reference). Навіть якщо об'єкт більше ніде не використовується, GC не може його видалити, поки він є в Map чи Set.

javascript
let user = { name: "Tim" }; const map = new Map(); map.set(user, "дані"); user = null; // об'єкт все ще зберігається в map! // GC не може звільнити пам'ять

Результат: витік пам'яті, якщо таких об'єктів стає багато.


Рішення: WeakMap і WeakSet

WeakMap

  • Ключі - лише об'єкти (не рядки, не числа);
  • Значення - будь-які;
  • Посилання "слабкі" (weak references): якщо об'єкт більше ніде не використовується, він автоматично видаляється з WeakMap збирачем сміття.
javascript
let user = { name: "Tim" }; const weakMap = new WeakMap(); weakMap.set(user, "дані"); user = null; // об'єкт більше недосяжний // GC видалить і ключ, і значення з WeakMap автоматично

Після видалення об'єкта з пам'яті ключ зникає з WeakMap. Жодного ручного delete() не потрібно.


WeakSet

  • Зберігає лише об'єкти (без примітивів);
  • Кожен запис - слабке посилання;
  • Якщо об'єкт більше ніде не використовується, він видаляється з WeakSet автоматично.
javascript
let user = { name: "Tim" }; const weakSet = new WeakSet(); weakSet.add(user); user = null; // об'єкт видалено GC // weakSet автоматично втрачає це посилання

Ключові особливості WeakMap / WeakSet

ВластивістьWeakMapWeakSet
КлючіЛише об'єктиЛише об'єкти
ЗначенняБудь-якіНемає значень
ПосиланняСлабкіСлабкі
GC очищає автоматичноТакТак
Ітерування (for...of)Не можнаНе можна
Методиset, get, has, deleteadd, has, delete

Чому не можна ітерувати WeakMap / WeakSet

Тому що браузер не знає, коли GC видалить конкретний об'єкт. GC працює непередбачувано, і вміст таких колекцій може змінитися в будь-який момент.

Тому в WeakMap і WeakSet немає методів:

  • .size
  • .keys()
  • .entries()
  • .values()
  • forEach

Реальні приклади використання

1. Зберігання даних, "прив'язаних" до об'єкта

javascript
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. Відстеження стану об'єктів

javascript
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 використовують слабкі посилання
ПоведінкаОб'єкти видаляються з колекції автоматично під час збирання сміття
ОбмеженняНе можна ітерувати, отримати розмір чи список елементів
ВикористанняКеші, тимчасові дані, прапорці відвідування, зберігання метаданих

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.