javascript - se duas variáveis compartilham a mesma referência para um tipo não primitivo, por que esse código não funciona
Atualmente, estou lidando com a compreensão de como os valores são atribuídos e passados no Javascript. Os valores de tipos primitivos são passados por cópia de valor, e os valores de tipos de objeto são passados por cópia de referência.
Se esse for o caso, então por que esta linha de código não faz com que a variável "yourAddress" mude a propriedade "street" para "321 cba street"?
var myAddress = {
street: "123 abc st",
};
var yourAddress = myAddress;
myAddress = { street: "321 cba street" }; // doesn't change the val
myAddress.street = "321 cba street"; // doesn't change the val
console.log(yourAddress.street);Por que reatribuir a variável ou modificar o nome da propriedade não afeta também a saída de yourAddress.street, já que ela tem a mesma referência que myAddress.
A razão para isso é o hoisting ou eu não estou entendendo algo aqui internamente com JS?
A versão deste código que funcionaria é esta, mas por quê?
var myAddress = {
street: "123 abc st",
};
myAddress = { street: "321 cba street" }; // doesn't change the val
myAddress.street = "321 cba street"; // doesn't change the val
var yourAddress = myAddress;
console.log(yourAddress.street);Resposta #1
myAddress = { street: "321 cba street" }; // doesn't change the val
Sim, porque isso reatribui myAddress para apontar para um objeto totalmente diferente de yourAddress, então, é claro, mudanças feitas posteriormente em myAddress não se refletirão em yourAddress. É como se yourAddress=myAddress nunca tivesse acontecido.
Voltando ao início do programa:
var myAddress = {
street: "123 abc st",
};
var yourAddress = myAddress;
Neste ponto, eis a que as variáveis apontam:
.------------------.
| object in memory | <------------ myAddress
`------------------`
^
+------------------------ yourAddress
Então, depois que a próxima linha for executada:
myAddress = { street: "321 cba street" }; // doesn't change the val
nós temos:
.------------------.
| object in memory | <------------ myAddress
`------------------`
.------------------.
| object in memory | <------------ yourAddress
`------------------`
Estes são dois objetos totalmente distintos sendo referenciados por variáveis separadas.
Remova a reatribuição para myAddress e você verá a mudança no objeto único acessado por várias variáveis como você espera.
var myAddress = {street: "123 abc st"};
var yourAddress = myAddress;
myAddress.street = "321 cba street";
console.log(yourAddress.street, myAddress.street);Esta situação (duas referências a um objeto na memória) é fundamentalmente a mesma que fazer uma chamada de função com um parâmetro de objeto. Uma nova variável é criada na pilha da função, mas ela não é uma cópia do objeto; é apenas uma referência aos mesmos dados subjacentes.
var fn = param => {
param.street = 42;
};
var myAddress = {street: "123 abc st"};
fn(myAddress);
console.log(myAddress.street);Resposta #2
Como você já entende, variáveis não primitivas armazenam apenas uma referência. Essa referência funciona como qualquer tipo primitivo (apenas a referência, não o objeto): ela pode ser copiada e reatribuída sem alterar a outra referência. Então, neste código, foo.bar ainda será 2:
let foo = {bar: 2};
let bar = foo;
bar = {bar: 5};
console.log(foo.bar);
A referência é copiada assim como qualquer tipo primitivo; a diferença é que você pode alterar um objeto através de uma referência.
