Среди положительных моментов, появившихся в JavaScript с приходом ES6, мы увидели новые типы данных - наборы (Set) и карты (Map). В отличие от обычных объектов и массивов, это «коллекции ключей». Это означает, что их поведение несколько отличается и, при правильном использовании, они дают значительные преимущества в производительности.
В предыдущей статье мы рассмотрели наборы (Set) и то, как они могут помочь нам писать более быстрый и чистый код. В этой статье я хочу сделать то же самое для Map. Я расскажу, чем они отличаются, где они пригодятся, и где они могут предложить преимущества в производительности по сравнению с обычными JS-объектами.
Чем Map отличается от Object?
Существует два основных различия между картами и обычными объектами JavaScript.
1. Любые значения в качестве ключей
Каждый ключ в обычном объекте JavaScript должен быть либо строкой, либо символом. Пример ниже демонстрирует это:
В отличие от простых объектов, карты позволяют вам использовать в качестве ключей функции, объекты и любые другие типы примитивов (включая NaN) - как показано ниже:
Эта способность обеспечивает большую гибкость при связывании разных типов данных.
2. Прямая итерация
Чтобы перебрать ключи, значения или записи в объекте, вы должны либо преобразовать их в массив, используя такой метод, как Object.keys (), Object.values () или Object.entries (), либо использовать for ... в цикле. Поскольку объекты не могут быть непосредственно итерируемыми, цикл for ... in имеет несколько ограничений: он выполняет итерацию только по перечисляемым, не символьным свойствам и делает это в произвольном порядке.
Но объекты Map позволяют итерировать их напрямую, и, поскольку они представляют собой набор ключей, порядок итерации такой же, как и порядок вставки. Чтобы перебрать записи Map, вы можете использовать цикл for ... of или метод forEach. Следующий код показывает оба перечисленных способа:
Чтобы узнать количество записей в объекте, вы должны сначала преобразовать его в массив следующим образом: Object.keys ({}). length. Напротив, объекты Map имеют свойство size, обратившись к которому вы всегда можете получить количество записей в карте.
Чем Map отличается от Set?
Карты ведут себя очень похоже на наборы, и они используют несколько одинаковых методов, включая has, get, delete и size. Оба являются коллекциями ключей, что означает, что вы можете использовать такие методы, как forEach, для перебора элементов в порядке вставки.
Основное отличие состоит в том, что карта состоит из двух измерений с элементами, которые входят в пару ключ / значение. Так же, как вы можете преобразовать массив в набор, вы можете преобразовать 2D-массив в карту:
Преобразование типов
Чтобы переключить карту обратно в массив, вы можете использовать синтаксис деструктурирования ES6:
До недавнего времени преобразовывать карту в объект было не так удобно (и наоборот), и вам нужно было использовать функцию, подобную приведенной ниже:
Но теперь, с выходом ES2019 , мы получили два новых методов объекта - Object.entries () и Object.fromEntries () - которые делают это намного проще:
Однако, прежде чем использовать Object.fromEntries для преобразования карты в объект, убедитесь, что ключи карты дают уникальные результаты при преобразовании в строку. В противном случае вы рискуете потерять данные при конвертации.
Тесты производительности
Чтобы подготовиться к тестам, я создам объект и карту - каждый из которых имеет миллион идентичных ключей и значений:
Я использовал console.time () для тестирования, поэтому результаты, что приведены ниже, будут зависеть от моей системы и версии Node.js, однако мои результаты постоянно показывают увеличение производительности при использовании Map, особенно при добавлении и удалении записей.
Поиск записей
Object: 0.250ms
Map: 0.095ms (в 2.6 раза быстрее)
Добавление записей
Object: 0.229ms
Map: 0.005ms (в 45.8 раз быстрее!)
Удаление записей
Object: 0.376ms
Map: 0.012ms (в 31 раз быстрее!)
В каких случаях карты медленнее
В моих тестах я обнаружил один случай, когда простые объекты превзошли Map: при использовании цикла for для создания нашего исходного объекта и карты. Этот результат удивителен, поскольку без цикла for добавление записей на карту происходит быстрее добавления записей к стандартному объекту.
Object: 32.143ms
Map: 163.828ms (в 5 раз медленнее)
Пример использования
В заключении, давайте рассмотрим случай, когда карта предпочтительнее объекта. Допустим, мы должны написать функцию, чтобы определить, являются ли две строки анаграммами друг друга:
Есть несколько способов решить эту задачу, но карты могут помочь нам создать одно из самых быстрых решений:
Здесь карты предпочтительнее объектов, потому что нам нужно динамически добавлять и удалять значения и потому что мы заранее не знаем форму данных (или количество записей).
Я надеюсь, что вы эта статья была полезной для вас, и, если вы раньше не сталкивались с JS Map, она открыла вам глаза на ценную часть современного JavaScript.
Пишите в комментариях свои примеры использования объектов Map в JavaScript.
Перевод статьи How JavaScript Maps Can Make Your Code Faster