Maison  >  Article  >  interface Web  >  Une brève discussion sur la façon d'utiliser la carte au lieu d'objets JS purs

Une brève discussion sur la façon d'utiliser la carte au lieu d'objets JS purs

青灯夜游
青灯夜游avant
2020-12-02 18:06:464902parcourir

Une brève discussion sur la façon d'utiliser la carte au lieu d'objets JS purs

L'objet JavaScript brut {key: 'value'} peut être utilisé pour enregistrer des données structurées.

Mais une chose que je trouve très énervante : les clés des objets doivent être des chaînes (ou des symboles rarement utilisés).

Que se passerait-il si les chiffres étaient utilisés comme clés ? Il n'y a pas d'erreur dans ce cas :

const names = {
  1: 'One',
  2: 'Two',
};

Object.keys(names); // => ['1', '2']

JavaScript convertit simplement implicitement les clés de l'objet en chaînes. C'est une chose délicate car vous perdez la cohérence du type.

Dans cet article, j'expliquerai comment l'objet JavaScript Map disponible dans ES2015 résout de nombreux problèmes des objets ordinaires, y compris la conversion des clés en chaînes.

1. la carte accepte les clés de tout type

Comme mentionné ci-dessus, si la clé de l'objet n'est pas une chaîne ou un symbole, JavaScript la convertira implicitement en chaîne.

Heureusement, map n'a aucun problème avec les types de clés :

const numbersMap = new Map();

numbersMap.set(1, 'one');
numbersMap.set(2, 'two');

[...numbersMap.keys()]; // => [1, 2]

1 et 2 sont des clés dans numbersMap. Le type de ces clés numéro reste inchangé.

Vous pouvez utiliser n'importe quel type de clé dans une carte : nombres, booléens et chaînes et symboles classiques.

const booleansMap = new Map();

booleansMap.set(true, "Yep");
booleansMap.set(false, "Nope");

[...booleansMap.keys()]; // => [true, false]

booleansMap Il n'y a aucun problème à utiliser des valeurs booléennes comme clés.

De même, les touches booléennes ne fonctionnent pas dans les objets normaux.

Repoussons les limites : peut-on utiliser un objet entier comme clé dans une carte ? bien sûr!

1.1 Utiliser des objets comme clés

Supposons que vous deviez stocker certaines données liées à l'objet, mais ne attachez pas les données à l'objet lui-même.

Impossible de faire cela avec des objets normaux.

Une solution consiste à utiliser un tuple de valeurs d'objet :

const foo = { name: 'foo' };
const bar = { name: 'bar' };

const kindOfMap = [
  [foo, 'Foo related data'],
  [bar, 'Bar related data'],
];

kindOfMap est un tableau contenant une paire d'objets et des valeurs associées.

Le plus gros problème de cette approche est que la complexité temporelle de l'accès à la valeur par clé est O(n) . Vous devez parcourir l'ensemble du tableau pour obtenir la valeur souhaitée par clé :

function getByKey(kindOfMap, key) {
  for (const [k, v] of kindOfMap) {
    if (key === k) {
      return v;
    }
  }
  return undefined;
}

getByKey(kindOfMap, foo); // => 'Foo related data'

Avec WeakMap (une version spécialisée de Map), vous n'avez pas besoin de vous en préoccuper. Il accepte les objets comme clés. La principale différence entre

Map et WeakMap est que ce dernier permet le garbage collection de l'objet qui est la clé, évitant ainsi les fuites de mémoire.

Le coût de refactorisation du code ci-dessus pour utiliser WeakMap est trivial :

const foo = { name: 'foo' };
const bar = { name: 'bar' };

const mapOfObjects = new WeakMap();

mapOfObjects.set(foo, 'Foo related data');
mapOfObjects.set(bar, 'Bar related data');

mapOfObjects.get(foo); // => 'Foo related data'

Contrairement à Map, WeakMap n'accepte que les objets comme clés et a Simplifié ensemble de méthodes.

2. La carte n'a aucune restriction sur les noms de clés.

Tout objet en JavaScript hérite des propriétés de son objet prototype. Il en va de même pour les objets JavaScript classiques.

Si vous remplacez les propriétés héritées du prototype, vous pouvez casser le code qui dépend de ces propriétés du prototype :

function isPlainObject(value) {
  return value.toString() === '[object Object]';
}

const actor = {
  name: 'Harrison Ford',
  toString: 'Actor: Harrison Ford'
};

// Does not work!
isPlainObject(actor); // TypeError: value.toString is not a function

Propriétés actor définies sur l'objet toString remplace l'héritage du prototype. toString() méthode. Parce qu'il repose sur la méthode toString(), cela casse isObject().

Consultez la liste des propriétés et méthodes dont les objets ordinaires héritent du prototype. Évitez d'utiliser ces noms pour définir des propriétés personnalisées.

Par exemple, imaginez que vous disposez d'une interface utilisateur qui gère certains champs personnalisés. Les utilisateurs peuvent ajouter des champs en spécifiant un nom et une valeur :

Une brève discussion sur la façon dutiliser la carte au lieu dobjets JS purs

Il serait pratique de stocker l'état du champ personnalisé dans un objet normal :

const userCustomFields = {
  'color':    'blue',
  'size':     'medium',
  'toString': 'A blue box'
};

Mais l'utilisateur peut choisir un nom de champ personnalisé tel que toString (comme indiqué dans l'exemple), constructor etc., ce qui peut casser votre objet.

Ne créez pas de clés sur des objets normaux en acceptant les entrées de l'utilisateur !

la carte n'a pas ce problème. Le nom de la clé est illimité :

function isMap(value) {
  return value.toString() === '[object Map]';
}

const actorMap = new Map();

actorMap.set('name', 'Harrison Ford');
actorMap.set('toString', 'Actor: Harrison Ford');

// Works!
isMap(actorMap); // => true

La méthode actorMap fonctionne indépendamment du fait que toString possède ou non une propriété nommée toString().

3. la carte est itérable

Afin de parcourir les propriétés d'un objet normal, vous devez utiliser d'autres fonctions statiques auxiliaires, telles que Object.keys() ou Object.entries() (disponibles dans ES2017). ):

const colorsHex = {
  'white': '#FFFFFF',
  'black': '#000000'
};

for (const [color, hex] of Object.entries(colorsHex)) {
  console.log(color, hex);
}
// 'white' '#FFFFFF'
// 'black' '#000000'

Object.entries(colorsHex) Renvoie un tableau de paires clé-valeur extraites de l'objet.

Cependant, la carte elle-même est itérable :

const colorsHexMap = new Map();

colorsHexMap.set('white', '#FFFFFF');
colorsHexMap.set('black', '#000000');

for (const [color, hex] of colorsHexMap) {
  console.log(color, hex);
}
// 'white' '#FFFFFF'
// 'black' '#000000'

colorsHexMap est itérable. Vous pouvez l'utiliser n'importe où itérable : for() boucles, opérateur de propagation [...map] etc.

map fournit également d'autres méthodes pour renvoyer des itérations : map.keys() pour les clés et map.values() pour les valeurs.

4. map的大小

普通对象的另一个问题是你无法轻松确定其拥有的属性数量:

const exams = {
  'John Smith': '10 points',
  'Jane Doe': '8 points',
};

Object.keys(exams).length; // => 2

要确定 exams 的大小,你必须通过它所有键来确定它们的数量。

map 提供了一种替代方法,通过它的访问器属性 size 计算键值对:

const examsMap = new Map([
  ['John Smith', '10 points'],
  ['Jane Doe', '8 points'],
]);
  
examsMap.size; // => 2

确定 map 的大小更加简单:examsMap.size

5.结论

普通的 JavaScript 对象通常可以很好地保存结构化数据。但是它们有一些限制:

  1. 只能用字符串或符号用作键
  2. 自己的对象属性可能会与从原型继承的属性键冲突(例如,toStringconstructor 等)。
  3. 对象不能用作键

所有这些问题都可以通过 map 轻松解决。而且它们提供了诸如迭代器和易于进行大小查找之类的好处。

不要将 map 视为普通对象的替代品,而应视为补充。

你知道 map 相对于普通对象的其他好处吗?请在下面写下你的评论!

原文地址:https://dmitripavlutin.com/maps-vs-plain-objects-javascript/

译文地址:https://segmentfault.com/a/1190000020660481

更多编程相关知识,请访问:编程课程!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer