ДокументацияJavaScriptMap, Set, WeakMap, WeakSet в JavaScript — когда использовать
Средний 8 мин чтения

Map, Set, WeakMap, WeakSet в JavaScript — когда использовать

Коллекции Map и Set в JavaScript — отличие от объектов и массивов, когда использовать Map вместо Object, Set для уникальных значений, WeakMap и WeakSet для памяти.

MapSetWeakMapWeakSetколлекцииSet JSMap JavaScriptуникальные значения

Map

Map — коллекция пар «ключ-значение». В отличие от объекта, ключом может быть что угодно: объект, функция, примитив.

Создание и базовые операции

const map = new Map()

// Добавить
map.set('name', 'Анна')
map.set('age', 25)
map.set({ id: 1 }, 'объект как ключ')

// Получить
map.get('name')  // 'Анна'
map.get('age')   // 25

// Проверить наличие
map.has('name')  // true

// Размер
map.size         // 3

// Удалить
map.delete('age')

// Очистить всё
map.clear()

set возвращает сам map, поэтому можно chaining:

const config = new Map()
  .set('api', '/api/v1')
  .set('timeout', 5000)
  .set('retries', 3)

Инициализация из массива

const users = new Map([
  ['anna', { age: 25 }],
  ['ivan', { age: 30 }],
])

users.get('anna') // { age: 25 }

Перебор

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

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

// Через методы
map.forEach((value, key) => {
  console.log(`${key} = ${value}`)
})

// Отдельно ключи и значения
[...map.keys()]    // ['a', 'b', 'c']
[...map.values()]  // [1, 2, 3]
[...map.entries()]  // [['a', 1], ['b', 2], ['c', 3]]

Когда Map лучше объекта

СвойствоObjectMap
Ключитолько строки и Symbolлюбые типы
Порядок ключейне гарантирован (до ES6)в порядке добавления
Размервручную Object.keys().lengthmap.size
Производительностьлучше для малого числа ключейлучше для частого добавления/удаления
Прототипесть (toString, hasOwnProperty)нет лишних свойств
// Map с объектами как ключами — объект так не может
const clicks = new Map()

document.querySelectorAll('.btn').forEach(btn => {
  clicks.set(btn, 0)
  btn.addEventListener('click', () => {
    clicks.set(btn, clicks.get(btn) + 1)
  })
})

Set

Set — коллекция уникальных значений. Дубликаты игнорируются.

const set = new Set()

set.add(1)
set.add(2)
set.add(3)
set.add(1) // дубль — проигнорирован

set.size // 3

set.has(2)  // true
set.has(99) // false

set.delete(3)

Создание из массива

const unique = new Set([1, 2, 2, 3, 3, 3])
console.log(unique) // Set { 1, 2, 3 }

// Обратно в массив
const arr = [...unique] // [1, 2, 3]

Удаление дубликатов из массива

Это главная повседневная задача для Set:

const tags = ['js', 'css', 'js', 'html', 'css', 'vue']
const uniqueTags = [...new Set(tags)]
// ['js', 'css', 'html', 'vue']

Перебор

const set = new Set(['яблоко', 'банан', 'груша'])

for (const item of set) {
  console.log(item)
}

set.forEach(item => console.log(item))

Операции над множествами

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

// Объединение
const union = new Set([...a, ...b]) // { 1, 2, 3, 4 }

// Пересечение
const intersection = new Set([...a].filter(x => b.has(x))) // { 2, 3 }

// Разность
const difference = new Set([...a].filter(x => !b.has(x))) // { 1 }

WeakMap

То же что Map, но:

  • Ключи — только объекты
  • Ключи — слабые ссылки: если на объект больше никто не ссылается, он удаляется сборщиком мусора
  • Нельзя перебрать (forEach, keys(), size — отсутствуют)
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
}

let element = document.querySelector('.card')
process(element)

// Когда element удаляется из DOM и на него нет ссылок:
element = null // WeakMap автоматически удалит запись — утечки памяти не будет

Типичное использование — приватные данные

const privateData = new WeakMap()

class User {
  constructor(name, secret) {
    this.name = name
    privateData.set(this, { secret })
  }

  getSecret() {
    return privateData.get(this).secret
  }
}

const anna = new User('Анна', 'пароль123')
anna.getSecret() // 'пароль123'
console.log(anna.secret) // undefined — нет прямого доступа

WeakSet

То же что Set, но:

  • Только объекты
  • Слабые ссылки — объекты удаляются, если больше нигде не используются
  • Нельзя перебрать
const visited = new WeakSet()

function trackVisit(user) {
  if (visited.has(user)) {
    console.log('Уже был')
    return
  }
  visited.add(user)
  console.log('Первый визит')
}

let user = { name: 'Анна' }
trackVisit(user) // 'Первый визит'
trackVisit(user) // 'Уже был'

user = null // запись в WeakSet удалится автоматически

Что когда использовать

ЗадачаИнструмент
Хранить пары «строка → значение»Object
Ключи не строки (объекты, функции)Map
Часто добавляете/удаляете парыMap
Нужно сохранить порядокMap
Уникальные значенияSet
Удалить дубликаты из массиваSet
Кэш, привязанный к объектуWeakMap
Отметить обработанные объектыWeakSet
Простая конфигурацияObject

Итог

  • Map — когда нужны нестроковые ключи или частое добавление/удаление
  • Set — для уникальных значений и удаления дубликатов
  • WeakMap / WeakSet — когда нужно привязать данные к объекту без утечек памяти
  • Для простых случаев ({ key: value }) обычный объект по-прежнему норма