web-dev-qa-db-fra.com

Définition d'une variable égale à une autre variable

J'ai quelques questions sur la définition d'une variable égale à une autre variable en JavaScript.

Disons que nous créons un objet, a et définissons b = a.

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;

Je comprends que si nous modifions l'une des propriétés de ab sera également modifiée parce que lorsque nous définirons b = a nous ne clonons pas les données de a, mais créons plutôt une référence aux données de a. Par exemple, si nous définissons a.fname = "Sarah", la nouvelle valeur de b.fname sera "Sarah".

Si nous essayons de "vider" a en définissant a = {}, l'objet b restera inchangé. Je ne comprends pas pourquoi la manipulation d'un objet de cette façon produit un résultat différent de celui du 1er exemple.


J'ai aussi une question sur le scénario suivant.

var x = 10;
var z = x;

Si nous définissons ensuite x = 20, la valeur de z reste inchangée. Sur la base du comportement décrit dans ma 1ère question, on pourrait penser que la nouvelle valeur de z refléterait la nouvelle valeur de x. Quelqu'un pourrait-il expliquer ce qui me manque ici?

Merci!

6
KGraber

La réponse très courte à vos deux questions est que lorsque vous faites une variable égale à une autre, une COPIE de ce qui est dans la première variable est faite et stockée dans la deuxième variable - il n'y a pas de lien entre les deux variables.

Mais lisez la suite pour plus de détails et pourquoi il peut y avoir un lien dans certains cas ...


JavaScript, comme de nombreux langages, divise les données en deux grandes catégories: les types de valeur et les types de référence. Les types de valeurs JavaScript sont ses primitives:

  • chaîne
  • nombre
  • booléen
  • nul
  • undefined
  • symbol

Lorsque vous affectez l'un de ces types à une variable, les données réelles sont stockées dans cette variable et si vous définissez une variable égale à une autre, une copie (pas un lien) de la primitive est faite et stockée dans la nouvelle variable:

var a = 10;  // Store the actual number 10 in the a variable
var b = a;   // Store a COPY of the actual number stored in a (10) in the b variable
a = 50;      // Change the actual data stored in a to 50 (no change to b here)
console.log(b);  // 10

Lorsque vous travaillez avec types de référence, quelque chose d'un peu différent se produit. L'affectation d'une variable à un type de référence signifie que la variable ne contient qu'une référence à l'emplacement de mémoire où l'objet est réellement stocké, pas l'objet lui-même. Donc, quand vous faites cela:

var a = {foo:"bar"};

a ne stocke pas réellement l'objet lui-même, il stocke uniquement l'emplacement mémoire où se trouve l'objet (c'est-à-dire 0x3C41A).

Mais, en ce qui concerne la définition d'une autre variable égale à la première, cela fonctionne toujours comme pour les primitives - - a une copie de ce qui est dans la première variable est faite et donnée à la seconde variable.

Voici un exemple:

// An object is instantiated in memory and a is given the address of it (for example 0x3C41A)
var a = {}; 
 
// The contents of a (the memory location of an object) is COPIED into b.
// Now, both a and b hold the same memory location of the object (0x3C41A)
var b = a;

// Regardless of whether a or b is used, the same underlying object
// will be affected:
a.foo = "test";
console.log(b.foo); // "test"

// If one of the variables takes on a new value, it won't change
// what the other variable holds:
a = "something else";
console.log(b);   // The object stored in memory location (0x3C41A)

Donc, dans vos premiers tests, vous avez simplement deux façons d'accéder à un objet, puis vous changez ce que a contient (l'emplacement de mémoire de l'objet) en un objet différent et donc maintenant vous n'en avez plus qu'un chemin à gauche pour accéder à l'objet d'origine, via b.


Si nous essayons de "supprimer" a en définissant a = {}, l'objet b restera inchangé. Je ne comprends pas pourquoi la manipulation d'un objet de cette façon produit un résultat différent de celui du 1er exemple.

Parce que maintenant nous savons que a = {} n'efface pas l'objet. Cela pointe simplement a vers autre chose.

7
Scott Marcus

Permettez-moi d'essayer d'expliquer:

1) Dans votre exemple, a et b sont des références à un seul et même objet, tandis que a.fname (ou b.fname) est un attribut de cet objet. Ainsi, lors de la manipulation de l'attribut, il sera modifié dans l'objet, alors que les références ne seront pas affectées, elles pointent toujours vers le même objet, l'objet lui-même a été modifié. a = {} d'autre part remplacera simplement la référence à l'objet sans affecter l'objet lui-même ou la référence de b à It.
Ce n'est pas un dégagement entre vous venez juste de créer une nouvelle référence à un nouvel objet vide.

2) Ce ne sont pas des objets, donc il n'y a aucune référence pour manipuler directement les valeurs. C'est parce qu'il y a une différence entre les objets et les primitives qui peuvent devenir déroutantes, surtout au début si vous n'êtes pas habitué à travailler avec des types stricts.

2
Chaz

Dans votre premier cas:

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;
a = {}

b reste inchangé car il s'agit de la séquence d'événements se produisant en arrière-plan:

  • Vous créez un objet à l'adresse mémoire 0x1234 avec les données

    fname: "Jon",lname: "Smith",age: 50

  • Un pointeur vers ce bloc de mémoire est stocké dans a.

  • Ensuite, ce pointeur est copié dans b

À ce stade, il y a deux références au même bit de mémoire. La modification de quoi que ce soit dans ce bloc de mémoire affectera ses deux références.

  • a = {} n'efface pas le bloc de mémoire 0x1234, mais crée un nouvel objet sur un autre emplacement de mémoire (0x1235) et stocke un pointeur vers ce bloc dans a. La mémoire à 0x1234 reste inchangée car b pointe toujours dessus.

Il existe une différence dans ce type de gestion de la mémoire entre les variables simples et les objets/pointeurs. Les chaînes et les nombres sont de la variété simple et sont "passés par valeur" au lieu d'être "passés par référence" pour les objets.

1
steenbergh