Skip to main content

WeakMap проти Map

Різниця між Map і WeakMap у JavaScript фундаментальна: обидва зберігають пари «ключ → значення», але WeakMap створений для особливих випадків, коли треба «зв'язувати дані з об'єктами», не заважаючи збирачу сміття (garbage collector, GC) прибрати ці об'єкти з пам'яті.

Теорія

TL;DR

  • Ключі Map, це будь-які значення, ключі WeakMap, тільки об'єкти.
  • Map тримає ключі сильними посиланнями, WeakMap, слабкими.
  • WeakMap не можна перебирати: немає size, keys(), values(), entries(), forEach().
  • Недосяжний ззовні об'єкт-ключ зникає з WeakMap автоматично, разом зі значенням.
  • Методи WeakMap: set, get, has, delete.
  • Типові задачі: приватні дані класу, кеш без витоків, службові позначки на об'єктах.

Швидкий приклад

Спочатку Map:

javascript
const map = new Map(); let user = { name: 'Alice' }; map.set(user, 'User data'); console.log(map.get(user)); // "User data" user = null; // прибираємо посилання console.log(map); // Map усе ще зберігає { name: "Alice" }

Об'єкт не буде видалений з пам'яті, поки Map зберігає посилання на нього, а це і є витік пам'яті.

Тепер WeakMap:

javascript
const weakMap = new WeakMap(); let user = { name: 'Alice' }; weakMap.set(user, 'User data'); console.log(weakMap.has(user)); // true user = null; // об'єкт стає недосяжним // об'єкт буде автоматично видалений збирачем сміття

Що тут відбувається:

  • Якщо об'єкт більше не досяжний з коду, збирач сміття видалить і сам об'єкт, і його запис із WeakMap.
  • WeakMap не перешкоджає очищенню пам'яті.

Головна відмінність

ВластивістьMapWeakMap
Ключібудь-які значення (рядки, числа, об'єкти)тільки об'єкти
Тип посиланьсильні (об'єкт живе, поки є посилання)слабкі (GC може видалити об'єкт)
Перебір (for...of, .keys(), .size)єнемає
Перевірка розміру.sizeнемає
Використанняуніверсальні пари ключ-значеннятимчасові «прив'язки» до об'єктів

Що означає «слабке посилання»

Слабке посилання, це посилання, яке не заважає збирачу сміття видалити об'єкт, якщо на нього немає інших, сильних посилань.

У звичайному Map ключі зберігаються сильно: поки існує сам Map, усі ключі й значення залишаться в пам'яті. У WeakMap це не так, GC може очистити їх у будь-який момент.

Саме тому WeakMap не дає себе перебрати: набір ключів змінюється непередбачувано, поза контролем коду, тож будь-який обхід був би недетермінованим.

Методи WeakMap

МетодОпис
set(key, value)додати значення для об'єкта
get(key)отримати значення
has(key)перевірити наявність
delete(key)видалити запис

Немає: size, keys(), values(), entries(), forEach(), тому що WeakMap неперебірний.

Практичне застосування

Зберігання приватних даних для об'єктів:

javascript
const privateData = new WeakMap(); class User { constructor(name, age) { privateData.set(this, { age }); this.name = name; } getAge() { return privateData.get(this).age; } } const alice = new User('Alice', 30); console.log(alice.getAge()); // 30 // після видалення alice об'єкт і його приватні дані зникнуть з пам'яті

Тут працюють одразу дві переваги:

  • приватні дані не видно ззовні,
  • вони автоматично очищаються при видаленні об'єкта.

Кешування:

javascript
const cache = new WeakMap(); function getData(obj) { if (!cache.has(obj)) { const data = Math.random(); // припустимо, обчислювати дорого cache.set(obj, data); } return cache.get(obj); } let user = {}; console.log(getData(user)); // створюється кеш user = null; // об'єкт і його кеш очищаються автоматично

Ідеально для тимчасового зберігання обчислених даних без витоків пам'яті.

Коротко:

ВластивістьMapWeakMap
Тип ключівбудь-якийтільки об'єкти
Перебір елементівєнемає
Зв'язок з об'єктамисильнийслабкий
Автоматичне видаленнянемаєє
Застосуваннякеш, словники, конфігиприватні дані, кеш без витоків

Типові помилки

  • Брати примітив за ключ WeakMap. weakMap.set('id', 1) кидає TypeError, ключем може бути тільки об'єкт.
  • Шукати size чи цикл по WeakMap. Їх немає за задумом, якщо потрібен перелік ключів, підходить лише Map.
  • Вважати Map безпечним кешем для об'єктів. Доки живе Map, живуть і всі ключі, це найпоширеніше джерело витоків у довгоживучих застосунках.
  • Очікувати миттєвого очищення. GC спрацьовує у свій час, тож одразу після user = null запис може ще існувати.
  • Плутати з WeakSet. WeakMap зберігає пари «об'єкт до значення», а WeakSet тільки самі об'єкти, без значень.
  • Тримати сильне посилання на ключ у значенні. Якщо значення посилається на свій же ключ через інший сильний ланцюжок, об'єкт з пам'яті не зникне.

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

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

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