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.
-
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 /[]/)
-
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...
-
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
.
-
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).
-
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.
5 votes
Vous pourriez être intéressé par jsperf .
11 votes
Repère
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.
0 votes
@tjameson d'après ce que j'ai compris de l'ES5, c'est que
[] === new Array()
0 votes
@Raynos : L'exécution du code de l'OP sur mon système produit des résultats similaires (
[]
(qui est plus rapide), mais lors de l'exécution du benchmark dont vous avez donné le lien,[]
s'avère en fait plus lent. O_o (Je l'ai lancé plusieurs fois pour m'en assurer. Il en résulte toujours moins d'ops/sec que n'importe lequel des autres snippets).0 votes
Cette partie de la question a déjà été discutée aquí y aquí
0 votes
@Raynos cela signifie-t-il que [3] === new Array(3) ?
2 votes
@kinakuta no. Ils créent tous deux de nouveaux objets non égaux. Je voulais dire
[]
équivaut ànew Array()
en termes de code source, et non d'objets renvoyés par des expressions0 votes
@kinakuta Non ! a = [3] créera un tableau avec un seul élément, new Array(3) créera un tableau avec 3 éléments.
0 votes
Oui, je suis conscient de ce qui est renvoyé, je cherche à clarifier comment [] === new Array() ;
0 votes
Ce n'est pas très important. Pour la quasi-totalité des applications pratiques, la différence de performance, qui variera d'un navigateur à l'autre, sera tout à fait insignifiante. Il y aura presque toujours des goulets d'étranglement plus importants que la méthode utilisée pour créer un tableau.
1 votes
Oui, ce n'est pas très important. Mais j'aime bien savoir.
0 votes
Un peu hors sujet, mais j'ai constaté qu'il y a aussi une énorme différence d'utilisation de la mémoire. Si je crée un tableau de 1000000 tableaux vides à l'intérieur, en utilisant le constructeur de tableau, cela prend environ 85 Mo, et lorsque la notation littérale est utilisée, cela prend environ 40 Mo. (testé sur des snapshots chrome).
0 votes
Il y a une différence de transformation parce que la notation littérale transforme d'abord l'objet en un objet temporel et travaille ensuite dessus.