Eu tenho uma variável que tem um objeto JSON como valor. Eu atribuo essa variável diretamente a alguma outra variável para que elas compartilhem o mesmo valor. É assim que funciona:
var a = $('#some_hidden_var').val(),
b = a;
Isso funciona e ambos têm o mesmo valor. Eu uso um mousemove
manipulador de eventos para atualizar b
meu aplicativo. Com um clique de botão, desejo reverter b
para o valor original, ou seja, o valor armazenado em a
.
$('#revert').on('click', function(e){
b = a;
});
Depois disso, se eu usar o mesmo mousemove
manipulador de eventos, ele atualiza ambos a
e b
, quando antes, ele estava atualizando apenas b
conforme o esperado.
Estou perplexo com esse problema! O que há de errado aqui?
javascript
jquery
Rutwick Gangurde
fonte
fonte
a
foi definido a partir de.val()
, presumo que seja JSON (uma string), não um objeto - certo? Você usaJSON.parse(a)
em algum ponto para obter um objeto real?$.parseJSON
convertê-la em um objeto. Estrutura:{ 'key': {...}, 'key': {...}, ...}
. Desculpe, não posso postar nenhum código aqui, não é permitido em meu local de trabalho!a
um objeto?a
uma variável global?$.parseJSON()
entra isso?), É difícil dizer qual é o problema. Com relação às regras do seu local de trabalho, você não precisa postar seu código real completo, apenas crie um exemplo mais curto e genérico que demonstre o problema (e, idealmente, inclua um link para uma demonstração ao vivo em jsfiddle.net ) .Respostas:
É importante entender o que o
=
operador em JavaScript faz e o que não faz.O
=
operador não faz uma cópia dos dados.O
=
operador cria uma nova referência para os mesmos dados.Depois de executar seu código original:
a
eb
agora são dois nomes diferentes para o mesmo objeto .Qualquer alteração que você fizer no conteúdo deste objeto será vista de forma idêntica, quer você faça referência a ela por meio da
a
variável ou dob
variável. Eles são o mesmo objeto.Então, quando você tentar "reverter" mais tarde
b
para oa
objeto original com este código:O código realmente não faz nada , porque
a
eb
são exatamente a mesma coisa. O código é o mesmo que se você tivesse escrito:que obviamente não fará nada.
Por que seu novo código funciona?
Aqui você está criando um novo objeto com o
{...}
literal de objeto. Este novo objeto não é igual ao antigo. Portanto, agora você está definindob
como referência este novo objeto, que faz o que você deseja.Para lidar com qualquer objeto arbitrário, você pode usar uma função de clonagem de objeto como a listada na resposta de Armand ou, já que está usando jQuery, apenas use a
$.extend()
função . Esta função fará uma cópia superficial ou profunda de um objeto. (Não confunda isso com o$().clone()
método que é para copiar elementos DOM, não objetos.)Para uma cópia superficial:
Ou uma cópia profunda:
Qual é a diferença entre uma cópia superficial e uma cópia profunda? Uma cópia superficial é semelhante ao seu código que cria um novo objeto com um literal de objeto. Ele cria um novo objeto de nível superior contendo referências às mesmas propriedades do objeto original.
Se o seu objeto contém apenas tipos primitivos, como números e strings, uma cópia profunda e uma cópia superficial farão exatamente a mesma coisa. Mas se o seu objeto contém outros objetos ou matrizes aninhados dentro dele, então uma cópia superficial não copia esses objetos aninhados, apenas cria referências a eles. Portanto, você pode ter o mesmo problema com objetos aninhados que teve com seu objeto de nível superior. Por exemplo, dado este objeto:
Se você fizer uma cópia superficial desse objeto, a
x
propriedade do seu novo objeto será o mesmox
objeto do original:Agora seus objetos ficarão assim:
Você pode evitar isso com uma cópia profunda. A cópia profunda recorre em cada objeto e matriz aninhados (e Data no código de Armand) para fazer cópias desses objetos da mesma forma que fez uma cópia do objeto de nível superior. Portanto, a mudança
copy.x.y
não afetariaobj.x.y
.Resposta curta: em caso de dúvida, você provavelmente deseja uma cópia profunda.
fonte
$.extend()
função integrada. Detalhes acima. :-)Descobri que usar JSON funciona, mas observe nosso para referências circulares
fonte
let a = {}; let b = {a:a}; a.b = b; JSON.stringify(a)
dará uma questão já está resolvida há muito tempo, mas para referência futura uma possível solução é
Tenha cuidado, isso funciona corretamente apenas se a for uma matriz não aninhada de números e strings
fonte
newVariable = originalVariable.valueOf();
para objetos que você pode usar,
b = Object.assign({},a);
fonte
A razão para isso é simples. JavaScript usa referências, então, quando você atribui
b = a
uma referênciab
,a
você também está atualizandob
Eu encontrei isso no stackoverflow e ajudarei a evitar coisas como essa no futuro apenas chamando esse método se você quiser fazer uma cópia profunda de um objeto.
fonte
if (obj instanceof x) { ... }
senão?Não entendo por que as respostas são tão complexas. Em Javascript, primitivos (strings, números, etc) são passados por valor e copiados. Objetos, incluindo matrizes, são passados por referência. Em qualquer caso, a atribuição de um novo valor ou referência de objeto a 'a' não mudará 'b'. Mas alterar o conteúdo de 'a' mudará o conteúdo de 'b'.
Cole qualquer uma das linhas acima (uma de cada vez) no nó ou em qualquer console javascript do navegador. Em seguida, digite qualquer variável e o console mostrará seu valor.
fonte
Para strings ou valores de entrada, você pode simplesmente usar isto:
fonte
A maioria das respostas aqui está usando métodos integrados ou usando bibliotecas / estruturas. Este método simples deve funcionar bem:
fonte
Object.assign({},a)
Eu mesmo resolvi por enquanto. O valor original tem apenas 2 subpropriedades. Reformulei um novo objeto com as propriedades de
a
e atribuí a eleb
. Agora, meu manipulador de eventos é atualizado apenasb
e o originala
permanece como está.Isso funciona bem. Eu não mudei uma única linha em qualquer lugar do meu código, exceto a acima, e funciona exatamente como eu queria. Então, acredite em mim, nada mais estava atualizando
a
.fonte
Uma solução para AngularJS :
fonte