Встроенные в JS структуры данных: Map/WeakMap, Set/WeakSet
Введение
Сразу оговорюсь, что речь не пойдет о структурах данных, которые можно с помощью 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
, пока на него есть ссылки где-то еще — иначе сборщик мусора этот объект удалит.
Вывод
Не стоит ограничиваться объектами — часто оптимальнее использовать что-то другое :)
Интересный пост?
Вот еще похожие:
- Событийно-ориентированная архитектура и Node.js Events
- Реактивное программирование: теория и практика
- Как и зачем писать тесты?
- Функциональное программирование. Что это и зачем?
- Профилирование Node.js-приложений