15 votes

Gestion de la mémoire des tableaux JavaScript

Duplicata possible :
Les tableaux Javascript sont-ils épars ?

J'apprends JavaScript en ce moment et j'ai lu quelques introductions et tutoriels simples. En regardant l'objet Array, je suis tombé sur certains détails, qui me semblent très étranges, venant d'autres langages comme C/Java/Scala/...


Supposons donc que nous définissions un tableau comme suit :

var arr = ['foo','bar','qux']

Nous attribuons maintenant

arr[5] = 'baz'

ce qui fait que notre tableau ressemble à ceci :

arr
>> ["foo", "bar", "qux", undefined, undefined, "baz"]

Et la longueur est conforme aux attentes

arr.length
>> 6

JavaScript a gentiment étendu notre tableau à la longueur nécessaire - six - et les nouveaux éléments sont définis comme indéfinis - sauf celui auquel nous avons réellement attribué une valeur.

D'un point de vue bas niveau, c'est horrible en termes de mémoire. Typiquement, un tableau est une plage continue en mémoire - agrandir un tableau implique généralement de copier l'ensemble du tableau vers un nouvel emplacement mémoire, de taille suffisante. C'est une opération très coûteuse.

Maintenant, je réalise que c'est probablement pas ce que font les moteurs JavaScript, car copier des tableaux serait extrêmement coûteux et l'espace mémoire serait gaspillé pour toutes ces valeurs "indéfinies".

Quelqu'un peut-il me dire ce qui se passe réellement derrière la porte ?

  • Les tableaux sont-ils en fait des sortes de listes liées ?
  • Les éléments du tableau "undefined" sont-ils réellement présents ?
  • Est-il coûteux de travailler avec des tableaux de grande taille qui sont principalement remplis de "non définis" ?

16voto

Elias Van Ootegem Points 29404

Dans la première version de JavaScript, il n'y avait pas de tableaux. Ils ont été introduits plus tard comme une sous-classe de la classe "mère de tous les objets" : Object . Vous pouvez tester cela assez facilement en faisant ceci :

var foo = [1,2,3,4];
for (var n in foo)
{//check if n is equal (value and type) to itself, coerced to a number
    console.log(n === +(n) ? 'Number' : 'String');
}

Cela permettra d'enregistrer String à chaque fois. En interne, toutes les touches numériques sont converties en chaînes de caractères. La propriété Length récupère simplement l'indice le plus élevé et lui ajoute 1. Rien de plus. Lorsque vous affichez votre tableau, l'objet est itéré, et pour chaque clé, les mêmes règles s'appliquent comme pour n'importe quel objet : d'abord l'instance est scannée, puis le(s) prototype(s)... donc si nous modifions un peu notre code :

var foo = [1,2,3,4];
foo[9] = 5;
for (var n in foo)
{
    if (foo.hasOwnProperty(n))
    {//check if current key is an array property
        console.log(n === +(n) ? 'Number' : 'String');
    }
}

Vous remarquerez que le tableau n'a que 5 propriétés propres, la propriété undefined Les clés 4-8 sont indéfinies, car aucune valeur correspondante n'a été trouvée dans l'instance, ni dans aucun des prototypes sous-jacents. En bref : les tableaux ne sont pas vraiment des tableaux, mais des objets qui se comportent de manière similaire.

Comme Tim l'a fait remarquer, vous puede ont une instance de tableau avec une propriété non définie qui fait existent dans cet objet :

var foo = [1,2,undefined,3];
console.log(foo[2] === undefined);//true
console.log(foo[99] === undefined);//true

Mais là encore, il y a une différence :

console.log((foo.hasOwnProperty('2') && foo[2] === undefined));//true
console.log((foo.hasOwnProperty('99') && foo[99] === undefined));//false

RECAP, vos trois principales questions :

  • Les tableaux sont des objets, qui vous permettent de référencer leurs propriétés avec des instances numériques.

  • En undefined ne sont pas là, elles sont simplement la valeur de retour par défaut lorsque JS scanne un objet et les prototypes et ne trouve pas ce que vous cherchez : "Désolé, ce que vous me demandez est indéfini dans mon livre." est ce qu'il dit.

  • Travailler avec des tableaux largement indéfinis n'affecte pas la taille de l'objet lui-même, mais accéder à une clé indéfinie peut être très difficile, très un peu plus lent, car les prototypes doivent aussi être scannés.

Mise à jour :

Juste en citant la norme Ecma :

15.4 Objets de type tableau
Les objets de type tableau accordent un traitement spécial à une certaine catégorie de noms de propriétés. Un nom de propriété P (sous la forme d'une valeur de type String) est un index de tableau si et seulement si ToString(ToUint32(P)) est égal à P et ToUint32(P) n'est pas égal à 2^32 1. Une propriété dont le nom de propriété est un indice de tableau est également appelée un élément. Chaque objet Array possède une propriété longueur dont la valeur est toujours un nombre entier non négatif inférieur à 2^32. La valeur de la propriété length est numériquement plus grande que le nom de chaque propriété dont le nom est un indice de tableau. propriété d'un objet Array est créée ou modifiée, les autres propriétés sont ajustées si nécessaire pour maintenir cet invariant. Plus précisément, chaque fois que l'on ajoute une propriété dont le nom est un indice de tableau, la propriété length est est modifiée, si nécessaire, pour être supérieure d'une unité à la valeur numérique de cet indice de tableau. est modifiée, chaque propriété dont le nom est un indice de tableau et dont la valeur n'est pas inférieure à la nouvelle longueur longueur est automatiquement supprimée. Cette contrainte s'applique uniquement aux propriétés propres d'un objet Array et n'est pas affectée par la propriété length. n'est pas affectée par les propriétés de longueur ou d'indice de tableau qui peuvent être héritées de ses prototypes.

On dit d'un objet, O, qu'il est clairsemé si l'algorithme suivant retourne vrai :
1. Soit len le résultat de l'appel de la méthode interne [[Get]] de O avec l'argument "length".
2. Pour chaque nombre entier i dans le ra
a. Soit elem le résultat de l'appel de la méthode interne [[GetOwnProperty]] de O avec l'argument [ ]
b. Si elem est indéfini, retourne true.
3. Faux retour.

4voto

Napolux Points 3153

Les tableaux sont simplement une liste ordonnée d'objets. En JavaScript, tout est un objet Les tableaux ne sont donc pas vraiment des tableaux tels que nous les connaissons :)

Vous pouvez trouver des petits internes aquí .

Pour vos doutes sur le travail avec de grands tableaux... Eh bien, rappelez-vous que moins vous faites de calculs "côté client", plus votre page sera rapide.

1voto

Tim Down Points 124501

Des réponses :

  1. En JavaScript, un tableau est identique à un objet (c'est-à-dire une collection non ordonnée de propriétés), mais il est doté de la fonction magique length et des méthodes de prototype supplémentaires ( push() etc.)
  2. Non, les éléments non définis ne sont pas là. JavaScript a un in opérateur qui teste l'existence d'une propriété que vous pouvez utiliser pour prouver ceci. Ainsi, pour le tableau suivant : var arr = ['foo']; arr[2] = 'bar'; , 2 in arr renvoie à true y 1 in arr renvoie à false .
  3. Un tableau clairsemé ne doit pas occuper plus de mémoire qu'un tableau dense dont la longueur correspond au nombre de propriétés réellement définies dans votre tableau clairsemé. Il sera seulement plus coûteux de travailler avec un tableau clairsemé lorsque vous itérerez sur ses propriétés non définies.

0voto

Philipp Points 22441

La plupart des implémentations javascript implémentent les tableaux comme une sorte d'arbre binaire ou de table de hachage avec l'index du tableau comme clé, ainsi une large gamme d'objets non définis n'utilise pas de mémoire.

0voto

exussum Points 6091

On m'a dit que les tableaux sont composés de deux parties, [valeur, pointeur]. Donc le pointeur de arr[2] est nul. Lorsque vous ajoutez un 5, cela change l'adresse de null à pointant sur le numéro 3, qui pointe sur le numéro 4, qui pointe sur le numéro 5, qui est null (donc fin du tableau).

Je ne suis pas sûr que ce soit vrai, car je ne l'ai jamais vérifié. Mais cela semble avoir du sens.

Vous ne pouvez donc pas faire les calculs comme avec un tableau de type c (c'est-à-dire que pour atteindre la valeur 4, il suffit de faire le point de départ de la mémoire + 4x (quantité d'objet en mémoire)) mais vous pouvez le faire en suivant le tableau morceau par morceau.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X