Встроенные в 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-приложений