Я только что обнаружил chromestatus.com и, потеряв несколько часов своего дня, нашел эту запись функции:
... все еще звучит как объект для меня, так что я пропустил что-то.
Ответ 2
Ключевое различие заключается в том, что объекты поддерживают только строковые ключи, где в качестве карт более или менее поддерживается любой тип ключа.
Если я делаю obj [123] = true, а затем Object.keys(obj), тогда я получу [ "123" ], а не [123]. Карта сохранит тип ключа и вернет [123], что отлично. Карты также позволяют использовать объекты как ключи. Традиционно для этого вам нужно было бы предоставить объектам какой-то уникальный идентификатор для их хэша (я не думаю, что когда-либо видел что-то вроде getObjectId в JS как часть стандарта). Карты также гарантируют сохранение порядка, так что все вокруг лучше для сохранения и иногда может сэкономить вам нужно сделать несколько видов.
Между картами и объектами на практике очень много плюсов и минусов. Объекты получают как преимущества, так и недостатки, которые очень тесно интегрированы в ядро JS, что отличает их от существенной карты за пределами разницы в поддержке ключей.
Непосредственным преимуществом является то, что у вас есть синтаксическая поддержка для объектов, упрощающих доступ к элементам. У вас также есть прямая поддержка с JSON. При использовании в качестве хеша раздражает получение объекта без каких-либо свойств. По умолчанию, если вы хотите использовать объекты в качестве хеш-таблицы, они будут загрязнены, и вам часто придется вызывать hasOwnProperty при их доступе к свойствам. Вы можете увидеть здесь, как по умолчанию объекты загрязнены и как создать надежно незагрязненные объекты для использования в качестве хэшей:
({}).toString
toString() { [native code] }
JSON.parse('{}').toString
toString() { [native code] }
(Object.create(null)).toString
undefined
JSON.parse('{}', (k,v) => (typeof v === 'object' && Object.setPrototypeOf(v, null) ,v)).toString
undefined
Загрязнение объектов - это не только то, что делает код более раздражающим, медленным и т.д., но также может иметь потенциальные последствия для безопасности.
Объекты не являются чистыми хеш-таблицами, но пытаются сделать больше. У вас есть головные боли, такие как hasOwnProperty, неспособность легко получить длину (Object.keys(obj).length) и так далее. Объекты не предназначены исключительно для использования в качестве хеш-карт, но как динамические расширяемые объекты, поэтому, когда вы используете их как чистые хеш-таблицы, возникают проблемы.
Сравнение/Список различных общих операций:
Object:
var o = {};
var o = Object.create(null);
o.key = 1;
o.key += 10;
for(let k in o) o[k]++;
var sum = 0;
for(let v of Object.values(m)) sum += v;
if('key' in o);
if(o.hasOwnProperty('key'));
delete(o.key);
Object.keys(o).length
Map:
var m = new Map();
m.set('key', 1);
m.set('key', m.get('key') + 10);
m.foreach((k, v) => m.set(k, m.get(k) + 1));
for(let k of m.keys()) m.set(k, m.get(k) + 1);
var sum = 0;
for(let v of m.values()) sum += v;
if(m.has('key'));
m.delete('key');
m.size();
Есть несколько других вариантов, подход, методологии и т.д. с различными взлетами и падениями (производительность, краткость, переносимость, возможность расширения и т.д.). Объекты немного странны, будучи ядром языка, поэтому у вас есть много статических методов для работы с ними.
Помимо преимуществ Карт, сохраняющих ключевые типы, а также возможность поддержки таких вещей, как объекты в качестве ключей, они изолированы от побочных эффектов, которые много объектов. Карта - это чистый хеш, нет путаницы в попытке быть объектом одновременно. Карты также могут быть легко расширены с помощью прокси-функций. Объект в настоящее время имеет класс Proxy, однако производительность и использование памяти являются мрачными, фактически создавая свой собственный прокси, который выглядит так, как Map for Objects в настоящее время работает лучше, чем Proxy.
Существенным недостатком для Maps является то, что они не поддерживаются напрямую JSON. Разбор возможен, но имеет несколько зависаний:
JSON.parse(str, (k,v) => {
if(typeof v !== 'object') return v;
let m = new Map();
for(k in v) m.set(k, v[k]);
return m;
});
Приведенное выше приведет к серьезному поражению производительности, а также не будет поддерживать любые строковые ключи. Кодирование JSON еще сложнее и проблематично (это один из многих подходов):
// An alternative to this it to use a replacer in JSON.stringify.
Map.prototype.toJSON = function() {
return JSON.stringify({
keys: Array.from(this.keys()),
values: Array.from(this.values())
});
};
Это не так плохо, если вы используете только Карты, но будете иметь проблемы при смешивании типов или использовании нескалярных значений в качестве ключей (не то, что JSON идеально подходит с такой проблемой, как она есть, круговой объект IE Справка). Я не тестировал его, но есть вероятность, что он сильно повредит производительность по сравнению с строкой.
Другие языки сценариев часто не имеют таких проблем, поскольку у них есть явные нескалярные типы для Map, Object и Array. Веб-разработка часто представляет собой боль с нескалярными типами, где вам приходится иметь дело с такими вещами, как PHP, объединяет Array/Map with Object с использованием A/M для свойств, а JS объединяет Map/Object с массивом, расширяющим M/O. Слияние сложных типов - это дьявольский провал языков сценариев высокого уровня.
До сих пор это в основном проблемы, связанные с внедрением, но также важны рабочие характеристики для основных операций. Производительность также сложна, поскольку она зависит от двигателя и использования. Проводите мои испытания с солью, потому что я не могу исключить какую-либо ошибку (я должен спешить с этим). Вы также должны запустить свои собственные тесты, чтобы подтвердить, поскольку мои рассматривают только очень специфические простые сценарии, чтобы дать приблизительное указание. Согласно испытаниям в Chrome для очень больших объектов/карт производительность для объектов хуже из-за удаления, которое, по-видимому, каким-то образом пропорционально количеству ключей, а не O (1):
Object Set Took: 146
Object Update Took: 7
Object Get Took: 4
Object Delete Took: 8239
Map Set Took: 80
Map Update Took: 51
Map Get Took: 40
Map Delete Took: 2
У Chrome явно есть сильное преимущество при получении и обновлении, но производительность удаления ужасающая. Карты используют в этом случае меньшую сумму памяти (накладные расходы), но при тестировании только одного объекта/карты с миллионами ключей влияние накладных расходов для карт не выражается хорошо. С объектами управления памятью также, кажется, освобождается раньше, если я правильно читаю профиль, который может быть одним из преимуществ в пользу объектов.
В FireFox для этого конкретного теста это совсем другая история:
Object Set Took: 435
Object Update Took: 126
Object Get Took: 50
Object Delete Took: 2
Map Set Took: 63
Map Update Took: 59
Map Get Took: 33
Map Delete Took: 1
Я должен сразу указать, что в этом конкретном тесте, удаляющем объекты из FireFox, не возникает никаких проблем, однако в других тестах это вызвало проблемы, особенно когда есть много ключей, как в Chrome. Карты значительно превосходят FireFox для больших коллекций.
Однако это еще не конец истории, что о многих маленьких объектах или картах? Я сделал быстрый тест, но не исчерпывающий (настройка/получение) которого лучше всего работает с небольшим количеством клавиш в вышеуказанных операциях. Этот тест больше связан с памятью и инициализацией.
Map Create: 69 // new Map
Object Create: 34 // {}
Снова эти цифры меняются, но в основном у Object есть хорошее преимущество. В некоторых случаях лидерство над объектами над картами является экстремальным (в 10 раз лучше), но в среднем он был примерно в 2-3 раза лучше. Похоже, экстремальные всплески производительности могут работать в обоих направлениях. Я только проверял это в Chrome и создании для использования памяти памяти и накладных расходов. Я был очень удивлен, увидев, что в Chrome кажется, что Карты с одним ключом используют в 30 раз больше памяти, чем объекты с одним ключом.
Для тестирования многих мелких объектов со всеми вышеперечисленными операциями (4 ключа):
Chrome Object Took: 61
Chrome Map Took: 67
FireFox Object Took: 54
FireFox Map Took: 139
В терминах распределения памяти они вели себя одинаково с точки зрения освобождения /GC, но Map использовал в 5 раз больше памяти. В этом тесте использовались 4 ключа, где, как и в последнем тесте, я установил только один ключ, чтобы это объясняло сокращение накладных расходов памяти. Я провел этот тест несколько раз, а Map/Object больше или меньше шеи и шеи в целом для Chrome с точки зрения общей скорости. В FireFox для небольших объектов существует определенное преимущество в производительности по сравнению с картами в целом.
Это, конечно, не включает отдельные варианты, которые могут сильно различаться. Я бы не советовал микро-оптимизировать эти цифры. Из этого можно сделать вывод, что, как правило, более внимательно рассмотрите Карты для очень больших хранилищ значений ключей и объектов для небольших хранилищ значений ключей.
Помимо того, что лучшая стратегия с этими двумя она реализует ее и просто заставляет ее работать в первую очередь. При профилировании важно иметь в виду, что иногда вещи, которые вы не думаете, будут медленными при взгляде на них, могут быть невероятно медленными из-за причудности двигателя, как видно в случае удаления объекта объекта.