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:
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:
const weakMap = new WeakMap();
let user = { name: 'Alice' };
weakMap.set(user, 'User data');
console.log(weakMap.has(user)); // true
user = null; // об'єкт стає недосяжним
// об'єкт буде автоматично видалений збирачем сміттяЩо тут відбувається:
- Якщо об'єкт більше не досяжний з коду, збирач сміття видалить і сам об'єкт, і його запис із
WeakMap. WeakMapне перешкоджає очищенню пам'яті.
Головна відмінність
| Властивість | Map | WeakMap |
|---|---|---|
| Ключі | будь-які значення (рядки, числа, об'єкти) | тільки об'єкти |
| Тип посилань | сильні (об'єкт живе, поки є посилання) | слабкі (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 неперебірний.
Практичне застосування
Зберігання приватних даних для об'єктів:
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 об'єкт і його приватні дані зникнуть з пам'ятіТут працюють одразу дві переваги:
- приватні дані не видно ззовні,
- вони автоматично очищаються при видаленні об'єкта.
Кешування:
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; // об'єкт і його кеш очищаються автоматичноІдеально для тимчасового зберігання обчислених даних без витоків пам'яті.
Коротко:
| Властивість | Map | WeakMap |
|---|---|---|
| Тип ключів | будь-який | тільки об'єкти |
| Перебір елементів | є | немає |
| Зв'язок з об'єктами | сильний | слабкий |
| Автоматичне видалення | немає | є |
| Застосування | кеш, словники, конфіги | приватні дані, кеш без витоків |
Типові помилки
- Брати примітив за ключ
WeakMap.weakMap.set('id', 1)кидаєTypeError, ключем може бути тільки об'єкт. - Шукати
sizeчи цикл поWeakMap. Їх немає за задумом, якщо потрібен перелік ключів, підходить лишеMap. - Вважати
Mapбезпечним кешем для об'єктів. Доки живеMap, живуть і всі ключі, це найпоширеніше джерело витоків у довгоживучих застосунках. - Очікувати миттєвого очищення. GC спрацьовує у свій час, тож одразу після
user = nullзапис може ще існувати. - Плутати з
WeakSet.WeakMapзберігає пари «об'єкт до значення», аWeakSetтільки самі об'єкти, без значень. - Тримати сильне посилання на ключ у значенні. Якщо значення посилається на свій же ключ через інший сильний ланцюжок, об'єкт з пам'яті не зникне.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.