Tengo una variable que tiene un objeto JSON como valor. Asigno directamente esta variable a alguna otra variable para que compartan el mismo valor. Así es como funciona:
var a = $('#some_hidden_var').val(),
b = a;
Esto funciona y ambos tienen el mismo valor. Utilizo un mousemove
controlador de eventos para actualizar b
mi aplicación. Al hacer clic en un botón, quiero volver b
al valor original, es decir, el valor almacenado en a
.
$('#revert').on('click', function(e){
b = a;
});
Después de esto, si uso el mismo mousemove
controlador de eventos, actualiza ambos a
y b
, cuando antes, se actualizaba solo b
como se esperaba.
¡Estoy perplejo por este problema! ¿Que esta mal aquí?
javascript
jquery
Rutwick Gangurde
fuente
fuente
a
se configuró desde.val()
, supongo que es JSON (una cadena), no un objeto, ¿es así? ¿UsasJSON.parse(a)
en algún momento para obtener un objeto real?$.parseJSON
para convertirla en un objeto. Estructura:{ 'key': {...}, 'key': {...}, ...}
. Lo siento, no puedo publicar ningún código aquí, ¡no está permitido en mi lugar de trabajo!a
un objeto?a
una variable global?$.parseJSON()
entra?) Es difícil decir cuál es el problema. Con respecto a las reglas de su lugar de trabajo, no tiene que publicar su código real real en su totalidad, solo presente un ejemplo más corto y más genérico que demuestre el problema (e, idealmente, incluya un enlace a una demostración en vivo en jsfiddle.net ) .Respuestas:
Es importante comprender qué
=
hace y qué no hace el operador en JavaScript.El
=
operador no realiza una copia de los datos.El
=
operador crea una nueva referencia a los mismos datos.Después de ejecutar su código original:
a
yb
ahora son dos nombres diferentes para el mismo objeto .Cualquier cambio que realice en el contenido de este objeto se verá de manera idéntica ya sea que haga referencia a él a través de la
a
variable o lab
variable. Son el mismo objeto.Entonces, cuando más tarde intente "volver"
b
ala
objeto original con este código:El código en realidad no hace nada en absoluto , porque
a
yb
son exactamente lo mismo. El código es el mismo que si hubiera escrito:que obviamente no hará nada.
¿Por qué funciona tu nuevo código?
Aquí está creando un objeto nuevo con el
{...}
objeto literal. Este nuevo objeto no es el mismo que su antiguo objeto. Así que ahora estás configurandob
como referencia a este nuevo objeto, que hace lo que quiere.Para manejar cualquier objeto arbitrario, puede usar una función de clonación de objetos como la que se enumera en la respuesta de Armand, o como está usando jQuery, simplemente use la
$.extend()
función . Esta función hará una copia superficial o una copia profunda de un objeto. (No confunda esto con el$().clone()
método que es para copiar elementos DOM, no objetos).Para una copia superficial:
O una copia profunda:
¿Cuál es la diferencia entre una copia superficial y una profunda? Una copia superficial es similar a su código que crea un nuevo objeto con un objeto literal. Crea un nuevo objeto de nivel superior que contiene referencias a las mismas propiedades que el objeto original.
Si su objeto contiene solo tipos primitivos como números y cadenas, una copia profunda y una copia superficial harán exactamente lo mismo. Pero si su objeto contiene otros objetos o matrices anidadas dentro de él, entonces una copia superficial no copia esos objetos anidados, simplemente crea referencias a ellos. Entonces, podría tener el mismo problema con los objetos anidados que tenía con su objeto de nivel superior. Por ejemplo, dado este objeto:
Si hace una copia superficial de ese objeto, entonces la
x
propiedad de su nuevo objeto es el mismox
objeto del original:Ahora sus objetos se verán así:
Puede evitar esto con una copia profunda. La copia profunda se repite en cada objeto y matriz anidados (y Fecha en el código de Armand) para hacer copias de esos objetos de la misma manera que hizo una copia del objeto de nivel superior. Así que cambiar
copy.x.y
no afectaríaobj.x.y
.Respuesta corta: en caso de duda, probablemente desee una copia detallada.
fuente
$.extend()
función incorporada. Detalles arriba. :-)Encontré que usar JSON funciona, pero observe nuestras referencias circulares
fuente
let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)
dará un TypeErrorla pregunta ya está resuelta desde hace bastante tiempo, pero para referencia futura una posible solución es
Tenga cuidado, esto funciona correctamente solo si a es una matriz no anidada de números y cadenas
fuente
newVariable = originalVariable.valueOf();
para los objetos que puedes usar,
b = Object.assign({},a);
fuente
La razón de esto es simple. JavaScript usa referencias, por lo que cuando asigna
b = a
, está asignando una referencia a, por lob
tanto, al actualizara
, también está actualizandob
Encontré esto en stackoverflow y ayudaré a prevenir cosas como esta en el futuro simplemente llamando a este método si desea hacer una copia profunda de un objeto.
fuente
if (obj instanceof x) { ... }
si?No entiendo por qué las respuestas son tan complejas. En Javascript, las primitivas (cadenas, números, etc.) se pasan por valor y se copian. Los objetos, incluidas las matrices, se pasan por referencia. En cualquier caso, la asignación de un nuevo valor o referencia de objeto a 'a' no cambiará 'b'. Pero cambiar el contenido de 'a' cambiará el contenido de 'b'.
Pegue cualquiera de las líneas anteriores (una a la vez) en el nodo o en cualquier consola javascript del navegador. Luego escriba cualquier variable y la consola mostrará su valor.
fuente
Para cadenas o valores de entrada, simplemente puede usar esto:
fuente
La mayoría de las respuestas aquí usan métodos integrados o bibliotecas / marcos. Este método simple debería funcionar bien:
fuente
Object.assign({},a)
Lo resolví yo mismo por el momento. El valor original tiene solo 2 subpropiedades. Reformé un nuevo objeto con las propiedades de
a
y luego se lo asignéb
. Ahora mi controlador de eventos solo se actualizab
, y mi originala
permanece como está.Esto funciona bien. No he cambiado una sola línea en ningún lugar de mi código, excepto lo anterior, y funciona exactamente como quería. Entonces, créame, nada más se estaba actualizando
a
.fuente
Una solución para AngularJS :
fuente