Carte vs Objet en JavaScript
Je viens de découvrir chromestatus.com et, après avoir perdu plusieurs heures de ma journée, trouvé cette entrée de la fonction:
Carte: les objets de la Carte sont simples clé/valeur des cartes.
Qui me confond. Régulièrement des objets JavaScript sont les dictionnaires, alors comment un Map
différents à partir d'un dictionnaire? Sur le plan conceptuel, ils sont identiques (selon Quelle est la différence entre une Carte et un Dictionnaire?)
La documentation chromestatus références n'aide pas:
Les objets de la carte sont des collections de paires clé/valeur où à la fois les clés et les valeurs peuvent être arbitraire langage ECMAScript valeurs. Une nette valeur de la clé ne peut se produire dans une paire clé/valeur dans la Carte de la collection. De valeurs de clé distinctes en tant que victime de l'aide de l'une comparaison de l'algorithme sélectionné lorsque la Carte est créée.
Une Carte objet peut itérer ses éléments dans l'ordre d'insertion. La carte de l'objet doivent être implémentées à l'aide de tables de hachage ou d'autres mécanismes qui, en moyenne, offrent des temps d'accès qui sont sublinéaire sur le nombre d'éléments dans la collection. Les structures de données utilisées dans cette Carte les objets spécification est uniquement destiné à décrire la nécessaire observables de la sémantique des objets de la Carte. Il n'est pas prévu pour être viable modèle de mise en œuvre.
...sonne toujours comme un objet pour moi, clairement, j'ai raté quelque chose.
Pourquoi JavaScript est d'acquérir une (bien pris en charge) Map
objet? Que faut-il faire?
Vous devez vous connecter pour publier un commentaire.
Selon mozilla:
et
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
La iterability-en-ordre est une fonctionnalité qui a longtemps été voulu par les développeurs, en partie parce qu'il assure le même niveau de performance dans tous les navigateurs. Donc, pour moi, c'est un grand.
La
myMap.has(key)
méthode sera particulièrement utile, et aussi lemyMap.size
propriété.map = Object.create(null)
. Quelles sont les touches par défaut? Comment les clés sont liées àObject.prototype
?new
opérateur pour être utilisé avec leMap
symbole c'est à direnew Map
pour créer un objet map.var a = {}
est une abréviation pour (sens équivalent)var a = Object.create(Object.prototype)
La principale différence est que les Objets de soutien de la chaîne de clés où des Cartes de soutien plus ou moins tout type de clé.
Si je ne obj[123] = true, puis de l'Objet.les touches(obj) alors j'aurai ["123"] plutôt que [123]. Une Carte permettrait de conserver le type de la clé et de retour [123] qui est grand. Des cartes vous permettent aussi d'utiliser des Objets comme des clés. Traditionnellement, pour ce faire, vous avez à donner aux objets une sorte d'identifiant unique de hachage (je ne pense pas que je n'ai jamais rien vu de tel getObjectId en JS dans le cadre de la norme). Des cartes de garantie de maintien de l'ordre sont donc tout rond mieux pour la préservation et peut parfois vous sauver de devoir faire quelques sortes.
Entre les cartes et les objets, dans la pratique, de très de plusieurs avantages et les inconvénients. Objets d'acquérir à la fois des avantages et des inconvénients d'être très bien intégré dans la base de JS qui les distingue de manière significative la Carte au-delà de la différence dans la clé de support.
Un avantage immédiat est que vous avez syntaxique de soutien pour les Objets facilitant l'accès à des éléments. Vous avez également un soutien direct pour avec JSON. Lorsqu'il est utilisé comme une table de hachage, c'est ennuyeux pour obtenir un objet sans propriétés à tous. Par défaut si vous souhaitez utiliser des Objets comme une table de hachage ils seront polluées et vous aurez souvent à l'appel hasOwnProperty sur eux lors de l'accès aux propriétés. Vous pouvez voir ici comment, par défaut, les Objets sont pollués et comment créer espérons-le, non polluées, les objets pour les utiliser comme des hachages:
De la Pollution sur des objets n'est pas seulement quelque chose qui rend le code plus ennuyeux, lent, etc, mais peut également avoir des conséquences potentielles pour la sécurité.
Les objets ne sont pas du pur tables de hachage, mais essayez de faire plus. Vous avez des maux de tête comme hasOwnProperty, de ne pas être en mesure d'obtenir la longueur facilement (Objet.les touches(obj).la longueur) et ainsi de suite. Les objets ne sont pas destinés uniquement être utilisé comme hachage des cartes, mais comme une dynamique évolutive d'Objets et donc quand vous les utilisez comme pure tables de hachage des problèmes surviennent.
Comparaison/Liste des différentes opérations communes:
Il ya quelques autres options, s'approcha, méthodologies, etc, avec des variations de hauts et de bas (la performance, laconique, portable, extensible, etc). Les objets sont un peu étrange au cœur de la langue de sorte que vous avez beaucoup de méthodes statiques pour travailler avec eux.
Outre l'avantage de Cartes en préservant types de clés ainsi que d'être en mesure de soutenir des choses comme des objets comme des clés, ils sont isolés d'effets secondaires que les objets de beaucoup ont. Une Carte est une pure hachage, il n'y a pas de confusion au sujet d'essayer d'être un objet en même temps. Les cartes peuvent également être facilement étendu avec les fonctions de proxy. L'objet actuellement d'une classe Proxy toutefois, le rendement et l'utilisation de la mémoire est sombre, en fait, la création de votre propre proxy qui ressemble à la Carte pour les Objets actuellement plus performante que la Procuration.
Un important désavantage pour les Cartes, c'est qu'ils ne sont pas pris en charge avec JSON directement. L'analyse est possible, mais a plusieurs décrochements:
Ci-dessus va introduire un sérieux gain de performance et sera également pas en charge les clés de chaîne. Encodage JSON est encore plus difficile et problématique (c'est l'une des nombreuses approches):
Ce n'est pas si mal si vous êtes purement à l'aide de Cartes mais ont des problèmes lorsqu'on mélange les types ou de l'utilisation non-valeurs scalaires comme les clés (pas que JSON est parfait avec ce genre de problème tel qu'il est, c'est à dire la circulaire de référence de l'objet). Je n'ai pas testé mais les chances sont qu'il va sérieusement affecter les performances par rapport à stringify.
D'autres langages de script, souvent, n'ont pas ces problèmes car ils sont explicites non scalaire types de Carte, l'Objet et le Tableau. Le développement Web est souvent une douleur avec les types scalaires où vous avez à traiter avec des choses comme PHP fusionne Tableau/Map avec un Objet à l'aide d'Un/M pour les propriétés et les JS fusionne la Carte/Objet avec la Matrice de l'extension M/O. Fusion complexe de types, c'est le diable fléau de haut niveau dans les langages de script.
Jusqu'à présent, ils sont en grande partie les questions autour de la mise en œuvre, mais les performances pour les opérations de base est important. La Performance est également complexe car il dépend du moteur et de l'utilisation. Prendre mes tests avec un grain de sel, car je ne peux pas exclure toute erreur (j'ai plus vite que ce que). Vous devez également exécuter vos propres tests afin de confirmer que la mienne examiner très spécifiques scénarios simples pour donner une indication approximative seulement. Selon des tests en Chrome pour les objets de très grande taille/les cartes de la performance pour les objets est de pire en raison de supprimer ce qui est apparemment d'une certaine manière proportionnelle au nombre de clés au lieu de O(1):
Chrome a clairement un fort avantage avec l'obtention et la mise à jour, mais la suppression de la performance est horrible. Cartes utiliser une petite quantité de mémoire en plus dans ce cas (frais généraux), mais avec un seul Objet/Carte testé avec des millions de clés de l'impact de la surcharge des cartes n'est pas bien exprimé. Avec la gestion de la mémoire les objets également semblent libre plus tôt si je lis le profil correctement ce qui pourrait être un avantage en faveur des objets.
Dans FireFox pour ce test, c'est une autre histoire:
Je doit immédiatement signaler que, dans cette référence de la suppression à partir d'objets dans FireFox n'est pas causer de problèmes, mais dans d'autres repères, il a causé des problèmes surtout quand il y a beaucoup de touches tout comme dans google Chrome. Les cartes sont nettement supérieure dans FireFox pour de grandes collections.
Cependant, ce n'est pas la fin de l'histoire, qu'en de nombreux petits objets ou des cartes? J'ai fait un rapide test de ce mais pas exhaustive (réglage/mise) qui donne les meilleurs résultats avec un petit nombre de clés dans les opérations ci-dessus. Ce test est plus sur la mémoire et l'initialisation.
Encore ces chiffres varient, mais, fondamentalement, l'Objet a une bonne longueur d'avance. Dans certains cas, le plomb pour les Objets de plus de cartes est extrême (~10 fois mieux) mais en moyenne, il était d'environ 2 à 3 fois mieux. Il semble extrême pointes de performance peut fonctionner dans les deux sens. J'ai uniquement testé sur Chrome et création de le profil de l'utilisation de la mémoire et de surcharge. J'ai été assez surpris de voir que dans google Chrome, il semble que les Cartes avec une touche d'environ 30 fois plus de mémoire que les Objets avec une seule clé.
Pour tester un grand nombre de petits objets avec toutes les opérations décrites ci-dessus (4 touches):
En termes d'allocation de mémoire ces se comportaient de la même en termes de libération/GC, mais la Carte utilisée 5 fois plus de mémoire. Ce test utilisé 4 touches où, comme dans le dernier test que j'ai seulement mis une clé, de sorte que cela permettrait d'expliquer la réduction de la surcharge de la mémoire. J'ai couru ce test plusieurs fois et de la Carte/Objet sont plus ou moins du cou et de la nuque pour l'ensemble de Chrome en termes de vitesse. Dans FireFox pour de petits Objets, il y a un réel avantage en termes de performances sur les cartes dans l'ensemble.
Bien sûr, cela n'inclut pas les options individuelles qui peuvent varier énormément. Je ne voudrais pas les conseils de micro-optimisation avec ces chiffres. Ce que vous pouvez sortir de cela est que, en règle générale, considérez les Cartes plus fortement que la très grande valeur de la clé de magasins et d'objets de petite valeur de la clé de magasins.
Au-delà, que la meilleure stratégie avec ces deux à la mise en place et il suffit de faire un travail d'abord. Lors de l'analyse, il est important de garder à l'esprit que, parfois, les choses que vous ne voudriez pas que serait lente lorsque l'on regarde peut être incroyablement lent, à cause de moteur de bizarreries comme on le voit avec la clé de l'objet de la suppression cas.
Je ne pense pas que les points suivants ont été mentionnés dans les réponses, et j'ai pensé qu'ils seraient dignes de mention.
Cartes peuvent être plus importantes
Dans google chrome, je peux obtenir de 16,7 millions de paires clé/valeur avec
Map
vs 11.1 millions de dollars avec un objet normal. Presque exactement 50% de plusieurs paires avec unMap
. Ils ont tous deux prendre environ 2 go de mémoire avant leur effondrement, et donc je pense peut-être à voir avec la mémoire de limiter par chrome (Modifier: Yep, essayez de remplissage 2Maps
et vous obtenez seulement à 8,3 millions de paires chaque avant de planter). Vous pouvez tester vous-même avec ce code (exécuter séparément, et non pas en même temps, évidemment):Objets ont certaines propriétés/clés déjà
Celui-ci a déclenché moi avant. Les objets ordinaires ont
toString
,constructor
,valueOf
,hasOwnProperty
,isPrototypeOf
et un tas d'autres pré-propriétés existantes. Cela peut ne pas être un gros problème pour la plupart des cas, mais il a causé des problèmes pour moi avant.Les cartes peuvent être plus lent:
En raison de la
.get
appel de fonction, les frais généraux et le manque de contrôle interne de l'optimisation, de la Carte peut-être considérablement plus lent qu'un simple vieux objet JavaScript pour certaines tâches.toString
,constructor
, etc. (c'est à dire vos clés sont extrêmement peu de chances d'entrer en collision avec eux). Ils sont plus faciles à travailler, par exemple par incrément estobj[i] = (obj[i] || 0) + 1
, alors qu'avecMap
c'estmap.set(i, (map.get(i) || 0) + 1)
qui n'est toujours pas trop mal, mais cela montre simplement comment les choses peuvent devenir inutilement en désordre. Les cartes sont certainement les cas d'utilisation, mais, souvent, un simple objet de faire.toString
,constructor
, (etc.) les propriétés de l'objet par écritobj = Object.create(null)
au lieu deobj = {}
.En plus des autres réponses, j'ai trouvé que les Cartes sont plus lourd et verbeux pour fonctionner avec des objets.
C'est important, parce que plus court code est plus rapide à lire, plus directement expressif, et mieux conservés dans le programmeur de la tête.
Un autre aspect: parce que set() retourne la carte, et non la valeur, il est impossible de la chaîne d'affectations.
Le débogage des cartes est également de plus en plus douloureux. Ci-dessous, vous ne pouvez pas voir ce que les clés sont dans la carte. Vous devez écrire du code pour le faire.
Les objets peuvent être évaluées par une IDE:
Résumé:
Object
: Une structure de données dans laquelle les données sont stockées comme des paires clé-valeur. Dans un objet, la clé est d'être un nombre, une chaîne, ou un symbole. La valeur peut être n'importe quoi, donc aussi d'autres objets, fonctions, etc. Un objet est un non commandé structure de données, c'est à dire la séquence d'insertion des paires clé-valeur n'est pas souvenu deES6 Map
: Une structure de données dans laquelle les données sont stockées comme des paires clé-valeur. En ce qui une clé unique de cartes pour une valeur. À la fois la clé et la valeur peut être dans tout type de données. Une carte est un objet iterable structure de données, cela signifie que la séquence d'insertion est de rappeler et que l'on peut accéder aux éléments, par exemplefor..of
bouclePrincipales différences:
Un
Map
est ordonné et itératif, alors qu'un des objets n'est pas commandé et non itératifOn peut mettre n'importe quel type de données comme un
Map
clé, tandis que les objets ne peuvent avoir qu'un nombre, une chaîne, ou un symbole comme une clé.Un
Map
hérite deMap.prototype
. Cette offre toutes sortes de fonctions d'utilité et de propriétés qui permet de travailler avecMap
des objets beaucoup plus facile.Exemple:
objet:
JS:
Carte:
JS:
source: MDN
Les objets peuvent se comporter comme des dictionnaires, car le Javascript est dynamiquement typé, mais ils ne sont vraiment pas destiné à être.
La nouvelle
Map()
fonctionnalité est beaucoup plus agréable, car il est normal deget/set/has/delete
méthodes, accepte tout type de la remise des clés au lieu de simplement les chaînes, plus facile à utiliser lors de l'itération, et il n'a pas de bord de cas à l'aide de prototypes et d'autres propriétés qui se montre. Il est aussi très rapide et ne cesse de devenir plus rapide que les moteurs de mieux. 99% du temps, vous devriez utiliser unMap()
.Toutefois, si vous êtes seulement en utilisant la chaîne de clés et besoin d'un maximum de performances de lecture, puis les objets peuvent être un meilleur choix. Le détail est que (presque tous) les moteurs javascript compiler les objets vers le bas pour les classes C++ en arrière-plan. Ces types sont mis en cache et réutilisé par leur "plan", de sorte que lorsque vous créer un nouvel objet avec les mêmes propriétés exactes le moteur de réutiliser une classe d'arrière-plan. Le chemin d'accès pour les propriétés de ces classes est très optimisé et beaucoup plus rapide que la recherche d'un
Map()
.L'ajout ou la suppression d'une propriété entraîne la mise en cache de la sauvegarde de la classe à la re-compilation, qui est pourquoi l'aide d'un objet comme un dictionnaire avec beaucoup de principaux ajouts et des suppressions est très lent, mais les lectures et l'attribution des clés existantes, sans modification de l'objet sont très rapides.
Donc si vous avez une écriture, une fois lu-lourde charge de travail avec des clés de chaîne d'utiliser ensuite une
object
en tant qu'institution spécialisée de haute performance dictionnaire, mais pour tout le reste d'utiliser uneMap()
.En outre à être itératif dans un ordre précis, et la capacité d'utiliser des valeurs arbitraires que les clés (à l'exception de
-0
), les cartes peuvent être utile pour les raisons suivantes:La spec applique carte des opérations sublinéaire en moyenne.
Non stupide de mise en œuvre de l'objet de l'utilisation d'une table de hachage ou similaire, de sorte que la propriété recherches seront probablement être constante en moyenne. Ensuite, les objets pourraient être encore plus rapide que les cartes. Mais ce n'est pas requis par la spécification.
Les objets peuvent avoir de mauvaises comportements inattendus.
Par exemple, disons que vous n'avez défini aucune
foo
propriété à un objet nouvellement crééobj
, donc, vous vous attendezobj.foo
de retour indéfini. Maisfoo
pourrait être intégré dans la propriété héritée deObject.prototype
. Ou vous essayez de créerobj.foo
à l'aide d'une cession, mais certains setter dansObject.prototype
s'exécute au lieu de stockage de votre valeur.Cartes de prévenir ce genre de choses. Eh bien, sauf si un script mess avec
Map.prototype
. EtObject.create(null)
serait trop de travail, mais alors vous perdez le simple objet d'initialiseur de syntaxe.Ces deux conseils peuvent vous aider à décider de l'utilisation d'une Carte ou d'un Objet:
Utiliser des cartes au-dessus des objets lorsque les clés sont inconnues jusqu'à ce moment de l'exécution, et quand
toutes les touches sont du même type et de toutes les valeurs sont du même type.
Utiliser des cartes dans le cas où si il y a un besoin de stocker des valeurs primitives comme des clés
parce que l'objet traite chaque touche comme une chaîne de caractères, soit de ses un certain nombre de valeur,
valeur booléenne ou toute autre valeur primitive.
Utiliser des objets quand il y a une logique qui opère sur les différents éléments.
Source:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_Collections#Object_and_Map_compared