146 votes

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

J'ai exécuté ce code et j'ai obtenu le résultat suivant. 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

Merci à Raynos voici un repère de ce code et d'autres façons possibles de définir une variable.

enter image description here

5 votes

Vous pourriez être intéressé par jsperf .

11 votes

0 votes

Notez le mot clé "nouveau". Cela signifie "veuillez être moins efficace". Cela n'a jamais de sens et oblige le navigateur à procéder à une instanciation normale au lieu d'essayer de faire des optimisations.

195voto

Roger Poon Points 1230

En complément des réponses précédentes...

Du point de vue des compilateurs généraux et sans tenir compte des optimisations spécifiques aux machines virtuelles :

Tout d'abord, nous passons par la phase d'analyse lexicale qui consiste à symboliser 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)

Nous espérons que cela vous fournira une visualisation suffisante pour que vous puissiez comprendre dans quelle mesure un traitement supplémentaire (ou moindre) est nécessaire.

  1. Sur la base des éléments ci-dessus, nous savons que ARRAY_INIT produira toujours un tableau. Nous nous contentons donc de créer un tableau et de le remplir. En ce qui concerne l'ambiguïté, l'étape de l'analyse lexicale a déjà distingué ARRAY_INIT d'un accesseur à une propriété d'objet (par ex. obj[foo] ) ou des parenthèses à l'intérieur de chaînes de caractères ou de littéraux d'expressions rationnelles (par exemple, "foo[]bar" ou /[]/)

  2. C'est minuscule, mais nous avons aussi plus de jetons avec new Array . De plus, il n'est pas encore tout à fait clair que nous voulons simplement créer un tableau. Nous voyons le jeton "new", mais "new" quoi ? Nous voyons ensuite le jeton IDENTIFIER qui signifie que nous voulons un nouveau "tableau", mais les VM JavaScript ne font généralement pas la distinction entre un jeton IDENTIFIER et des jetons pour des "objets globaux natifs". Par conséquent...

  3. Nous devons consulter 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", des variables définies localement, etc. Si nous ne le trouvons pas dans l'objet d'activation, nous commençons à chercher dans la chaîne de portée jusqu'à ce que nous atteignions 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 la 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 lors de l'exécution (c'est pourquoi les compilateurs C/C++ statiques permettent l'"inlining de fonction" - ce que les moteurs JIT JS tels que SpiderMonkey doivent faire à la volée).

  5. Les Array est surchargé. Le constructeur de tableau est implémenté en tant que code natif, ce qui permet d'améliorer les 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 vérifier le type de l'argument. new Array("foo") produit ["foo"] alors que new Array(1) produit [undefined]

Pour simplifier, avec les littéraux de tableau, la VM sait que nous voulons un tableau ; avec les littéraux de tableau, la VM sait que nous voulons un tableau ; avec les littéraux de tableau, la VM sait que nous voulons un tableau. new Array la VM doit utiliser des cycles supplémentaires de l'unité centrale pour déterminer ce qu'elle doit faire. new Array en fait ne.

0 votes

A = new Array(1000);for(from 0 to 999){a[i]=i} n'est-il pas plus rapide que a = [];for(from 0 to 999){a[i]=i} à cause de la surcharge d'allocation ?

0 votes

Je viens de faire un test. new Array(n) est plus rapide dans les cas où l'on connaît la taille du tableau à l'avance. jsperf.com/bretelles carrées-vs-nouveau-array

27voto

hammar Points 89293

L'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 le champ d'application), alors que [] ne le fait pas.

4 votes

La vérification des arguments peut également y contribuer.

0 votes

Array accepte à la fois un argument len et des arguments multiples. Dans le cas où [] n'accepte que des arguments multiples. De plus, les tests de firefox ne montrent pratiquement aucune différence.

0 votes

Je pense qu'il y a une part de vérité là-dedans. L'exécution du test de boucle de l'OP dans un IIFE fait un (relativement) impact substantiel sur la performance. Notamment var Array = window.Array améliore les performances de la new Array test.

2voto

Oleg Zarevennyi Points 308

Il est également intéressant de noter que si le la longueur du tableau est connue à l'avance (les éléments seront ajoutés juste après la création), l'utilisation d'un constructeur de tableau avec un longueur est beaucoup plus rapide sur les versions récentes de Google Chrome 70+.

  • " nouveau tableau( %ARR_LENGTH% ) " - 100% (plus rapide) !

  • " [] " - 160-170% (plus lent)

Chart with results of the measures.

Le test est disponible ici - https://jsperf.com/small-arr-init-with-known-length-brackets-vs-new-array/2

Note : ce résultat a été testé sur Google Chrome v.70+ ; dans le Firefox v.70 et IE, les deux variantes sont presque égales.

2voto

Laurent Zuijdwijk Points 493

Bonne question. Le premier exemple s'appelle un tableau littéral. C'est le moyen préféré de nombreux développeurs pour créer des tableaux. Il se peut que la différence de performance soit due à la vérification des arguments de l'appel new Array() et à la création de l'objet, alors que le littéral crée directement un tableau.

La différence de performance relativement faible confirme ce point de vue, je pense. Vous pourriez d'ailleurs faire le même test avec l'objet et le littéral d'objet {}.

1voto

lnguyen55 Points 355

Cela aurait du sens

Les objets littéraux nous permettent d'écrire du code qui prend en charge un grand nombre d'objets de type fonctionnalités, tout en restant relativement simple pour les pour les personnes chargées de la mise en œuvre de notre code. N de maintenir l'ordre correct des arguments transmis aux fonctions, etc.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X