Урок 08

Map, Set, WeakMap, WeakSet

Современные коллекции помимо объектов и массивов.

Map

Коллекция пар «ключ-значение» с любыми типами ключей.

const map = new Map();

map.set('name', 'Алиса');
map.set(42, 'ответ');
map.set({ id: 1 }, 'объект-ключ');

map.get('name');   // 'Алиса'
map.get(42);       // 'ответ'
map.has('name');   // true
map.size;          // 3
map.delete(42);
map.clear();

Отличие от объекта

  • Ключи любого типа, не только строки
  • Порядок сохраняется
  • Есть size
  • Итерируется напрямую
  • Лучше для частых добавлений и удалений

Создание

const map = new Map([
    ['a', 1],
    ['b', 2],
]);

Из объекта:

const map = new Map(Object.entries({ a: 1, b: 2 }));

Перебор

for (const [key, value] of map) {
    console.log(key, value);
}

for (const key of map.keys()) {}
for (const value of map.values()) {}
for (const [key, value] of map.entries()) {}

map.forEach((value, key) => {});

В объект

Object.fromEntries(map);

Практика: счётчик

function countWords(words) {
    const counts = new Map();

    for (const word of words) {
        counts.set(word, (counts.get(word) ?? 0) + 1);
    }

    return counts;
}

Set

Коллекция уникальных значений.

const set = new Set([1, 2, 2, 3]);
// Set(3) { 1, 2, 3 }

set.add(4);
set.has(2);   // true
set.size;     // 4
set.delete(2);
set.clear();

Уникальность

const unique = [...new Set([1, 2, 2, 3])]; // [1, 2, 3]

Объекты сравниваются по ссылке:

new Set([{ a: 1 }, { a: 1 }]).size; // 2

Перебор

for (const value of set) {}
set.forEach((value) => {});

Практика: пересечение

const a = new Set([1, 2, 3]);
const b = new Set([2, 3, 4]);

const intersection = new Set([...a].filter((x) => b.has(x))); // { 2, 3 }
const union = new Set([...a, ...b]);                         // { 1, 2, 3, 4 }
const difference = new Set([...a].filter((x) => !b.has(x))); // { 1 }

WeakMap

Map с ключами-объектами и слабыми ссылками:

const wm = new WeakMap();

const key = {};
wm.set(key, 'value');
wm.get(key); // 'value'

Особенности:

  • Ключи только объекты
  • Не итерируется
  • Нет size
  • Нет clear
  • Если ключ больше не используется — сборщик мусора удалит запись

Где используется WeakMap

Приватные данные:

const privates = new WeakMap();

class User {
    constructor(name) {
        privates.set(this, { name });
    }

    getName() {
        return privates.get(this).name;
    }
}

Кеширование:

const cache = new WeakMap();

function process(obj) {
    if (cache.has(obj)) return cache.get(obj);
    const result = heavyComputation(obj);
    cache.set(obj, result);
    return result;
}

WeakSet

Set со слабыми ссылками:

const ws = new WeakSet();
const obj = {};
ws.add(obj);
ws.has(obj); // true
  • Только объекты
  • Не итерируется
  • Нет size

Когда что

  • Map — словарь с любыми ключами
  • Set — уникальные значения
  • WeakMap — приватные данные, кеш по объектам
  • WeakSet — отметки объектов
  • Объект — статические данные с строковыми ключами
  • Массив — упорядоченные значения

Итоги

  • Map — ключи любого типа
  • Set — уникальные значения
  • WeakMap — слабые ссылки, не итерируется
  • WeakSet — слабые ссылки
  • Object.fromEntries для преобразования
  • Spread для массивов