it-swarm.it

Perché arr = [] è più veloce di arr = new Array?

Ho eseguito questo codice e ho ottenuto il risultato di seguito. Sono curioso di sapere perché [] è più veloce?

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')
  • utilizzando []: 299ms
  • utilizzando new: 363ms

Grazie a Raynos ecco un benchmark di questo codice e qualche altro modo possibile per definire una variabile.

enter image description here

143
Mohsen

Espandere ulteriormente le risposte precedenti ...

Dal punto di vista dei compilatori generali e ignorando le ottimizzazioni specifiche della VM:

Innanzitutto, passiamo alla fase di analisi lessicale in cui tokenizziamo il codice.

A titolo di esempio, possono essere prodotti i seguenti token:

[]: 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)

Speriamo che questo ti fornisca una visualizzazione sufficiente in modo da poter capire quanto più (o meno) elaborazione è richiesta.

  1. Sulla base dei token precedenti, sappiamo che ARRAY_INIT produrrà sempre un array. Pertanto, semplicemente creiamo un array e lo popoliamo. Per quanto riguarda l'ambiguità, la fase di analisi lessicale ha già distinto ARRAY_INIT da un oggetto di accesso alla proprietà dell'oggetto (ad esempio obj[foo]) o parentesi all'interno di stringhe/valori letterali regex (ad esempio "foo [] bar" o/[] /)

  2. Questo è minuscolo, ma abbiamo anche più token con new Array. Inoltre, non è ancora del tutto chiaro che vogliamo semplicemente creare un array. Vediamo il "nuovo" token, ma "nuovo" cosa? Vediamo quindi il token IDENTIFIER che significa che vogliamo un nuovo "array", ma i VM JavaScript generalmente non distinguono un token IDENTIFIER e token per "oggetti globali nativi". Perciò...

  3. Dobbiamo cercare la catena di portata ogni volta che incontriamo un token IDENTIFIER. Le macchine virtuali Javascript contengono un "oggetto di attivazione" per ogni contesto di esecuzione che può contenere l'oggetto "argomenti", variabili definite localmente, ecc. Se non riusciamo a trovarlo nell'oggetto di attivazione, iniziamo a cercare la catena dell'ambito fino a raggiungere l'ambito globale . Se non viene trovato nulla, lanciamo un ReferenceError.

  4. Una volta individuata la dichiarazione della variabile, invochiamo il costruttore. new Array è una chiamata di funzione implicita e la regola empirica è che le chiamate di funzione sono più lente durante l'esecuzione (quindi perché i compilatori C/C++ statici consentono "allineamento di funzioni" - che i motori JS JIT come SpiderMonkey devono fare al volo )

  5. Il costruttore Array è sovraccarico. Il costruttore di array è implementato come codice nativo, quindi fornisce alcuni miglioramenti delle prestazioni, ma deve comunque verificare la lunghezza degli argomenti e agire di conseguenza. Inoltre, nel caso in cui venga fornito un solo argomento, è necessario verificare ulteriormente il tipo di argomento. new Array ("foo") produce ["foo"] dove come nuovo Array (1) produce [indefinito]

Quindi, per semplificare tutto: con i letterali di array, il VM sa che vogliamo un array; con new Array, il VM deve utilizzare cicli CPU aggiuntivi per capire cosa new Arrayattualmente lo fa.

192
Roger Poon

Una possibile ragione è che new Array richiede una ricerca del nome su Array (puoi avere una variabile con quel nome nell'ambito), mentre [] non.

27
hammar

Buona domanda. Il primo esempio è chiamato array letterale. È il modo preferito per creare array tra molti sviluppatori. È possibile che la differenza di prestazioni sia causata controllando gli argomenti della nuova chiamata Array () e quindi creando l'oggetto, mentre il valore letterale crea direttamente un array.

La differenza relativamente piccola nelle prestazioni supporta questo punto credo. A proposito, potresti fare lo stesso test con l'oggetto e l'oggetto letterale {}.

2

Questo avrebbe un senso

I letterali di oggetti ci consentono di scrivere codice che supporta molte funzionalità ma che lo rende ancora relativamente semplice per gli implementatori del nostro codice. Non è necessario richiamare direttamente i costruttori o mantenere l'ordine corretto degli argomenti passati alle funzioni, ecc.

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

1
lnguyen55