1
votes

La mutabilité du tableau et le scénario de référence variable ne sont pas clairs

Donc, je comprends que les tableaux en JavaScript sont mutables.

Cela signifie que si je crée un tableau a et un tableau b = a , alors si je modifie un tableau a , la modification est également visible dans le tableau b.

Cependant, dans le scénario suivant, je ne comprends pas pourquoi b code> perd la "référence" au tableau a .

var a = [1,2,3];
var b = a;

console.log('a =', a);
console.log('b =', b);

a[0] = 4;
console.log('a =', a);
console.log('b =', b);

a = [5,5];
console.log('a =', a);
console.log('b =', b);


1 commentaires

Ce que Tyler a dit et la journalisation de la console afficheront les éléments tels qu'ils sont, et non tels qu'ils étaient à l'avenir lorsque vous vous connecterez peut-être faire un console.log (JSON.stringify (quelque chose, null, 2)) au lieu. Lorsque vous exécutez ce var arr = [{name: 'original'}]; console.log (arr); arr [0] .name = 'changed' puis développez la sortie de la console, il dira "changé" mais vous l'avez connecté avant de le modifier.


3 Réponses :


6
votes

a et b ne sont pas des références l'un à l'autre - ce sont des références au même tableau .

Lorsque vous faites a = [5,5] , vous définissez a sur un tout nouveau tableau, tandis que b < / code> fait toujours référence à l'ancien.


9 commentaires

Et comment pourrais-je dire à b de garder une référence à tout ce que contient a ?


@DonJoe Soyez plus précis alors, sur la façon dont vous voulez que [5, 5] affecte les résultats dans a et b


@DoJoe JavaScript n'a pas la capacité pour les variables de contenir des pointeurs, vous ne pouvez donc pas essayer de définir a à b et que b soit {value: [1,2,3]} alors vous pouvez définir b.value sur n'importe quoi et a.value changera.


@DonJoe Comme le souligne Taplar, vous devrez élaborer un peu. Il n'y a pas vraiment de moyen inhérent de faire en sorte qu'une variable conserve la valeur d'une autre, bien qu'il existe des solutions de contournement telles que les mentions HMR.


medium.com/@naveenkarippai/... est un assez bon aperçu du fonctionnement des références dans JS


@DonJoe JavaScript n'a pas de pointeurs. Plus d'informations . Techniquement, vous pouvez faire quelque chose comme Object.defineProperty ('window', 'b', get () => this .a); , mais c'est moche car cela nécessite des globaux et autres.


@tylerRoper ou avec ({a, get b () {return this.a;}}) {...} ;)


@donJoe vous ne pouvez pas avoir de références à des références dans JS (en C, vous pouvez pointer vers un pointeur). Les variables ne peuvent référencer que des valeurs, il n'y a aucun moyen pour une variable de référencer une variable.


@DonJoe au lieu d'un "pointeur" utilise une fonction dans JS. var b = () => a; var b contient maintenant une fonction qui retournera toujours la valeur courante stockée dans la variable a . Et dans JS, vous pouvez transmettre cette fonction comme toute autre valeur. C'est la voie à suivre pour JS. Vous souhaitez peut-être en savoir plus sur les fermetures , les rappels et les fonctions en tant que citoyens de première classe .



3
votes

Regardons la mémoire des ordinateurs¹. Tout d'abord, deux variables sont créées, a et b . Ce sont essentiellement des emplacements de mémoire, qui sont remplis avec une valeur:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 5
  3        |            |  [1, 2, 3] // waiting for GC
  4        |            |  [5, 5]
  5        |            | { value: ➡️4 }

Maintenant a est initialisé, et un nouveau tableau est créé. Ce tableau n'est cependant pas stocké directement sous la variable, mais à un autre emplacement, à l'intérieur d'un a il y a juste une référence à cet emplacement:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 4
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]
  4        |            |  [5, 5]

Maintenant, lorsque vous faites b = a la référence est copiée, vous vous retrouvez à:

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  ➡️ 3
  3        |            |  [1, 2, 3]

Maintenant, lorsque vous faites a = [ 5,5] un autre tableau est créé, et a y fait référence. Cependant, b n'a pas été modifié, il fait toujours référence à l'autre tableau.

  location | name²      |  value
  -------------------------------------
  1        |  a         |  ➡️ 3
  2        |  b         |  undefined
  3        |            |  [1, 2, 3]

Ou si vous faites b = {value: a} :

 location | name²      |  value
 -------------------------------------
  1       |  a         |  undefined
  2       |  b         |  undefined

¹ oui, JavaScript est un langage interprété, vous ne saurez donc pas avec certitude comment il se retrouve dans la mémoire à la fin, c'est au moteur. Cependant, JS dérive ses concepts d'autres langages, et c'est pourquoi il est souvent utile de penser à un bas niveau.

² il n'y a pas de nom d'un emplacement mémoire spécifique, j'ai juste ajouté que pour plus de clarté.


2 commentaires

La visualisation est très cool. Pourriez-vous étendre cela en incluant également un cas où, par exemple, b = {value: a} , ou tout autre scénario?


@donJoe "tout autre scénario" sera trop.



3
votes

Il peut être utile de considérer les "variables" comme distinctes des "valeurs".

a et b dans votre exemple sont des variables.

[1,2,3] , 4 et [5,5] dans votre exemple sont des valeurs.

Plusieurs variables peuvent référencer la même valeur. Si cette valeur change (mute), toutes les variables qui font référence à cette valeur renverront la valeur modifiée. L'exemple ci-dessous définit les références de a et b à la même valeur, puis apporte des modifications à cette valeur via à la fois la référence de a et le référence de b . Le résultat est que la valeur modifiée est toujours référencée par les deux variables.

var a = [1,2,3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a = [5,5]; // a reference assigned to new value [5,5]
console.log(a); // [5,5]
console.log(b); // [1,2,3]

Cependant, vous pouvez changer la valeur à laquelle une variable fait référence en la "affectant" à une nouvelle valeur. Cela ne changera pas (mute) la valeur elle-même et ne changera pas la référence de toute autre variable ayant fait référence à la même valeur. L'exemple ci-dessous définit les références de a et b à la même valeur, puis change la référence de a en une nouvelle valeur. Le résultat est que les variables font désormais référence à des valeurs différentes.

var a = [1,2,3]; // a references the value [1,2,3]
var b = a; // b references the value [1,2,3]
a[0] = 4; // [1,2,3] changed to [4,2,3]
b[1] = 5; // [1,2,3] changed to [4,5,3]
console.log(a); // [4,5,3]
console.log(b); // [4,5,3]


0 commentaires