Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «WeakMap проти Map». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Обидві структури зберігають пари «ключ → значення», але `Map` тримає ключі сильними посиланнями, а `WeakMap` слабкими, і його ключами можуть бути тільки об'єкти.** Поки живий `Map`, усі його ключі й значення залишаються в пам'яті, навіть якщо зовнішніх посилань на них уже немає, і це прямий шлях до витоку. У `WeakMap` об'єкт, який став недосяжним з коду, збирач сміття видалить разом із записом. Платою за це є відсутність перебору: немає `size`, `keys()`, `values()`, `entries()` і `forEach()`, лише `set`, `get`, `has`, `delete`. ```javascript const weakMap = new WeakMap(); let user = { name: 'Alice' }; weakMap.set(user, 'User data'); user = null; // об'єкт і його запис прибере GC ``` **Ключове:** `Map` для універсальних словників і кешу, `WeakMap` для тимчасової прив'язки даних до об'єктів без витоків пам'яті.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Різниця між `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` не перешкоджає очищенню пам'яті. ### Головна відмінність | Властивість | `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` неперебірний. ### Практичне застосування **Зберігання приватних даних для об'єктів:** ```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; // об'єкт і його кеш очищаються автоматично ``` Ідеально для тимчасового зберігання обчислених даних без витоків пам'яті. **Коротко:** | Властивість | `Map` | `WeakMap` | | --- | --- | --- | | Тип ключів | будь-який | тільки об'єкти | | Перебір елементів | є | немає | | Зв'язок з об'єктами | сильний | слабкий | | Автоматичне видалення | немає | є | | Застосування | кеш, словники, конфіги | приватні дані, кеш без витоків | ### Типові помилки - **Брати примітив за ключ `WeakMap`.** `weakMap.set('id', 1)` кидає `TypeError`, ключем може бути тільки об'єкт. - **Шукати `size` чи цикл по `WeakMap`.** Їх немає за задумом, якщо потрібен перелік ключів, підходить лише `Map`. - **Вважати `Map` безпечним кешем для об'єктів.** Доки живе `Map`, живуть і всі ключі, це найпоширеніше джерело витоків у довгоживучих застосунках. - **Очікувати миттєвого очищення.** GC спрацьовує у свій час, тож одразу після `user = null` запис може ще існувати. - **Плутати з `WeakSet`.** `WeakMap` зберігає пари «об'єкт до значення», а `WeakSet` тільки самі об'єкти, без значень. - **Тримати сильне посилання на ключ у значенні.** Якщо значення посилається на свій же ключ через інший сильний ланцюжок, об'єкт з пам'яті не зникне.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.