Введение

Сразу оговорюсь, что речь не пойдет о структурах данных, которые можно с помощью JS реализовать — понятно, что любые. Об этом мы поговорим позже. А в этой статье я расскажу о структурах, призванных в некоторых случаях заменить объекты — Map, WeakMap, Set и WeakSet.

Map

Map — это key-value-хранилище, достаточно похожая на обычный объект структура данных. Отличается она тем, что ключами в Map может быть что угодно — объект, другая Map, любой примитив, что угодно. Еще одно серьезное отличие от объекта — Map запоминает ключи в порядке их вставки.

У Map нет значений в прототипе, поэтому она хранит только то, что мы туда положили. Еще у Map есть cвойство size, что дает нам возможность легко получить количество ключей в Map - в случае с объектом пришлось бы делать Object.keys(obj).length, что не только длиннее, но и имеет большую сложность (O(n log n) в отличие от константной сложности у Map.size).

Еще одно отличие: Map — это Iterable-объект, что позволяет нам напрямую итерировать ее, не используя Object.keys() или Object.entries(), опять же, имеющие свою неконстантную сложность.

Map ощутимо быстрее работает со вставкой и удалением данных, в отличие от неоптимизированного для этого объекта.

Map не умеет в нативную сериализацию, но мы можем сделать что-то вроде такого:

const stringFromMap = JSON.stringify(Array.from(myMap.entries()));

Заодно рассмотрим методы Map:

const map = new Map();

map.clear(); // очистим Map

map.size; // 0

map.set('key', 'value'); // добавим ключ key со значением value
map.get('key'); // 'value'
map.has('key'); // true

map.keys(); // Iterable [key]
map.values(); // Iterable [value]
map.entries(); // Iterable [ [key, value] ]

map.has('nonExistingKey'); // false
map.get('nonExistingKey'); // undefined

WeakMap

Основное отличие WeakMap от Map — то, что ключи WeakMap должны быть объектами. В чем прикол этого? Если ссылок на ключ-объект нет больше нигде, то сборщик мусора спокойно очищает память и удаляет значение из WeakMap. В остальном — это тот же Map.

Set

Set — это коллекция уникальных значений в том порядке, в котором они были добавлены. Преимущества очевидны — мы можем добавлять значения в Set, не заморачиваясь об их уникальности. Поиск значения в Set имеет константную сложность, добавление — линейную.

Рассмотрим методы Set:

const set = new Set();

set.clear(); // очистим set

set.size; // 0

set.add('value');
set.size; // 1

set.add('value');
set.size; // 1 (as Set stores unique values only)

set.has('value') // true
set.has('nonExistingValue') // false

set.values() // Iterable [ 'value' ]
set.keys() // алиас для set.values()
set.entries() // Iterable [ ['value', 'value'] ]

set.delete('value') // true
set.delete('nonExistingValue') // false

WeakSet

WeakSet отличается от Set примерно так же, как WeakMap отличается от Map — в WeakSet мы можем добавлять только объекты, и объект присутствует в WeakSet, пока на него есть ссылки где-то еще — иначе сборщик мусора этот объект удалит.

Вывод

Не стоит ограничиваться объектами — часто оптимальнее использовать что-то другое :)