Il est important de comprendre ce que le =
en JavaScript fait et ne fait pas.
El =
ne fait pas un copie des données.
El =
L'opérateur crée un nouveau référence à la même données.
Après avoir exécuté votre code original :
var a = $('#some_hidden_var').val(),
b = a;
a
y b
sont maintenant deux noms différents pour le même objet .
Toute modification apportée au contenu de cet objet sera perçue de manière identique, que vous y fassiez référence par l'intermédiaire de l'objet a
ou la variable b
variable. Ils sont le même objet.
Donc, quand vous essayez plus tard de "revenir" b
à l'original a
avec ce code :
b = a;
Le code fait en réalité rien du tout parce que a
y b
sont exactement la même chose. Le code est le même que si vous aviez écrit :
b = b;
ce qui évidemment ne fera rien.
Pourquoi votre nouveau code fonctionne-t-il ?
b = { key1: a.key1, key2: a.key2 };
Ici, vous créez un tout nouvel objet avec l'attribut {...}
objet littéral. Ce nouvel objet n'est pas le même que votre ancien objet. Vous définissez donc maintenant b
comme une référence à ce nouvel objet, ce qui fait ce que vous voulez.
Pour gérer n'importe quel objet arbitraire, vous pouvez utiliser une fonction de clonage d'objet telle que celle indiquée dans la réponse d'Armand, ou, puisque vous utilisez jQuery, utilisez simplement la fonction $.extend()
fonction . Cette fonction va faire une copie superficielle ou une copie profonde d'un objet. (Ne confondez pas cette fonction avec la fonction $().clone()
méthode qui sert à copier des éléments du DOM, pas des objets).
Pour une copie superficielle :
b = $.extend( {}, a );
Ou une copie profonde :
b = $.extend( true, {}, a );
Quelle est la différence entre une copie superficielle et une copie profonde ? Une copie superficielle est similaire à votre code qui crée un nouvel objet avec un objet littéral. Elle crée un nouvel objet de haut niveau contenant des références aux mêmes propriétés que l'objet original.
Si votre objet ne contient que des types primitifs comme des nombres et des chaînes de caractères, une copie profonde et une copie superficielle feront exactement la même chose. Mais si votre objet contient d'autres objets ou des tableaux imbriqués à l'intérieur de lui, alors une copie superficielle n'est pas nécessaire. copie ces objets imbriqués, il crée simplement des références à ceux-ci. On peut donc avoir le même problème avec les objets imbriqués qu'avec l'objet de niveau supérieur. Par exemple, avec cet objet :
var obj = {
w: 123,
x: {
y: 456,
z: 789
}
};
Si vous faites une copie superficielle de cet objet, alors l'objet x
de votre nouvel objet est la même x
de l'original :
var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;
Maintenant, vos objets vont ressembler à ceci :
// copy looks as expected
var copy = {
w: 321,
x: {
y: 654,
z: 789
}
};
// But changing copy.x.y also changed obj.x.y!
var obj = {
w: 123, // changing copy.w didn't affect obj.w
x: {
y: 654, // changing copy.x.y also changed obj.x.y
z: 789
}
};
Vous pouvez éviter cela avec une copie profonde. La copie profonde récure dans chaque objet et tableau imbriqué (et Date dans le code d'Armand) pour faire des copies de ces objets de la même manière qu'elle a fait une copie de l'objet de niveau supérieur. Ainsi, en changeant copy.x.y
n'affecterait pas obj.x.y
.
Réponse courte : En cas de doute, il est préférable d'avoir une copie profonde.