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.
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 accessor (ad esempio obj[foo]
) o parentesi all'interno di stringhe / valori letterali regex (ad esempio "foo [] bar" o / [] /)
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 le VM JavaScript generalmente non distinguono un token IDENTIFIER e token per "oggetti globali nativi". Perciò...
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 a ReferenceError
.
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)
Il Array
costruttore è 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 dell'array, la VM sa che vogliamo un array; con new Array
, la VM deve usare cicli di CPU extra per capire cosa fa new Array
realmente .