Структуры данных
Структуры данных в JavaScript — встроенные и пользовательские способы хранения и организации данных:
Array,Object,Map,Set,WeakMap,WeakSet, а также реализации очередей, стеков и связных списков.
Зачем нужно
Выбор правильной структуры данных определяет производительность алгоритма. Map быстрее Object для частых добавлений/удалений, Set гарантирует уникальность без дублирующей логики, слабые коллекции (WeakMap, WeakSet) не мешают сборщику мусора.
Где используется
- Кеширование результатов (Map)
- Уникальные значения, дедупликация (Set)
- Приватные данные объектов без утечек (WeakMap)
- Очереди (Queue) в BFS, задачах планировщика
- Стеки (Stack) в рекурсии, undo/redo
Map — ключ → значение любого типа
const cache = new Map();
// Ключом может быть что угодно
cache.set('user:1', { name: 'Иван' });
cache.set(42, 'числовой ключ');
cache.set({ id: 1 }, 'объект как ключ');
cache.get('user:1'); // { name: 'Иван' }
cache.has('user:1'); // true
cache.size; // 3
cache.delete('user:1');
// Итерация (порядок вставки сохраняется)
for (const [key, value] of cache) {
console.log(key, '→', value);
}
cache.forEach((value, key) => console.log(key, value));
[...cache.keys()]; // массив ключей
[...cache.values()]; // массив значений
[...cache.entries()]; // массив [key, value]
Set — уникальные значения
// Дедупликация массива
const arr = [1, 2, 2, 3, 3, 3];
const unique = [...new Set(arr)]; // [1, 2, 3]
const roles = new Set(['admin', 'user', 'admin']);
roles.size; // 2 — дубликат отброшен
roles.add('moderator');
roles.has('admin'); // true
roles.delete('user');
for (const role of roles) console.log(role); // admin, moderator
// Пересечение, объединение, разность
const setA = new Set([1, 2, 3, 4]);
const setB = new Set([3, 4, 5, 6]);
const union = new Set([...setA, ...setB]); // {1,2,3,4,5,6}
const intersection = new Set([...setA].filter(x => setB.has(x))); // {3,4}
const difference = new Set([...setA].filter(x => !setB.has(x))); // {1,2}
WeakMap и WeakSet — слабые ссылки
// WeakMap: ключ — только объект, не мешает GC
const metadata = new WeakMap();
function processUser(user) {
if (!metadata.has(user)) {
metadata.set(user, { createdAt: Date.now() });
}
return metadata.get(user);
}
// Когда user удаляется — запись в metadata автоматически исчезает
// Нет .size, нет итерации — это намеренно
// WeakSet: только объекты, нет итерации
const processed = new WeakSet();
function markProcessed(obj) { processed.add(obj); }
function isProcessed(obj) { return processed.has(obj); }
Стек (Stack) — LIFO
class Stack {
#items = ;
push(item) { this.#items.push(item); }
pop { return this.#items.pop(); }
peek { return this.#items.at(-1); }
isEmpty { return this.#items.length === 0; }
get size { return this.#items.length; }
}
const history = new Stack();
history.push('/home');
history.push('/products');
history.push('/cart');
history.pop(); // '/cart' — вернулись назад
history.peek; // '/products' — текущая
Очередь (Queue) — FIFO
class Queue {
#items = ;
enqueue(item) { this.#items.push(item); }
dequeue { return this.#items.shift(); }
front { return this.#items[0]; }
isEmpty { return this.#items.length === 0; }
get size { return this.#items.length; }
}
const taskQueue = new Queue();
taskQueue.enqueue('задача 1');
taskQueue.enqueue('задача 2');
taskQueue.enqueue('задача 3');
while (!taskQueue.isEmpty) {
console.log('Выполняю:', taskQueue.dequeue);
}
// Выполняю: задача 1
// Выполняю: задача 2
// Выполняю: задача 3
Map vs Object
| Критерий | Object | Map |
|---|---|---|
| Ключи | Строки и Symbol | Любой тип |
| Порядок | Частично | Гарантирован (вставки) |
| Размер | Object.keys().length |
.size |
| Итерация | for...in (с проблемами) |
for...of |
| Прототип | Есть (может конфликтовать) | Нет |
| Производительность | Быстро для малых коллекций | Лучше при частых мутациях |
Частые ошибки
1. Сравнение ключей Map по ссылке
const map = new Map();
map.set({ id: 1 }, 'a');
map.get({ id: 1 }); // undefined — другой объект!
// Решение: хранить ссылку на ключ
const key = { id: 1 };
map.set(key, 'a');
map.get(key); // 'a'
2. Использование Object там, где нужен Map
// Частые добавления/удаления → Map быстрее Object
const freq = {}; // медленнее для 10k операций
const freq2 = new Map(); // быстрее
Связанные темы
- Сравнение объектов -- ссылки vs значения
- Структурированное клонирование -- structuredClone
- _MOC JavaScript