【Перевод】Сходства и различия между Объектом и Картой и сценарии их использования

ECMAScript 6

Это второй перевод в серии, посвященной Array, Set, Object, Map.
Оригинальная ссылка:кликните сюда
По соглашению подробный API добавлен внизу статьи.

Вам может быть интересно, почему объекты и карты сравниваются по отдельности, а не карты, массивы или объекты и наборы? В отличие от двух других групп, карта и объект имеют много общего, что требует от нас более глубокого понимания и сравнения, чтобы проанализировать их более подходящие сценарии применения.

концепция

Что такое карта

Карта — это структура данных (это специальный абстрактный тип структуры данных), в которой данные хранятся попарно, содержащие ключ и значение, сопоставленное с этим ключом. А из-за уникальности ключей не существует повторяющихся пар ключ-значение.
Карта была создана для быстрого поиска и поиска данных.
Например:{(1, "smile"), (2, "cry"), (42, "happy")}

В Map каждая пара данных представлена ​​в виде пар ключ-значение.

Примечание: Ключи и значения в Карте могут быть любого типа данных, не ограничиваясь строками или целыми числами.

Что такое объект

в JavaScriptобычный объектявляется структурой данных словарного типа, что означает, что она по-прежнему следует той же структуре хранения ключ-значение, что и тип карты. Ключ в объекте, или мы можем назвать его свойством, также уникален и соответствует одному значению.

Кроме того, Object в JavaScript имеет встроенный прототип (prototype). Следует отметить, что почти все объекты в JavaScript являются экземплярами Object, включая Map.
Например:{1: 'smile', 2: 'cry', 42: 'happy'}

С точки зрения определения суть Object и Map заключается в хранении данных в виде пар ключ-значение, но по сути между ними есть большая разница——

  • Ключи: объект следует обычным правилам словаря, ключи должны быть одного типа и могут быть только целочисленными, строковыми или символьными. Но в Map ключ может быть любого типа данных (Object, Array и т.д.). (Вы можете попробовать установить объект в качестве ключа объекта, чтобы увидеть окончательную структуру данных)
  • Порядок элементов: Map сохраняет порядок всех элементов, а Object не гарантирует порядок свойств. (Если есть сомнения, см.:Связь)
  • Наследование: Map является экземпляром объекта Object, а Object, очевидно, не может быть экземпляром объекта Map.
var map = new Map([[1,2],[3,4]]);
console.log(map instanceof Object); //true
var obj = new Object();
console.log(obj instanceof Map); //false

как построить

Object

Как и в случае с массивами, способ определения объекта очень прост и понятен:

var obj = {}; //空对象
var obj = {id: 1, name: "Test object"}; 
//2 keys here: id maps to 1, and name maps to "Test object"

Или используйте конструктор:

var obj = new Object(); //空对象
var obj = new Object; //空对象

или использоватьObject.prototype.create

var obj = Object.create(null); //空对象

Примечание:
вы можете использовать его только в определенных обстоятельствахObject.prototype.create,Например:

  • Вы хотите наследовать от объекта-прототипа, не определяя его конструктор.
var Vehicle = {
    type: "General",
    display: function(){console.log(this.type);}
}
var Car = Object.create(Vehicle); //创建一个继承自Vehicle的对象Car
Car.type = "Car";  //重写type属性
Car.display(); //Car
Vehicle.display(); //General

В целом, как и в случае с массивами, старайтесь избегать использования конструкторов по следующим причинам:

  • Конструкторы пишут больше кода
  • худшая производительность
  • Большая путаница с большей вероятностью вызовет программные ошибки, такие как:
var obj = new Object(id: 1, name: "test") //显然的语法错误

var obj1 = {id: 1, name: "test"};
var obj2 = new Object(obj1); //obj1与obj2指向同一个对象
obj2.id = 2;
console.log(obj1.id); //2

Map

Существует только один способ создать Карту, используя встроенный конструктор иnewграмматика.

var map = new Map(); //Empty Map
var map = new Map([[1,2],[2,3]]); // map = {1=>2, 2=>3}

грамматика:

Map([iterable])

Конструктор Map принимает в качестве параметра массив или проходимый объект, а данные в этом параметре представляют собой структуру пары ключ-значение. Если это массив, то он содержит два элемента[key, value].

Элемент доступа

  • Для Map получить элементы через методMap.prototype.get(key)Реализация, что означает, что мы должны сначала знать ключ, соответствующий значению
map.get(1);
  • Объект аналогичен, чтобы получить значение, вы должны сначала знать соответствующий ключ/свойство, но использовать другой синтаксис:Object.<key> and Object[‘key’]
obj.id //1
obj['id'] //1
  • Определить, существует ли ключ на карте
map.has(1);//return boolean value:  true/false
  • Объект требует некоторого дополнительного суждения
var isExist = obj.id === undefined; 

// or
var isExist = 'id' in obj; // 该方法会检查继承的属性

Карта очень похожа на синтаксис объекта, но синтаксис карты проще.

Примечание: мы можем использоватьObject.prototype.hasOwnProperty()Определить, существует ли конкретный ключ в объекте, и его возвращаемое значение равноtrue/false,а такжебудет проверять только неунаследованные свойства объекта.

вставить элемент

  • Поддержка карты черезMap.prototype.set()Метод вставляет элемент, метод получает два параметра: ключ, значение. Если передается существующий ключ, значение, соответствующее ключу, будет перезаписано.
map.set(4,5); 
  • Точно так же для добавления свойств к объекту можно использовать следующий метод.
obj['gender'] = 'female'; //{id: 1, name: "test", gender: "female"}
obj.gender = male; // 重写已存在的属性
//{id: 1, name: "test", gender: "male"}

Как видите, благодаря своей структуре данных оба метода вставки элементов имеют временную сложность O(1), а получение ключа не требует обхода всех данных.

удалить элемент

Объект не предоставляет встроенного метода для удаления элементов, мы можем использоватьdeleteграмматика:

delete obj.id;

Стоит отметить, что многие люди спрашивали, будет ли лучше и менее эффективно использовать следующий метод.

obj.id = undefined

Существует большая разница в логике между этими двумя способами:

  • deleteПолностью удалит определенное свойство объекта.
  • использоватьobj[key] = undefinedТолько значение, соответствующее этому ключу, будет изменено наundefined, а свойство остается в объекте.

Итак, используяfor...in...Ключ свойства по-прежнему будет проходиться при цикле.

Конечно, проверка, если свойство уже существует в объекте, даст два разных результата в этих двух случаях, за исключением следующих проверок:

obj.id === undefined; //结果相同

Поэтому повышение производительности в некоторых случаях не подходит.

Еще кое-что,deleteВозвращаемое значение оператораtrue/false, но основа его возвращаемого значения отличается от ожидаемой ситуации:
возврат на все случаиtrue, если атрибут не являетсяnon-configurableсвойство, в противном случае возвращается в нестрогом режимеfalse, в строгом режиме будет выдано исключение.

Карта имеет больше встроенных способов удаления элементов, таких как:

  • delete(key)Этот метод, используемый для удаления значения, соответствующего определенному ключу, с Карты, возвращает логическое значение. Возвращает, если указанный ключ существует в целевом объекте и успешно удален.true; вернуть, если ключ не существует в объектеfalse.
var isDeleteSucceeded = map.delete(1);
console.log(isDeleteSucceeded); //true- 
  • clear()- Очистить все элементы на карте.
map.clear();

Объект для реализации Картаclear()вам нужно просмотреть свойства этого объекта и удалить их одно за другим.

Методы удаления элементов из Object и Map также очень похожи. Временная сложность удаления элемента составляет O(1), а временная сложность очистки элемента — O(n), где n — размер объекта и карты.

получить размер

Одним из преимуществ Map по сравнению с Object является то, что он может автоматически обновлять свой размер, чего мы легко можем добиться:

console.log(map.size);

С Object нам нужно пройтиObject.keys()Метод вычисляет его размер, который возвращает массив, содержащий все ключи.

console.log(Object.keys(obj).length);

Итерация элементов

Map имеет встроенные итераторы, Object не имеет встроенных итераторов.
Дополнение: Как определить, является ли тип итерируемым, можно реализовать следующими способами

//typeof <obj>[Symbol.iterator] === “function”
console.log(typeof obj[Symbol.iterator]); //undefined
console.log(typeof map[Symbol.iterator]); //function

На карте ко всем элементам можно получить доступ черезfor...ofМетод обхода:

//For map: { 2 => 3, 4 => 5 }
for (const item of map){
    console.log(item); 
    //Array[2,3]
    //Array[4,5]
}
//Or
for (const [key,value] of map){
    console.log(`key: ${key}, value: ${value}`);
    //key: 2, value: 3
    //key: 4, value: 5
}

или используйте его встроенныйforEach()метод:

map.forEach((value, key) => console.log(`key: ${key}, value: ${value}`));
//key: 2, value: 3
//key: 4, value: 5

Но для объекта мы используемfor...inметод

//{id: 1, name: "test"}
for (var key in obj){
   console.log(`key: ${key}, value: ${obj[key]}`);
   //key: id, value: 1
   //key: name, value: test
}

или использоватьObject.keys(obj)Только получить все ключи и пройти

Object.keys(obj).forEach((key)=> console.log(`key: ${key}, value: ${obj[key]}`));
//key: id, value: 1
//key: name, value: test

Итак, возникает вопрос, поскольку они очень похожи по структуре и производительности, Map имеет больше преимуществ перед Object, поэтому следует ли нам чаще использовать Map вместо Object?

Сценарии применения Объекта и Карты

Хотя Map имеет много преимуществ перед Object, все же есть сценарии, в которых Object лучше, ведь Object — это самая основная концепция в JavaScript.

  • Если вы знаете все ключи, это строки или целые числа (или типы символов), и вам нужна простая структура для хранения этих данных, Object — очень хороший выбор. Построение объекта и выборка элемента, зная конкретный ключ, лучше, чем карта (литерал против конструктора, прямая выборка противget()метод).
  • Если вам нужно поддерживать свою собственную уникальную логику и свойства в объекте, вы можете использовать только Object.
var obj = {
    id: 1, 
    name: "It's Me!", 
    print: function(){ 
        return `Object Id: ${this.id}, with Name: ${this.name}`;
    }
}
console.log(obj.print());//Object Id: 1, with Name: It's Me.

(Вы можете попробовать это с Map, но Map не реализует такую ​​структуру данных)

  • JSON поддерживает Object напрямую, но еще не Map. Поэтому Object следует рассматривать как первый выбор в некоторых случаях, когда нам приходится использовать JSON.
  • Map是一个纯哈希结构,而Object不是(它拥有自己的内部逻辑)。 использоватьdeleteСуществует много проблем с производительностью при удалении свойств объекта. Поэтому для сценариев с большим количеством добавлений и удалений целесообразнее использовать Map.
  • В отличие от Object, Map сохраняет порядок всех элементов. Структура карты построена на итерационной основе, поэтому, если рассматривается итерация или порядок элементов, лучше использовать карту, которая обеспечивает итеративную производительность во всех браузерах.
  • Карты работают лучше в сценариях, где хранятся большие объемы данных, особенно когда ключи неизвестны и все ключи и все значения относятся к одному типу.

Суммировать

Способ выбора объекта и карты зависит от типа данных и операции, которую вы хотите использовать.

Когда нам нужна только простая структура хранения поиска, Map имеет преимущество перед Object, она обеспечивает все основные операции. Но Map ни в коем случае не заменяет Object. Потому что в Javascript Object — это не просто обычная хэш-таблица (поэтому Object не следует использовать как обычную хеш-таблицу, это приведет к потере большого количества ресурсов).

Другие информационные ссылки:
Object - MDN - Mozilla
Map - MDN - Mozilla
Начало работы с ES6 — Жуан Ифэн