J'ai une variable qui a un objet JSON comme valeur. J'attribue directement cette variable à une autre variable afin qu'elles partagent la même valeur. Voilà comment cela fonctionne:
var a = $('#some_hidden_var').val(),
b = a;
Cela fonctionne et les deux ont la même valeur. J'utilise un mousemove
gestionnaire d'événements pour mettre à jour b
mon application. Lors d'un clic sur un bouton, je souhaite revenir b
à la valeur d'origine, c'est-à-dire à la valeur stockée dans a
.
$('#revert').on('click', function(e){
b = a;
});
Après cela, si j'utilise le même mousemove
gestionnaire d'événements, il met à jour les deux a
et b
, auparavant, il ne se mettait à jour que b
comme prévu.
Je suis perplexe sur ce problème! Quel est le problème ici?
javascript
jquery
Rutwick Gangurde
la source
la source
a
été défini à partir de,.val()
je suppose que c'est JSON (une chaîne), pas un objet - est-ce vrai? Utilisez-vousJSON.parse(a)
à un moment donné pour obtenir un objet réel?$.parseJSON
pour la convertir en objet. Structure:{ 'key': {...}, 'key': {...}, ...}
. Désolé, je ne peux pas publier de code ici, non autorisé sur mon lieu de travail!a
donc un objet?a
une variable globale?$.parseJSON()
vient-il?), Il est difficile de dire quel est le problème. En ce qui concerne les règles de votre lieu de travail, vous n'avez pas à publier votre véritable code réel dans son intégralité, il suffit de proposer un exemple plus court et plus générique qui démontre le problème (et, idéalement, d'inclure un lien vers une démo en direct sur jsfiddle.net ) .Réponses:
Il est important de comprendre ce que
=
fait et ne fait pas l' opérateur JavaScript.L'
=
opérateur ne fait pas de copie des données.L'
=
opérateur crée une nouvelle référence aux mêmes données.Après avoir exécuté votre code d'origine:
a
etb
sont maintenant deux noms différents pour le même objet .Toute modification que vous apportez au contenu de cet objet sera vue de la même manière que vous le référeniez via la
a
variable ou lab
variable. Ce sont le même objet.Ainsi, lorsque vous essayez plus tard de "revenir"
b
à l'a
objet d' origine avec ce code:Le code ne fait rien du tout , car
a
etb
sont exactement la même chose. Le code est le même que si vous aviez écrit:qui évidemment ne fera rien.
Pourquoi votre nouveau code fonctionne-t-il?
Ici, vous créez un tout nouvel objet avec le
{...}
littéral objet. Ce nouvel objet n'est pas le même que votre ancien objet. Vous définissez donc maintenantb
comme référence ce nouvel objet, 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 répertoriée dans la réponse d'Armand, ou puisque vous utilisez jQuery, utilisez simplement la
$.extend()
fonction . Cette fonction fera une copie superficielle ou une copie profonde d'un objet. (Ne confondez pas cela avec la$().clone()
méthode qui consiste à copier des éléments DOM, pas des objets.)Pour une copie superficielle:
Ou une copie complète:
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 littéral d'objet. Il crée un nouvel objet de niveau supérieur contenant des références aux mêmes propriétés que l'objet d'origine.
Si votre objet ne contient que des types primitifs tels que des nombres et des chaînes, une copie profonde et une copie superficielle feront exactement la même chose. Mais si votre objet contient d'autres objets ou tableaux imbriqués à l'intérieur, alors une copie superficielle ne copie pas ces objets imbriqués, elle crée simplement des références à eux. Vous pourriez donc avoir le même problème avec les objets imbriqués que vous aviez avec votre objet de niveau supérieur. Par exemple, étant donné cet objet:
Si vous faites une copie superficielle de cet objet, alors la
x
propriété de votre nouvel objet est le mêmex
objet que l'original:Maintenant, vos objets ressembleront à ceci:
Vous pouvez éviter cela avec une copie complète. La copie profonde est récursée dans chaque objet et tableau imbriqués (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. Donc changer
copy.x.y
n'affecterait pasobj.x.y
.Réponse courte: en cas de doute, vous voulez probablement une copie complète.
la source
$.extend()
fonction intégrée. Détails ci-dessus. :-)J'ai trouvé que l'utilisation de JSON fonctionne mais surveillez nos références circulaires
la source
let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)
donnera un TypeErrorla question est déjà résolue depuis assez longtemps, mais pour référence future une solution possible est
Attention, cela ne fonctionne correctement que si a est un tableau non imbriqué de nombres et de chaînes
la source
newVariable = originalVariable.valueOf();
pour les objets que vous pouvez utiliser,
b = Object.assign({},a);
la source
La raison en est simple. JavaScript utilise des références, donc lorsque vous affectez,
b = a
vous attribuez une référence àb
ainsi lors de la mise à jour,a
vous mettez également à jourb
J'ai trouvé cela sur stackoverflow et je vais aider à éviter des choses comme celle-ci à l'avenir en appelant simplement cette méthode si vous souhaitez faire une copie complète d'un objet.
la source
if (obj instanceof x) { ... }
être autrement si?Je ne comprends pas pourquoi les réponses sont si complexes. En Javascript, les primitives (chaînes, nombres, etc.) sont passées par valeur et copiées. Les objets, y compris les tableaux, sont passés par référence. Dans tous les cas, l'attribution d'une nouvelle valeur ou référence d'objet à «a» ne changera pas «b». Mais changer le contenu de «a» changera le contenu de «b».
Collez l'une des lignes ci-dessus (une à la fois) dans le nœud ou dans n'importe quelle console javascript du navigateur. Tapez ensuite n'importe quelle variable et la console affichera sa valeur.
la source
Pour les chaînes ou les valeurs d'entrée, vous pouvez simplement utiliser ceci:
la source
La plupart des réponses ici utilisent des méthodes intégrées ou des bibliothèques / frameworks. Cette méthode simple devrait fonctionner correctement:
la source
Object.assign({},a)
Je l'ai résolu moi-même pour le moment. La valeur d'origine n'a que 2 sous-propriétés. J'ai reformé un nouvel objet avec les propriétés de
a
, puis je l'ai attribuéb
. Désormais, mon gestionnaire d'événements est mis à jour uniquementb
et mon originala
reste tel quel.Cela fonctionne très bien. Je n'ai changé aucune ligne n'importe où dans mon code à l'exception de ce qui précède, et cela fonctionne exactement comme je le voulais. Alors, croyez-moi, rien d'autre n'a été mis à jour
a
.la source
Une solution pour AngularJS :
la source