Структуры данных

Структуры данных в 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(); // быстрее

Связанные темы

Ресурсы