É 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:
var a = $('#some_hidden_var').val(),
b = a;
a
e b
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 o a
objeto original com este código:
b = a;
O código realmente não faz nada , porque a
e b
são exatamente a mesma coisa. O código é o mesmo que se você tivesse escrito:
b = b;
que obviamente não fará nada.
Por que seu novo código funciona?
b = { key1: a.key1, key2: a.key2 };
Aqui você está criando um novo objeto com o {...}
literal de objeto. Este novo objeto não é igual ao antigo. Portanto, agora você está definindo b
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:
b = $.extend( {}, a );
Ou uma cópia profunda:
b = $.extend( true, {}, a );
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:
var obj = {
w: 123,
x: {
y: 456,
z: 789
}
};
Se você fizer uma cópia superficial desse objeto, a x
propriedade do seu novo objeto será o mesmo x
objeto do original:
var copy = $.extend( {}, obj );
copy.w = 321;
copy.x.y = 654;
Agora seus objetos ficarão assim:
// 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
}
};
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.
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?