Я только что обнаружил chromestatus.com и, потеряв несколько часов своего дня, нашел эту запись :
Карта: Объекты карты являются простыми картами ключ / значение.
Это смутило меня. Обычные объекты JavaScript являются словарями, так чем же они Map
отличаются от словаря? Концептуально они идентичны (в зависимости от разницы между картой и словарем? )
Ссылки на chromestatus в документации тоже не помогают:
Объекты карты представляют собой наборы пар ключ / значение, где и ключи, и значения могут быть произвольными значениями языка ECMAScript. Отдельное значение ключа может встречаться только в одной паре ключ / значение в коллекции карты. Определите ключевые значения в соответствии с алгоритмом сравнения, который выбирается при создании карты.
Объект Map может перебирать свои элементы в порядке вставки. Объект карты должен быть реализован с использованием хеш-таблиц или других механизмов, которые в среднем обеспечивают времена доступа, которые являются сублинейными по количеству элементов в коллекции. Структуры данных, используемые в этой спецификации объектов Map, предназначены только для описания требуемой наблюдаемой семантики объектов Map. Он не предназначен для жизнеспособной модели реализации.
... все еще звучит как объект для меня, так ясно, что я что-то пропустил.
Почему JavaScript получает (хорошо поддерживаемый) Map
объект? Что оно делает?
Ответы:
По словам Мозиллы:
и
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
Итеративность по порядку - это функция, которая давно востребована разработчиками, отчасти потому, что она обеспечивает одинаковую производительность во всех браузерах. Так что для меня это большой.
myMap.has(key)
Метод будет особенно удобно, а такжеmyMap.size
недвижимость.источник
map = Object.create(null)
. Что такое ключи по умолчанию? Как ключи связаны сObject.prototype
?new
оператор использовался сMap
символом, т. Е. Дляnew Map
него создавался объект карты.var a = {}
является сокращением для (означает эквивалентно)var a = Object.create(Object.prototype)
Основное отличие состоит в том, что Объекты поддерживают только строковые ключи, тогда как Карты поддерживают более или менее любой тип ключа.
Если я это сделаю,
obj[123] = true
тоObject.keys(obj)
тогда я получу,["123"]
а не[123]
. Карта будет сохранять тип ключа и возвращать,[123]
что здорово. Карты также позволяют использовать объекты в качестве ключей. Традиционно для этого вам нужно было бы дать объектам какой-то уникальный идентификатор для их хеширования (я не думаю, что когда-либо видел что-то подобноеgetObjectId
в JS как часть стандарта). Карты также гарантируют сохранение порядка, поэтому они лучше сохраняются и иногда могут спасти вас от необходимости делать несколько сортировок.Между картами и объектами на практике есть несколько плюсов и минусов. Объекты получают как преимущества, так и недостатки, будучи очень тесно интегрированными в ядро JavaScript, что отличает их от значительного Map за исключением различий в поддержке ключей.
Непосредственным преимуществом является то, что у вас есть синтаксическая поддержка объектов, облегчающая доступ к элементам. У вас также есть прямая поддержка для этого с JSON. При использовании в качестве хэша раздражает получение объекта без каких-либо свойств. По умолчанию, если вы хотите использовать объекты в качестве хеш-таблицы, они будут загрязнены, и вам часто придется вызывать
hasOwnProperty
их при доступе к свойствам. Здесь вы можете увидеть, как по умолчанию объекты загрязняются и как создавать, как мы надеемся, незагрязненные объекты для использования в качестве хэшей:Загрязнение объектов не только делает код более раздражающим, медленным и т. Д., Но также может иметь потенциальные последствия для безопасности.
Объекты не являются чистыми хеш-таблицами, но пытаются сделать больше. У вас такие головные боли
hasOwnProperty
, как неспособность легко определить длину (Object.keys(obj).length
) и так далее. Объекты предназначены не только для использования в качестве хеш-карт, но и в качестве динамически расширяемых объектов, и поэтому при использовании их в качестве чистых хеш-таблиц возникают проблемы.Сравнение / Список различных общих операций:
Есть несколько других вариантов, подходов, методологий и т. Д. С различными подъемами и падениями (производительность, краткость, переносимость, расширение и т. Д.). Объекты немного странны, так как являются ядром языка, поэтому у вас есть много статических методов для работы с ними.
Помимо преимущества Карт, сохраняющих типы ключей, а также возможность поддерживать такие вещи, как объекты, в качестве ключей, они изолированы от побочных эффектов, которые имеют многие объекты. Карта - это чистый хеш, и нет никакой путаницы в попытках быть объектом одновременно. Карты также могут быть легко расширены с помощью функций прокси. У объекта в настоящее время есть класс Proxy, однако производительность и использование памяти мрачны, фактически создание собственного прокси-сервера, который выглядит так, как будто карта для объектов в настоящее время работает лучше, чем Proxy.
Существенным недостатком Карт является то, что они не поддерживаются с помощью JSON напрямую. Разбор возможен, но имеет несколько зависаний:
Выше приведено серьезное снижение производительности, а также не поддерживаются строковые ключи. Кодирование JSON еще сложнее и проблематичнее (это один из многих подходов):
Это не так плохо, если вы просто используете Карты, но у вас будут проблемы, когда вы смешиваете типы или используете нескалярные значения в качестве ключей (не то, чтобы JSON идеально подходил для такого рода проблем, как круговая ссылка на объект IE). Я не проверял это, но есть вероятность, что это сильно повредит производительности по сравнению с stringify.
У других языков сценариев часто нет таких проблем, поскольку они имеют явные нескалярные типы для Map, Object и Array. Веб-разработка часто представляет собой проблему с нескалярными типами, когда вам приходится иметь дело с такими вещами, как PHP объединяет массив / карту с объектом, используя A / M для свойств, а JS объединяет карту / объект с массивом, расширяющим M / O. Слияние сложных типов - проклятие дьявола для языков сценариев высокого уровня.
Пока это в значительной степени проблемы, связанные с внедрением, но важна и производительность для основных операций. Производительность также сложна, потому что это зависит от двигателя и использования. Пройдите мои тесты с долей соли, поскольку я не могу исключить любую ошибку (я должен спешить с этим). Вы также должны запустить свои собственные тесты, чтобы подтвердить, так как мои проверяют только очень конкретные простые сценарии, чтобы дать только приблизительное указание. Согласно тестам в Chrome для очень больших объектов / карт производительность для объектов хуже из-за удаления, которое, очевидно, каким-то образом пропорционально количеству ключей, а не O (1):
Chrome явно имеет большое преимущество при получении и обновлении, но производительность удаления просто ужасна. Карты в этом случае используют чуть-чуть больше памяти (накладные расходы), но при проверке только одного объекта / карты с миллионами ключей влияние накладных расходов на карты выражается недостаточно хорошо. Объекты управления памятью также, кажется, освобождаются раньше, если я правильно читаю профиль, что может быть одним из преимуществ в пользу объектов.
В Firefox для этого конкретного теста это другая история:
Я должен сразу отметить, что в этом конкретном бенчмарке удаление из объектов в Firefox не вызывает никаких проблем, однако в других бенчмарках это вызывало проблемы, особенно когда имеется много ключей, как в Chrome. Карты явно превосходят Firefox для больших коллекций.
Однако это не конец истории, как насчет множества маленьких объектов или карт? Я сделал быстрый тест этого, но не исчерпывающий (настройка / получение), который лучше всего работает с небольшим количеством ключей в вышеуказанных операциях. Этот тест больше о памяти и инициализации.
Опять же, эти цифры меняются, но в основном у Object хорошее преимущество. В некоторых случаях опережение «Объекты над картами» является экстремальным (~ в 10 раз лучше), но в среднем оно было в 2-3 раза лучше. Кажется, что экстремальные скачки производительности могут работать в обоих направлениях. Я только протестировал это в Chrome и создании, чтобы профилировать использование памяти и накладные расходы. Я был очень удивлен, увидев, что в Chrome оказалось, что Карты с одним ключом используют примерно в 30 раз больше памяти, чем Объекты с одним ключом.
Для тестирования множества мелких объектов со всеми вышеуказанными операциями (4 клавиши):
С точки зрения распределения памяти они вели себя одинаково с точки зрения освобождения / GC, но Map использовала в 5 раз больше памяти. В этом тесте использовалось 4 ключа, где, как и в последнем тесте, я установил только один ключ, так что это объясняет сокращение накладных расходов памяти. Я провел этот тест несколько раз, и карта / объект в целом более или менее похожи на Chrome с точки зрения общей скорости. В Firefox для небольших объектов есть определенное преимущество в производительности по сравнению с картами в целом.
Это, конечно, не включает в себя отдельные варианты, которые могут сильно отличаться. Я бы не советовал микрооптимизировать с этими цифрами. Что из этого можно сделать, так это то, что, как правило, более тщательно рассмотрите Карты для хранилищ с очень большими значениями ключей и объекты для хранилищ с небольшими значениями ключей.
Кроме того, лучшая стратегия с этими двумя - это реализовать ее и просто заставить работать в первую очередь. При профилировании важно иметь в виду, что иногда вещи, о которых вы не думаете, будут медленными, если смотреть на них, они могут быть невероятно медленными из-за причуд движка, как это видно в случае удаления ключа объекта.
источник
Я не думаю, что следующие ответы были упомянуты в ответах до сих пор, и я подумал, что их стоит упомянуть.
Карты могут быть больше
В хроме я могу получить 16,7 миллиона пар ключ / значение с
Map
VS. 11,1 млн с обычным объектом. Почти ровно на 50% больше пар сMap
. Они оба занимают около 2 ГБ памяти, прежде чем они рушатся, и поэтому я думаю, что это может быть связано с ограничением памяти хромом ( Правка : Да, попробуйте заполнить 2,Maps
и вы получите только 8,3 миллиона пар до каждой аварии). Вы можете проверить это самостоятельно с помощью этого кода (очевидно, запускать их отдельно, а не одновременно):У объектов уже есть некоторые свойства / ключи
Этот споткнул меня раньше. Обычные объекты имеют
toString
,constructor
,valueOf
,hasOwnProperty
,isPrototypeOf
и куча других уже существующих свойств. Это не может быть большой проблемой для большинства случаев использования, но раньше это вызывало у меня проблемы.Карты могут быть медленнее:
Из-за
.get
накладных расходов на вызов функции и отсутствия внутренней оптимизации Map может быть значительно медленнее, чем обычный старый объект JavaScript для некоторых задач.источник
toString
,constructor
и т.д. (то есть ключи крайне маловероятно , чтобы столкнуться с ними). С ними легче работать - например, с приращением естьobj[i] = (obj[i] || 0) + 1
, тогда как сMap
ним всеmap.set(i, (map.get(i) || 0) + 1)
еще не так уж плохо, но это просто показывает, как все может стать беспорядочным. У карт определенно есть свои варианты использования, но часто подойдет простой объект.toString
,constructor
( и т.д.) свойства объекта путем написанияobj = Object.create(null)
вместоobj = {}
.Объекты могут вести себя как словари, потому что Javascript динамически типизирован, что позволяет вам добавлять или удалять свойства объекта в любое время.
Но новая
Map()
функциональность намного лучше, потому что:get
,set
,has
иdelete
методы.for-of
использования и поддерживает порядок результатов.99% времени вы должны просто использовать
Map()
. Однако, если вы используете только строковые ключи и вам нужна максимальная производительность чтения, тогда объекты могут быть лучшим выбором.Суть в том, что (почти все) движки javascript компилируют объекты до классов C ++ в фоновом режиме. Эти типы кэшируются и повторно используются их «контуром», поэтому при создании нового объекта с точно такими же свойствами движок будет повторно использовать существующий фоновый класс. Путь доступа к свойствам в этих классах очень оптимизирован и намного быстрее, чем поиск
Map()
.Добавление или удаление свойства приводит к повторной компиляции кэшированного класса поддержки, поэтому использование объекта в качестве словаря с большим количеством добавлений и удалений ключей происходит очень медленно, но чтение и назначение существующих ключей без изменения объекта выполняется очень быстро.
Так что, если у вас нагрузка для чтения с однократной записью и строковыми ключами, используйте
object
специализированный высокопроизводительный словарь, а для всего остального используйте aMap()
.источник
get set has delete
функциональные возможности, но это не так уж и элегантно (но и неплохо). КакMap
проще использовать для итерации? Не уверен, что могу согласиться.В дополнение к другим ответам я обнаружил, что Карты более громоздкие и многословные для работы, чем объекты.
Это важно, потому что более короткий код быстрее читается, более выразителен и лучше хранится в голове программиста .
Другой аспект: так как set () возвращает карту, а не значение, невозможно связать назначения.
Отладка карт также более болезненна. Ниже вы не можете увидеть, какие ключи находятся на карте. Вы должны написать код, чтобы сделать это.
Объекты могут быть оценены любой IDE:
источник
Резюме:
Object
: Структура данных, в которой данные хранятся в виде пар ключ-значение. В объекте ключ должен быть числом, строкой или символом. Значением может быть что угодно, так же как и другие объекты, функции и т. Д. Объект является неупорядоченной структурой данных, т.е. последовательность вставки пар ключ-значение не запоминается.ES6 Map
: Структура данных, в которой данные хранятся в виде пар ключ-значение. В котором уникальный ключ отображается на значение . И ключ, и значение могут быть в любом типе данных . Карта - это итеративная структура данных, это означает, что последовательность вставки запоминается и что мы можем получить доступ к элементам, например, вfor..of
циклеКлючевые отличия:
A
Map
является упорядоченным и повторяемым, тогда как объекты не упорядочены и не повторяемыМы можем поместить любой тип данных в качестве
Map
ключа, тогда как объекты могут иметь в качестве ключа только число, строку или символ.А
Map
наследует отMap.prototype
. Это предлагает все виды служебных функций и свойств, что делает работу сMap
объектами намного проще.Пример:
объект:
Карта:
Источник: MDN
источник
В дополнение к возможности повторения в четко определенном порядке и возможности использовать произвольные значения в качестве ключей (кроме
-0
), карты могут быть полезны по следующим причинам:Спецификация заставляет операции карты быть сублинейными в среднем.
Любая не глупая реализация объекта будет использовать хеш-таблицу или аналогичную, поэтому поиск свойств, вероятно, будет в среднем постоянным. Тогда объекты могут быть даже быстрее, чем карты. Но это не требуется спецификацией.
У объектов могут быть неприятные неожиданные поведения.
Например, допустим, вы не установили какое-либо
foo
свойство для вновь созданного объектаobj
, поэтому вы ожидаетеobj.foo
вернуть undefined. Ноfoo
может быть встроенным свойством, унаследованным отObject.prototype
. Или вы пытаетесь создатьobj.foo
с помощью присваивания, ноObject.prototype
запускается какой-то сеттер вместо сохранения вашего значения.Карты предотвращают подобные вещи. Ну, если какой-то сценарий не испортится
Map.prototype
. ИObject.create(null)
будет работать, но тогда вы потеряете простой синтаксис инициализатора объекта.источник
Когда использовать Карты вместо простых объектов JavaScript?
Простой объект JavaScript {key: 'value'} содержит структурированные данные. Но простой объект JS имеет свои ограничения:
В качестве ключей Объектов могут использоваться только строки и символы. Если мы будем использовать любые другие вещи, скажем, числа в качестве ключей объекта, то при доступе к этим ключам мы увидим, что эти ключи будут неявно преобразованы в строки, что приведет к потере согласованности типов. const names = {1: «один», 2: «два»}; Object.keys (имена); // ['1', '2']
Есть вероятность случайной перезаписи унаследованных свойств из прототипов путем записи идентификаторов JS в качестве ключевых имен объекта (например, toString, конструктор и т. Д.)
Другой объект не может быть использован в качестве ключа объекта, поэтому для объекта нельзя записать дополнительную информацию, записав этот объект в качестве ключа другого объекта, и значение этого другого объекта будет содержать дополнительную информацию.
Объекты не являются итераторами
Размер объекта не может быть определен напрямую
Эти ограничения Объектов решаются с помощью Карт, но мы должны рассматривать Карты как дополнение к Объектам вместо замены. По сути, Map - это просто массив массивов, но мы должны передать этот массив массивов в объект Map как аргумент с новым ключевым словом, иначе только для массива массивов полезные свойства и методы Map недоступны. И помните, что пары ключ-значение внутри массива массивов или карты должны быть разделены только запятыми, а не двоеточиями, как в простых объектах.
3 совета, чтобы решить, использовать ли карту или объект:
Используйте карты для объектов, когда ключи неизвестны до времени выполнения, потому что ключи, сформированные пользовательским вводом или неосознанно, могут нарушить код, который использует объект, если эти ключи перезаписывают унаследованные свойства объекта, поэтому карта в этих случаях безопаснее. Также используйте карты, когда все ключи одного типа и все карты одного типа.
Используйте карты, если необходимо хранить примитивные значения в качестве ключей.
Используйте объекты, если нам нужно оперировать отдельными элементами.
Преимущества использования Карт:
1. Карта принимает любой тип ключа и сохраняет тип ключа:
Мы знаем, что если ключ объекта не является строкой или символом, то JS неявно преобразует его в строку. Напротив, Map принимает ключи любого типа: строку, число, логическое значение, символ и т. Д., А Map сохраняет исходный тип ключа. Здесь мы будем использовать число в качестве ключа внутри карты, и оно останется числом:
Внутри карты мы можем даже использовать весь объект в качестве ключа. Могут быть случаи, когда мы хотим сохранить некоторые данные, относящиеся к объекту, не прикрепляя эти данные внутри самого объекта, чтобы мы могли работать с худыми объектами, но хотели бы хранить некоторую информацию об объекте. В этих случаях нам нужно использовать Map, чтобы мы могли сделать Object в качестве ключа и связанные данные объекта в качестве значения.
Но недостатком этого подхода является сложность доступа к значению по ключу, так как нам нужно перебрать весь массив, чтобы получить желаемое значение.
Мы можем решить эту проблему, не получая прямой доступ к значению, используя правильную карту.
Мы могли бы сделать это с помощью WeakMap, просто написать, const myMap = new WeakMap (). Различия между Map и WeakMap заключаются в том, что WeakMap позволяет собирать мусор ключей (здесь объектов), поэтому он предотвращает утечки памяти, WeakMap принимает только объекты в качестве ключей, а WeakMap сокращает набор методов.
2. Карта не имеет ограничений по именам ключей:
Для простых объектов JS мы можем случайно перезаписать свойство, унаследованное от прототипа, и это может быть опасно. Здесь мы перезапишем свойство toString () объекта actor:
Теперь давайте определим fn isPlainObject (), чтобы определить, является ли предоставленный аргумент простым объектом, и этот fn использует метод toString () для его проверки:
Карта не имеет никаких ограничений на имена ключей, мы можем использовать имена ключей, такие как toString, конструктор и т. Д. Здесь, хотя объект actorMap имеет свойство с именем toString, но метод toString (), унаследованный от прототипа объекта actorMap, работает отлично.
Если у нас есть ситуация, когда пользовательский ввод создает ключи, тогда мы должны взять эти ключи внутри карты вместо простого объекта. Это связано с тем, что пользователь может выбрать имя настраиваемого поля, например, toString, конструктор и т. Д., Тогда такие имена ключей в простом объекте потенциально могут нарушить код, который позднее использует этот объект. Таким образом, правильное решение состоит в том, чтобы связать состояние пользовательского интерфейса с картой, нет способа сломать карту:
3. Карта повторяется:
Для итерации свойств простого объекта нам нужны Object.entries () или Object.keys (). Object.entries (plainObject) возвращает массив пар ключ-значение, извлеченных из объекта, мы можем затем деструктурировать эти ключи и значения и получить нормальные ключи и значения на выходе.
Поскольку карты являются итеративными, поэтому нам не нужны методы entry () для итерации по карте и деструктуризации ключа, массив значений может быть выполнен непосредственно на карте, поскольку внутри карты каждый элемент живет как массив пар значений ключа, разделенных запятыми. ,
Также map.keys () возвращает итератор по ключам, а map.values () возвращает итератор по значениям.
4. Мы можем легко узнать размер карты
Мы не можем напрямую определить количество свойств в простом объекте. Нам нужен помощник типа fn, Object.keys (), который возвращает массив с ключами объекта, затем, используя свойство length, мы можем получить количество ключей или размер простого объекта.
Но в случае с Картами мы можем иметь прямой доступ к размеру Карты, используя свойство map.size.
источник
Эти два совета помогут вам решить, использовать ли карту или объект:
Используйте карты над объектами, когда ключи неизвестны до времени выполнения, и когда все ключи имеют одинаковый тип и все значения имеют одинаковый тип.
Используйте карты в случае, если необходимо сохранить значения примитивов в качестве ключей, поскольку объект обрабатывает каждый ключ как строку, либо его числовое значение, либо логическое значение, либо любое другое значение примитива.
Используйте объекты, когда есть логика, которая работает с отдельными элементами.
Источник: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_Collections#Object_and_Map_compared
источник
Это короткий путь для меня, чтобы помнить это: KOI
NaN
и т. Д. Он используется===
для различения ключей, за одним исключением,NaN !== NaN
но вы можете использовать егоNaN
в качестве ключа.[...map]
или[...map.keys()]
есть определенный порядок.obj[key]
илиobj.a
(на каком-то языке,[]
и[]=
действительно являются частью интерфейса). Карта имеетget()
,set()
,has()
, иdelete()
т.д. Обратите внимание , что вы можете использовать ,map[123]
но который использует его как простой объект JS.источник
По словам Мозиллы
Коротко об объекте против карты в JavaScript с примерами.
Объект - следует той же концепции, что и карта, т.е. использует пару ключ-значение для хранения данных. Но есть небольшие отличия, которые делают карту более эффективной в определенных ситуациях.
Карта - это структура данных, которая помогает хранить данные в виде пар. Пара состоит из уникального ключа и значения, сопоставленного с ключом. Это помогает предотвратить двуличие.
Ключевые отличия
источник
Мне
this post
попался Минько Гечев, который четко объясняет основные различия.источник