Referências à objetos em JS

Publicado em 14/05/2016 - Javascript

No artigo de hoje veremos algo extremamente básico para qualquer linguagem de programação, mas que infelizmente muitos programadores web nem sequer conhecem.

Responda rápidamente: A passagem de parâmetros em Javascript é feita por valor ou por referência?
Se a sua resposta foi "ambos, depende do tipo da variável passada", parabéns ;)
Caso contrário, esse artigo é para você.

De forma direta e resumida, o javascript utiliza passagem de parêmetros por VALOR quando a variável é de algum tipo primitivo (ou seja, quando typeof da variável é "number", "string", "boolean", "undefined" ou "null"), e utiliza passagem de parâmetros por REFERÊNCIA quando a variável é de algum tipo complexo ("object" ou "function").

Certamente, como um(a) bom(a) programador(a), você está pensando "Hm, interessante... But show me the code"
É prá já.

var meuNumero = 10;
var minhaString = "Meu Nome";

var somarCinco = function(parametro){
	parametro += 5;
}

var concatenarAlgo = function(parametro){
	parametro += " - Algo Concatenado";
}

somarCinco(meuNumero);
concatenarAlgo(minhaString);

//Qual será o valor de meuNumero agora?
console.log(meuNumero); // Acertou quem disse 10.

//Qual será o valor de minhaString agora?
console.log(minhaString); // Acertou quem disse "Meu Nome".

Deu para pareceber que a chamada à função não alterou o valor original dos parâmetros?
Agora vamos modificar um pouco nosso código, para que a passagem passe a ser por referência:

var meuObjeto = {};
meuObjeto.meuNumero = 10;
meuObjeto.minhaString = "Meu Nome";

var somarCinco = function(parametro){
	parametro.meuNumero += 5;
}

var concatenarAlgo = function(parametro){
	parametro.minhaString += " - Algo Concatenado";
}

somarCinco(meuObjeto);
concatenarAlgo(meuObjeto);

//Qual será o valor de meuObjeto.meuNumero agora?
console.log(meuObjeto.meuNumero); // Acertou quem disse 15.

//Qual será o valor de minhaString agora?
console.log(meuObjeto.minhaString); // Acertou quem disse "Meu Nome - Algo Concatenado".

Ou seja, neste segundo exemplo, a passagem foi feita por referência, e a chamada às funções reflete na alteração do valor original

Mas isto não se aplica apenas à passagem de parâmetros.
O mesmo vale também para a atribuição de valores às variáveis.

//Inicializar um objeto e atribuí-lo à uma váriável.
var a = {
	"primeiroItem": 1, 
	"segundoItem":2
};

// Atribuir esta variável à uma nova variável.
// O que acontecerá? Será que o javascript copia o objeto e
// fica com duas instancias dele na memória, sendo uma para "a" e outra para "b"?
var b = a;

// Adicionar uma nova propriedade ao objecto referenciado por "a"
a["terceiroItem"] = 3;

// E então, como estará "b" agora?
console.log(b);

Sim, no código acima, "b" estará com a propriedade "terceiroItem", mesmo sem numa ter cido adicionada diretamente à ela.
O que acontece é que tanto "a" quanto "b" referênciam-se à mesma instância do objeto criado na inicialização de "a". Ou seja, modificações em "a" refletem-se diretamente em "b", e vice-versa.

"Mas ok, Douglas, que diferença isso faz na minha vida?"

Bom, agora você tem como desenvolver códigos mais limpos, você sabe extamente o que esperar dos efeitos colaterais em chamadas de funções que recebem objetos e, sem contar que isto é fundamental para AngularJS (e outros frameworks complexos como ele, claro). Futuramente, farei alguns artigos sobre AngularJS e este conhecimento será pré-requisito.

Até mais e ótimos códigos. ;)