web-dev-qa-db-fra.com

Comment les tableaux JavaScript sont-ils représentés dans la mémoire physique?

Je crois comprendre que je peux stocker des données mixtes dans un tableau JavaScript, ainsi que changer n'importe quel élément du tableau en un autre type. Comment l'interprète garde-t-il la place dans la mémoire physique d'un élément? De même, comment l'écrasement des données dans l'élément suivant est-il empêché si je change un élément en un type de données plus grand.

Je suppose que les tableaux stockent uniquement des références à des objets réels, et les primitives sont enveloppées dans les coulisses lorsqu'elles sont placées dans des tableaux.

En supposant que c'est le cas, si j'ai une poignée différente sur la variable primitive et que je change la valeur stockée dans le tableau, la synchronicité est-elle maintenue?

Je sais que j'ai probablement déjà répondu à ma propre question, mais je n'en suis pas sûr et je ne trouve aucune information à ce sujet.

49
user3056052

Normalement, les tableaux allouent un bloc de mémoire contigu de longueur fixe. Cependant, en Javascript, les tableaux sont des types d'objets avec des constructeurs spéciaux et des méthodes d'accesseur.

Ce qui signifie, une déclaration comme:

var arr = new Array(100000);

n'alloue aucune mémoire! En fait, il définit simplement la valeur de la propriété length dans le tableau. Lorsque vous construisez un tableau, vous n'avez pas besoin de déclarer une taille car elles grandissent automatiquement. Donc, vous devriez utiliser ceci à la place:

var arr = [];

Les tableaux en Javascript sont rares, ce qui signifie que tous les éléments du tableau ne peuvent pas contenir de données. En d'autres termes, seuls les éléments qui contiennent réellement des données existent dans le tableau. Cela réduit la quantité de mémoire utilisée par la baie. Les valeurs sont localisées par une clé et non par un décalage. Ils sont simplement une méthode pratique et ne sont pas destinés à être utilisés pour une analyse numérique complexe.

Les tableaux en Javascript ne sont pas saisis, la valeur d'un élément peut donc être un objet, une chaîne, un nombre, un booléen, une fonction ou un tableau. La principale différence entre un tableau et un objet est la propriété length qui a une valeur supérieure à la plus grande clé entière du tableau.

Par exemple:

Vous pouvez créer un tableau vide et ajouter deux éléments à l'index 0 et à l'index 99. La longueur serait 100, mais le nombre d'éléments dans le tableau serait 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"}]

Pour répondre directement à vos questions:

Q. Je crois comprendre que je peux stocker des données mixtes dans un tableau JavaScript, ainsi que changer n'importe quel élément du tableau en un autre type. Comment l'interprète garde-t-il la place dans la mémoire physique d'un élément? En outre, comment l'écrasement des données dans l'élément suivant est-il empêché si je change un élément en un type de données plus grand?

R. Vous le savez probablement déjà si vous avez lu mes commentaires ci-dessus. En Javascript, un tableau est un type d'objet Hashtable, donc l'interpréteur n'a pas besoin de garder une trace de la mémoire physique et la modification de la valeur d'un élément n'affecte pas les autres éléments car ils ne sont pas stockés dans un bloc de mémoire contigu.

-

Q. Je suppose que les tableaux stockent uniquement des références à des objets réels et que les primitives sont placées en arrière-plan lorsqu'elles sont placées dans des tableaux. En supposant que c'est le cas, si j'ai une poignée différente sur la variable primitive et que je change la valeur stockée dans le tableau, la synchronicité est-elle maintenue?

R. Non, les primitives ne sont pas encapsulées. La modification d'une primitive qui a été affectée à un tableau ne modifie pas la valeur du tableau car elle est stockée par valeur. Les objets d'autre part sont stockés par référence, donc la modification de la valeur des objets reflétera ce changement dans ce tableau.

Voici un exemple que vous pouvez essayer:

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

Notez également que lorsque vous initialisez un tableau des deux manières suivantes, il a un comportement différent:

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]

Si vous souhaitez utiliser des tableaux Javascript en tant que blocs de mémoire contigus, vous devriez envisager d'utiliser TypedArray . TypedArray vous permet d'allouer un bloc de mémoire en tant que tableau d'octets et d'accéder plus efficacement aux données binaires brutes.

Vous pouvez en savoir plus sur les subtilités de Javascript en lisant la spécification ECMA-262 (ver 5.1) .

45
Nick

Voici un peu de grain à moudre. J'ai fait n jsperf pour tester une simple optimisation de tablea que certains moteurs JavaScript implémentent.

Le scénario de test crée deux tableaux avec un million d'éléments chacun. Le tableau a ne contient que des nombres; le tableau b contient les mêmes nombres à l'exception du premier élément qui est un objet:

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

La propriété valueOf de l'objet dans le premier élément du tableau b renvoie 0 donc l'arithmétique sera la même que la première matrice.

Ensuite, les deux tests résument simplement toutes les valeurs des deux tableaux.

Tableau rapide:

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

Tableau lent:

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

Comme vous pouvez le voir d'après les résultats du test dans le jsperf, dans Chrome le tableau numérique est environ 5 fois plus rapide, dans Firefox le tableau numérique est environ 10 fois plus rapide et dans IE c'est environ 2x plus rapide.

Cela ne révèle pas directement les structures internes utilisées pour le tableau, mais cela donne une assez bonne indication que les deux sont assez différents l'un de l'autre.

8
Michael Geary

La réponse acceptée dit que

[Une construction de tableau] n'alloue aucune mémoire!

Ce n'est pas nécessairement vrai. Le stockage de tableaux sous forme de paires clé-valeur non ordonnées comme dans des objets est très inefficace car chaque recherche est une recherche. Même si les entrées étaient triées, il allouerait toujours plus de mémoire que nécessaire. Par conséquent, de nombreux moteurs représentent les tableaux de différentes manières pour sécuriser la mémoire et optimiser les performances. Cela peut également être vu dans l'exemple de Michael Geary, le tableau qui contient uniquement des nombres est optimisé ( détails pour V8 ). Et parfois, le moteur peut décider d'allouer des emplacements vides pour un tableau nouvellement créé, si la représentation sous-jacente a une taille fixe et ne peut pas être mise à l'échelle aussi facilement.

0
Jonas Wilms