← Назад к вопросам
В чем разница между Map, Set, WeakMap, WeakSet?
2.3 Middle🔥 153 комментариев
#JavaScript Core
Комментарии (3)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Map, Set, WeakMap, WeakSet: полное сравнение
Эти четыре структуры данных часто путают. Давай разберёмся в различиях и когда использовать каждую.
Set: уникальные значения
Set — это коллекция уникальных значений любого типа:
const set = new Set();
set.add(1);
set.add('hello');
set.add(1); // Дубликат, не добавится
console.log(set.size); // 2
console.log(set.has(1)); // true
// Итерация
for (const value of set) {
console.log(value);
}
Методы Set:
const set = new Set([1, 2, 3, 2, 1]);
// Проверка наличия
set.has(2); // true
// Добавление
set.add(4); // Set { 1, 2, 3, 4 }
// Удаление
set.delete(2); // true
set.delete(10); // false (элемента нет)
// Очистка
set.clear(); // Set {}
// Размер
set.size; // количество элементов
Map: ключ-значение пары
Map — это коллекция ключ-значение пар (как объект, но лучше):
const map = new Map();
map.set('name', 'John');
map.set('age', 30);
map.set(1, 'один'); // Ключ может быть любого типа!
console.log(map.get('name')); // 'John'
console.log(map.get(1)); // 'один'
console.log(map.size); // 3
Методы Map:
const map = new Map();
// Добавление
map.set('key', 'value');
map.set(42, 'number key');
// Получение
map.get('key'); // 'value'
map.get('unknown'); // undefined
// Проверка
map.has('key'); // true
// Удаление
map.delete('key'); // true
// Очистка
map.clear();
// Размер
map.size; // количество пар
// Итерация
for (const [key, value] of map) {
console.log(key, value);
}
Map vs Object: преимущества
// Object
const obj = {};
obj['key'] = 'value';
obj[1] = 'number'; // Будет преобразовано в '1'
// Map
const map = new Map();
map.set('key', 'value');
map.set(1, 'number'); // Ключ остаётся числом!
console.log(Object.keys(obj)); // ['1', 'key'] - все строки
console.log([...map.keys()]); // [1, 'key'] - оригинальные типы
Почему Map лучше Object:
- Ключи любого типа: объект преобразует ключи в строки
- Итерация в порядке вставки: объект не гарантирует порядок
- Есть метод has(): в объекте нужно проверять undefined
- Есть размер (size): объект нужно считать через Object.keys()
// Object проблемы
const obj = { hasOwnProperty: 'value' };
obj.hasOwnProperty('name'); // TypeError! Поле перезаписало метод
// Map не имеет таких проблем
const map = new Map();
map.set('hasOwnProperty', 'value'); // OK!
WeakSet: "слабые" уникальные значения
WeakSet — это Set, но ключи могут быть удалены сборщиком мусора:
const weakSet = new WeakSet();
const obj = { name: 'John' };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
weakSet.delete(obj);
console.log(weakSet.has(obj)); // false
Ограничения WeakSet:
const weakSet = new WeakSet();
// МОЖНО добавлять
weakSet.add({});
weakSet.add(new Date());
weakSet.add(new Map());
// ЗАПРЕЩЕНО - примитивные типы
weakSet.add(1); // TypeError
weakSet.add('string'); // TypeError
weakSet.add(true); // TypeError
weakSet.add(null); // TypeError
weakSet.add(undefined); // TypeError
Ключевое отличие: автоматическая очистка:
const weakSet = new WeakSet();
let obj = { data: 'important' };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
obj = null; // Удалили последнюю ссылку на объект
// GC удалит объект и автоматически удалит из WeakSet!
// Нет способа проверить, есть ли в WeakSet (потому что он может быть GC'д)
weakSet.has(obj); // false (потому что obj === null теперь)
WeakMap: "слабые" ключ-значение пары
WeakMap — это Map, но ключи могут быть удалены сборщиком мусора:
const weakMap = new WeakMap();
const key1 = { id: 1 };
const key2 = { id: 2 };
weakMap.set(key1, 'value1');
weakMap.set(key2, 'value2');
console.log(weakMap.get(key1)); // 'value1'
Ограничения WeakMap:
const weakMap = new WeakMap();
// МОЖНО использовать как ключи только объекты
const obj = {};
weakMap.set(obj, 'value');
// ЗАПРЕЩЕНО - примитивные типы
weakMap.set('string', 'value'); // TypeError
weakMap.set(123, 'value'); // TypeError
weakMap.set(true, 'value'); // TypeError
WeakMap vs Map: автоматическая очистка памяти
// Map - никогда не удаляет элементы
const cache = new Map();
let user = { id: 1, name: 'John' };
cache.set(user, 'user data');
user = null; // Удалили ссылку
// НО объект остаётся в cache!
console.log(cache.size); // 1 (утечка памяти!)
// WeakMap - автоматически удаляет
const weakCache = new WeakMap();
let user2 = { id: 2, name: 'Jane' };
weakCache.set(user2, 'user data');
user2 = null; // Удалили ссылку
// Объект удалится из weakCache автоматически
Практический пример: кэширование с WeakMap
const cache = new WeakMap();
function getCachedResult(obj) {
if (cache.has(obj)) {
console.log('From cache');
return cache.get(obj);
}
// Дорогостоящее вычисление
const result = heavyCalculation(obj);
cache.set(obj, result);
return result;
}
let data = { value: 100 };
getCachedResult(data); // Вычисляет
getCachedResult(data); // From cache
data = null; // Удалили ссылку
// Кэш автоматически очищается (нет утечки памяти)
Сравнительная таблица
| Свойство | Set | Map | WeakSet | WeakMap |
|---|---|---|---|---|
| Хранит | Значения | Ключ-значение | Значения | Ключ-значение |
| Типы элементов | Любые | Ключ: любые, Значение: любые | Только объекты | Ключ: только объекты |
| Итерируемый | Да | Да | Нет | Нет |
| Имеет size | Да | Да | Нет | Нет |
| Удаление GC | Нет | Нет | Да | Да |
| Использование | Уникальные значения | Кэш, словари | Приватные данные | Кэш объектов |
Когда использовать
Set — когда нужны уникальные значения:
const uniqueIds = new Set([1, 2, 2, 3, 3, 3]);
console.log(uniqueIds.size); // 3
Map — вместо объекта, когда нужна гибкость:
const userMap = new Map();
const userId = { id: 123 }; // Объект как ключ
userMap.set(userId, 'John');
WeakSet — для приватных флагов объектов:
const processed = new WeakSet();
function processUser(user) {
if (processed.has(user)) return;
// обработка
processed.add(user);
}
WeakMap — для кэширования связанных с объектами данных:
const domNodeMetadata = new WeakMap();
const node = document.getElementById('my-element');
domNodeMetadata.set(node, { clicks: 0 });
Итоговые правила
- Set для уникальности, Map для словарей
- WeakSet/WeakMap только для ключей-объектов и автоматической очистки
- Не итерируй WeakSet/WeakMap — это невозможно
- WeakMap идеален для кэширования (нет утечек памяти)
- Используй Map вместо Object для гибкости