Meus dois centavos ... É assim que eu entendo. (Sinta-se livre para me corrigir se eu estiver errado)
É hora de jogar fora tudo o que você sabe sobre passar por valor / referência.
Porque em JavaScript, não importa se é passado por valor ou por referência ou o que for. O que importa é a mutação vs a atribuição dos parâmetros passados para uma função.
OK, deixe-me fazer o meu melhor para explicar o que quero dizer. Digamos que você tenha alguns objetos.
var object1 = {};
var object2 = {};
O que fizemos foi "atribuição" ... Atribuímos 2 objetos vazios separados às variáveis "objeto1" e "objeto2".
Agora, digamos que gostamos mais do objeto1 ... Então, "atribuímos" uma nova variável.
var favoriteObject = object1;
Em seguida, por qualquer motivo, decidimos que gostamos mais do objeto 2. Então, simplesmente fazemos uma pequena re-atribuição.
favoriteObject = object2;
Nada aconteceu ao objeto1 ou ao objeto2. Não alteramos nenhum dado. Tudo o que fizemos foi redesignar qual é o nosso objeto favorito. É importante saber que object2 e favoriteObject estão atribuídos ao mesmo objeto. Podemos mudar esse objeto através de qualquer uma dessas variáveis.
object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe
OK, agora vamos ver primitivas como cadeias de caracteres, por exemplo
var string1 = 'Hello world';
var string2 = 'Goodbye world';
Mais uma vez, escolhemos um favorito.
var favoriteString = string1;
Nossas variáveis favoriteString e string1 são atribuídas a 'Hello world'. Agora, e se quisermos mudar nossa string favorita ??? O que vai acontecer???
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'
Uh oh .... O que aconteceu. Não foi possível alterar a string1 alterando favoriteString ... Por que ?? Porque não mudamos nosso objeto string . Tudo o que fizemos foi "RE ASSIGN" a variável favoriteString para uma nova string. Isso basicamente o desconectou da string1. No exemplo anterior, quando renomeamos nosso objeto, não atribuímos nada. (Bem, não para a variável em si , ... no entanto, atribuímos a propriedade name a uma nova string.) Em vez disso, simplesmente modificamos o objeto que mantém as conexões entre as 2 variáveis e os objetos subjacentes. (Mesmo se quiséssemos modificar ou alterar o próprio objeto string, não poderíamos ter, porque as strings são realmente imutáveis em JavaScript.)
Agora, para funções e passagem de parâmetros .... Quando você chama uma função e passa um parâmetro, o que você está fazendo essencialmente é uma "atribuição" a uma nova variável, e funciona exatamente da mesma forma como se você tivesse simplesmente atribuído usando o sinal de igual (=).
Veja estes exemplos.
var myString = 'hello';
// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment
console.log(myString); // Logs 'hello'
console.log(param1); // Logs 'world'
Agora, a mesma coisa, mas com uma função
function myFunc(param1) {
param1 = 'world';
console.log(param1); // Logs 'world'
}
var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);
console.log(myString); // logs 'hello'
OK, agora vamos dar alguns exemplos usando objetos ... primeiro, sem a função
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;
// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'
// Now, let's reassign the variable
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object has no influence on the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';
Agora, a mesma coisa, mas com uma chamada de função
function myFunc(otherObj) {
// Let's mutate our object
otherObj.firstName = 'Sue';
console.log(otherObj.firstName); // Logs 'Sue'
// Now let's re-assign
otherObj = {
firstName: 'Jack',
lastName: 'Frost'
};
console.log(otherObj.firstName); // Logs 'Jack'
// Again, otherObj and myObject are assigned to 2 very different objects
// And mutating one object doesn't magically mutate the other
}
var myObject = {
firstName: 'Joe',
lastName: 'Smith'
};
// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);
console.log(myObject.firstName); // Logs 'Sue', just like before
OK, se você ler esta postagem inteira, talvez agora tenha uma melhor compreensão de como as chamadas de função funcionam em JavaScript. Não importa se algo é passado por referência ou por valor ... O que importa é atribuição versus mutação.
Toda vez que você passa uma variável para uma função, você está "Atribuindo" a qualquer que seja o nome da variável de parâmetro, como se você usasse o sinal de igual (=).
Lembre-se sempre de que o sinal de igual (=) significa atribuição. Lembre-se sempre de que passar um parâmetro para uma função em JavaScript também significa atribuição. Eles são iguais e as 2 variáveis são conectadas exatamente da mesma maneira (ou seja, não são, a menos que você conte que elas foram atribuídas ao mesmo objeto).
O único momento em que "modificar uma variável" afeta uma variável diferente é quando o objeto subjacente é alterado (nesse caso, você não modificou a variável, mas o próprio objeto.
Não faz sentido fazer uma distinção entre objetos e primitivas, porque funciona da mesma maneira exata como se você não tivesse uma função e apenas usasse o sinal de igual para atribuir a uma nova variável.
A única pegadinha é quando o nome da variável que você passa para a função é igual ao nome do parâmetro da função. Quando isso acontece, você deve tratar o parâmetro dentro da função como se fosse uma variável totalmente nova privada à função (porque é)
function myFunc(myString) {
// myString is private and does not affect the outer variable
myString = 'hello';
}
var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';
myFunc(myString);
console.log(myString); // Logs 'test'