web-dev-qa-db-fra.com

Pourquoi arr = [] est-il plus rapide que arr = new Array?

J'ai couru ce code et obtenu le résultat ci-dessous. Je suis curieux de savoir pourquoi [] est plus rapide?

console.time('using[]')
for(var i=0; i<200000; i++){var arr = []};
console.timeEnd('using[]')

console.time('using new')
for(var i=0; i<200000; i++){var arr = new Array};
console.timeEnd('using new')
  • en utilisant []: 299ms
  • en utilisant new: 363ms

Grâce à Raynos , voici un test de performance de ce code et un moyen plus possible de définir une variable.

enter image description here

143
Mohsen

Développer davantage les réponses précédentes ...

Du point de vue général des compilateurs et sans tenir compte des optimisations spécifiques aux ordinateurs virtuels:

Premièrement, nous passons à la phase d’analyse lexicale où nous tokenisons le code.

A titre d'exemple, les jetons suivants peuvent être produits:

[]: ARRAY_INIT
[1]: ARRAY_INIT (NUMBER)
[1, foo]: ARRAY_INIT (NUMBER, IDENTIFIER)
new Array: NEW, IDENTIFIER
new Array(): NEW, IDENTIFIER, CALL
new Array(5): NEW, IDENTIFIER, CALL (NUMBER)
new Array(5,4): NEW, IDENTIFIER, CALL (NUMBER, NUMBER)
new Array(5, foo): NEW, IDENTIFIER, CALL (NUMBER, IDENTIFIER)

J'espère que cela devrait vous fournir une visualisation suffisante pour que vous puissiez comprendre combien de traitement (plus ou moins) est nécessaire.

  1. Sur la base des jetons ci-dessus, nous savons qu'un fait, ARRAY_INIT produira toujours un tableau. Nous créons donc simplement un tableau et le peuplons. En ce qui concerne l’ambiguïté, l’étape de l’analyse lexicale a déjà distingué ARRAY_INIT d’un accesseur de propriété d’objet (par exemple, obj[foo]) ou entre crochets dans les chaînes de caractères/littéraux regex (par exemple, "foo [] bar" ou/[] /)

  2. C’est minime, mais nous avons aussi plus de jetons avec new Array. De plus, il n'est pas encore tout à fait clair que nous souhaitons simplement créer un tableau. Nous voyons le "nouveau" jeton, mais "nouveau" quoi? Nous voyons ensuite le jeton IDENTIFIANT qui signifie que nous voulons un nouveau "Tableau", mais les machines virtuelles JavaScript ne distinguent généralement pas un jeton IDENTIFIANT et des jetons pour les "objets globaux natifs". Par conséquent...

  3. Nous devons rechercher la chaîne d'étendue chaque fois que nous rencontrons un jeton IDENTIFIANT. Les machines virtuelles Javascript contiennent un "objet d'activation" pour chaque contexte d'exécution, lequel peut contenir l'objet "arguments", des variables définies localement, etc. Si nous ne le trouvons pas dans l'objet Activation, nous commençons à rechercher la chaîne de la portée jusqu'à atteindre la portée globale. . Si rien n'est trouvé, nous lançons un ReferenceError.

  4. Une fois que nous avons localisé la déclaration de variable, nous appelons le constructeur. new Array est un appel de fonction implicite, et la règle générale est que les appels de fonction sont plus lents pendant l’exécution (c’est pourquoi les compilateurs statiques C/C++ autorisent le "inlining de fonction" - ce que les moteurs JS JIT tels que SpiderMonkey doivent effectuer à la volée )

  5. Le constructeur Array est surchargé. Le constructeur Array étant implémenté en tant que code natif, il apporte certaines améliorations en termes de performances, mais il doit toujours vérifier la longueur des arguments et agir en conséquence. De plus, dans le cas où un seul argument est fourni, nous devons en vérifier le type. new Array ("foo") produit ["foo"] où, comme nouveau, Array (1) produit [undefined]

Donc, pour simplifier les choses: avec les littéraux de tableau, le VM sait que nous voulons un tableau; avec new Array, le VM doit utiliser des cycles de processeur supplémentaires pour comprendre ce que new Arrayen fait le fait.

192
Roger Poon

Une des raisons possibles est que new Array nécessite une recherche de nom sur Array (vous pouvez avoir une variable avec ce nom dans la portée), alors que [] ne fait pas.

27
hammar

Bonne question. Le premier exemple s'appelle un littéral de tableau. C'est le moyen préféré de créer des tableaux parmi de nombreux développeurs. Il est possible que la différence de performances résulte de la vérification des arguments du nouvel appel Array (), puis de la création de l’objet, tandis que le littéral crée directement un tableau.

La différence de performance relativement faible confirme ce point, je pense. Vous pouvez faire le même test avec Object et object literal {}.

2
Laurent Zuijdwijk

Cela aurait du sens

Les objets littéraux nous permettent d'écrire du code qui prend en charge de nombreuses fonctionnalités tout en en faisant un outil relativement simple pour les développeurs de notre code. Il n'est pas nécessaire d'appeler directement les constructeurs ni de conserver l'ordre correct des arguments passés aux fonctions, etc.

http://www.dyn-web.com/tutorials/obj_lit.php

1
lnguyen55