In che modo gli array JavaScript sono rappresentati nella memoria fisica?

Sono a conoscenza del fatto che posso memorizzare dati misti in un array JavaScript, nonché modificare qualsiasi elemento nell’array con un altro tipo. Come fa l’interprete a tenere traccia di quale sia il posto nella memoria fisica in cui si trova un elemento. Inoltre, come viene impedita la sovrascrittura dei dati nell’elemento successivo se si modifica un elemento in un tipo di dati più grande.

Suppongo che gli array memorizzino solo riferimenti a oggetti reali e che le primitive siano avvolte dietro le quinte quando posizionate in array.

Supponendo che questo è il caso, se ho un diverso handle sulla variabile primitiva e modificare il valore memorizzato nella matrice è mantenuta la sincronicità?

So che probabilmente ho già risposto alla mia domanda, ma non ne sono sicuro e non riesco a trovare alcuna informazione in merito.

Normalmente, gli array allocano un blocco contiguo di memoria di lunghezza fissa. Tuttavia, in Javascript, gli array sono tipi di object con costruttori speciali e metodi di accesso.

Il che significa, una dichiarazione come:

 var arr = new Array(100000); 

non alloca memoria! Di fatto, imposta semplicemente il valore della proprietà length nell’array. Quando si costruisce un array, non è necessario dichiarare una dimensione man mano che crescono automaticamente. Quindi, dovresti usare questo invece:

 var arr = []; 

Le matrici in Javascript sono sparse, il che significa che non tutti gli elementi dell’array possono contenere dati. In altre parole, solo gli elementi che contengono effettivamente dati esistono nell’array. Ciò riduce la quantità di memoria utilizzata dall’array. I valori sono posizionati da una chiave e non da un offset. Sono semplicemente un metodo di convenienza e non sono destinati ad essere utilizzati per complesse analisi numeriche.

Le matrici in Javascript non vengono digitate in modo che il valore di un elemento possa essere un object, una stringa, un numero, un valore booleano, una funzione o un array. La principale differenza tra una matrice e un object è la proprietà length che ha un valore maggiore della chiave intera più grande nella matrice.

Per esempio:

Si potrebbe creare un array vuoto e aggiungere due elementi all’indice 0 e all’indice 99. La lunghezza sarebbe 100, ma il numero di elementi nell’array sarebbe 2.

 var arr = []; arr[0] = 0; arr[99] = {name: "John"}; console.log(arr.length); // prints 100 arr; // prints something like [0, undefined × 98, Object { name: "John"}] 

Per rispondere direttamente alle tue domande:

D. Sono a conoscenza del fatto che posso memorizzare dati misti in un array JavaScript, nonché modificare qualsiasi elemento nell’array con un altro tipo. In che modo l’interprete tiene traccia di quale posto nella memoria fisica è presente in ogni elemento? Inoltre, come viene impedita la sovrascrittura dei dati nell’elemento successivo se si modifica un elemento in un tipo di dati più grande?

R. Probabilmente lo sai ormai se hai letto i miei commenti sopra. In Javascript, un array è un tipo di object Hashtable, quindi l’interprete non ha bisogno di tenere traccia della memoria fisica e la modifica del valore di un elemento non influisce su altri elementi poiché non sono memorizzati in un blocco contiguo di memoria.

D. Suppongo che gli array memorizzino solo riferimenti a oggetti reali e che le primitive siano avvolte dietro le quinte quando posizionate in array. Supponendo che questo è il caso, se ho un diverso handle sulla variabile primitiva e modificare il valore memorizzato nella matrice è mantenuta la sincronicità?

R. No, i primitivi non sono avvolti. La modifica di una primitiva assegnata a una matrice non modificherà il valore nella matrice man mano che vengono memorizzati per valore. Gli oggetti d’altra parte sono memorizzati per riferimento, quindi la modifica del valore degli oggetti rifletterà quella modifica in quella matrice.

Ecco un esempio che puoi provare:

 var arr = []; var obj = { name: "John" }; var isBool = true; arr.push(obj); arr[1] = isBool; console.log(arr[0]); // print obj.name console.log(arr[1]); // print true obj.age = 40; // add age to obj isBool = false; // change value for isBool console.log(arr[0]); // value here will contain age console.log(arr[1]); // value here will still be true 

Inoltre, tieni presente che quando si inizializza una matrice nei seguenti due modi, ha un comportamento diverso:

 var arr = new Array(100); console.log(arr.length); // prints 100 console.log(arr); // prints [] var arr2 = new Array(100, 200); console.log(arr2.length); // prints 2 console.log(arr2); // prints [100, 200] 

Se si desidera utilizzare gli array Javascript come blocchi contigui di memoria, è necessario utilizzare TypedArray . TypedArray consente di allocare un blocco di memoria come array di byte e accedere ai dati binari non elaborati in modo più efficiente.

Puoi saperne di più sulla complessità di Javascript leggendo la specifica ECMA-262 (ver 5.1) .

Ecco alcuni spunti di riflessione. Ho creato un jsperf per testare una semplice ottimizzazione dell’array implementata da alcuni motori JavaScript.

Il test case crea due array con un milione di elementi ciascuno. L’array contiene solo numeri; la matrice b contiene gli stessi numeri ad eccezione del primo elemento che è un object:

 var a = [ 0 ], b = [ { valueOf: function() { return 0; } } ]; for( var i = 1; i < 1000000; ++i ) { a[i] = b[i] = i; } 

La proprietà valueOf dell'object nel primo elemento dell'array b restituisce 0 quindi l'aritmetica sarà la stessa del primo array.

Quindi i due test sumno semplicemente tutti i valori per i due array.

Array veloce:

 var x = 0; for( var i = 0; i < 1000000; ++i ) { x += a[i]; } 

Array lento:

 var x = 0; for( var i = 0; i < 1000000; ++i ) { x += b[i]; } 

Come si può vedere dai risultati del test in jsperf, in Chrome l'array numerico è circa 5 volte più veloce, in Firefox l'array numerico è circa 10 volte più veloce, e in IE è circa 2 volte più veloce.

Questo non rivela direttamente le strutture interne utilizzate per l'array, ma fornisce una buona indicazione che i due sono piuttosto diversi l'uno dall'altro.