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 [] : 299 ms
  • En utilisant new : 363 ms

Merci à Raynos ici est une référence de ce code et une façon plus possible de définir une variable.

Entrez la description de l'image ici

Étendre les réponses précédentes …

Du point de vue des compilateurs généraux et méconnaître les optimisations spécifiques à VM:

Tout d'abord, nous passons par la phase d'analyse lexicale où on symbolise le code.

À 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) 

Espérons que cela devrait vous fournir une visualisation suffisante afin que vous puissiez comprendre combien plus (ou moins) le traitement 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 simplement un tableau et le remplissons. En ce qui concerne l'ambiguïté, l'étape d'analyse lexicale a déjà distingué ARRAY_INIT d'un accessoire de propriété d'objet (p. Ex. obj[foo] ) ou des parenthèses à l'intérieur de chaînes / littératures regex (p. Ex. "Foo [] bar" ou / [] /)

  2. C'est minime, mais nous avons aussi plus de jetons avec un new Array . En outre, il n'est pas tout à fait clair que nous voulons simplement créer un tableau. Nous voyons le "nouveau" jeton, mais "nouveau" quoi? Nous voyons alors le jeton IDENTIFIER qui signifie que nous voulons un nouveau "Array", mais les VM JavaScript ne distinguent généralement pas un jeton et des jetons d'IDENTIFIER pour "objets globaux natifs". Donc…

  3. Nous devons rechercher la chaîne de portée chaque fois que nous rencontrons un jeton IDENTIFIER. Les VM Javascript contiennent un "objet d'activation" pour chaque contexte d'exécution qui peut contenir l'objet "arguments", les variables définies localement, etc. Si nous ne pouvons pas le trouver dans l'objet Activation, nous commençons à chercher la chaîne de portée jusqu'à atteindre la portée globale . Si rien n'est trouvé, nous jetons un ReferenceError .

  4. Une fois que nous avons localisé la déclaration de variable, nous invoquons le constructeur. new Array est un appel de fonction implicite et la règle de base est que les appels de fonction sont plus lents pendant l'exécution (par conséquent, pourquoi les compilateurs C / C ++ statiques permettent "l'ajout de la fonction" – que les moteurs JS JIT tels que SpiderMonkey doivent faire à la volée )

  5. Le constructeur Array est surchargé. Le constructeur Array est implémenté comme code natif de sorte qu'il offre des améliorations de performances, mais il doit toujours vérifier la longueur des arguments et agir en conséquence. En outre, dans le cas où un seul argument est fourni, nous devons vérifier plus avant le type de l'argument. New Array ("foo") produit ["foo"] où, comme une nouvelle Array (1) produit [undefined]

Donc, pour simplifier tout: avec des référentiels, la VM sait que nous voulons un tableau; Avec la new Array , la machine virtuelle doit utiliser des cycles de CPU supplémentaires pour déterminer ce qu'est actuellement le new Array .

Une raison possible est que la 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 le fait pas.

Bonne question. Le premier exemple s'appelle un tableau littéral. C'est la manière privilégiée de créer des tableaux parmi de nombreux développeurs. Il pourrait être que la différence de performance est causée par la vérification des arguments du nouvel appel Array (), puis la création de l'objet, alors que le littéral crée un tableau directement.

La différence relativement faible dans la performance appuie ce point je pense. Vous pouvez faire le même test avec l'objet et l'objet littéral {} en passant.

Cela aurait un certain sens

Les littéraux d'objets nous permettent d'écrire un code qui prend en charge de nombreuses fonctionnalités, ce qui rend toujours plus direct pour les implémenteurs de notre code. Il n'est pas nécessaire d'inviter les constructeurs directement ou de maintenir l'ordre correct des arguments passés aux fonctions, etc.

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