English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Breve discussão sobre referência e cópia (passagem por valor e por referência) no JavaScript

Parece que poucos falam sobre referências e cópias no JavaScript, mas entender esse conceito pode ajudar a compreender muitas coisas

Vamos começar com algo muito básico, veja quais tipos de dados são passados no JavaScript

Referência: objetos, arrays, funções

Cópia: números, booleanos

A string merece uma menção especial, pois devido à sua peculiaridade, não é possível determinar se é passado por referência ou por cópia de valor (já que o valor da string não pode ser alterado, a discussão sobre isso também não tem significado, mas quando usada para comparação, claramente é uma comparação por valor; falaremos sobre comparações em breve)

Vamos falar sobre como isso se manifesta no uso

O uso mais comum é a atribuição

var a = 1;
var b = a;  //Atribui uma cópia do valor de a
b ++;
alert(a);  //"1"A modificação de b não afeta a
/****************************************/
var a = [1};
var b = a;   //Atribui a referência de a 
b[0] ++;
alert(a); //"2"A modificação de b também é válida para a, mas claro, b = [2];Essa modificação não é útil para 'a'.

Parâmetros da função

Passagem por valor: A passagem para a função é uma cópia do número, as modificações da função nele são invisíveis externamente

var a = 1;
var b = 2;
function change(a,b) {
 var c = a;
 a = b;   //Cobertura com nova referência
 b = c;
 alert(a);  //"2"     
 alert(b);  //"1"
}
change(a,b);
alert(a);  //"1"     
alert(b);  //"2"

Passagem por valor:Passagem por referência: A passagem para a função é uma referência de número, as modificações da função em suas propriedades são visíveis externamente, mas a cobertura com uma nova referência é invisível externamente, por exemplo

var a = [1, 2, 3};
var b = [5, 6};
function change(a,b) {
 a[0] = 4;  //As modificações nas propriedades são visíveis externamente 
 var c = a;
 a = b;   //Cobertura com nova referência
 b = c;
 alert(a);  //"5,6"     
 alert(b);  //"4,2,3"
}
change(a,b);
alert(a);  //"4,2,3"
alert(b);   //"5,6"

Do resultado, podemos ver que 'a' e 'b' não foram trocados... Porque a nova referência cobre o externo invisível. Isso é muito natural, porque a função apenas obteve a referência e não tem o poder de mudar a referência

Isso é diferente

var a = [1, 2, 3};
var b = [5, 6};
function change() {
 var c = a;
 a[0] = 4;
 a = b;
 b = c;
};
change();
alert(a);  //"5,6"
alert(b);  //"4,2,3"

Aqui, a troca foi bem-sucedida 

Novamente, precisamos mencionar o escopo de bloco do js. Isso definitivamente geraria um erro de variável não definida em alguns outros idiomas, porque o js não tem escopo de bloco. Portanto, quando não encontra as variáveis 'a', 'b' dentro de 'change', ele automaticamente vai para o nível superior para encontrar, então 'a', 'b' aqui são referências de variáveis globais

E os 'a', 'b' acima são variáveis da função 'change', ao chamar a função, a referência de 'a', 'b' é atribuída a essas variáveis. No entanto, não podem mudar 'a', 'b' no escopo global. Mude o nome e é mais fácil entender

Isso é um pouco mencionado... Algo que se desviou do tema...

Voltemos para as considerações de comparação de referência e cópia na operação de comparação

A comparação por valor compara números, enquanto a comparação por referência compara referências, referências diferentes, mesmo que os números sejam iguais, não são iguais.

1 == 1;  //true
1 === 1;  //true
[0] == [0]; //false
[0][0] == [0][0];  //true
[0][0] === [0][0];  //true
[0].toString() == [0].toString();  //true 

No closure...

O closure é provavelmente a coisa mais complicada no js. A questão clássica da entrevista de nosso departamento, sempre em demanda e nunca desatualizada...

Aqui, eu não vou falar sobre as coisas do closure, apenas sobre a parte que envolve passagem por valor e referência. Quando eu determinar que posso explicar claramente com itens de clareza, linguagem clara e exemplos vívidos, então eu vou详细介绍这个在js não pode deixar de mencionar esse tipo de pessoa...

No closure, a função interna usa a variável local da função externa de forma de referência, não de cópia.

Na verdade, isso também é uma parte muito importante para entender o closures, pode ser usado para explicar um fenômeno de closure muito clássico, um exemplo que muitas vezes é usado para explicar closures.

/*Construa uma função, defina o manipulador de eventos para os nós do array, ao clicar em um nó, alerta o número do nó*/
var add_handlers = function (nodes) {
  var i;
  for (i = 0, l = nodes.length; i < l; i ++) {
    nodes[i].onclick = function (e) {
      alert(i);  // Claro, o resultado aqui é que o alert sempre será o número total de nós...
    }
  }
};

Por que o alert sempre é o número total de nós em vez do número esperado? Isso é fácil de explicar usando cópia e referência

Porque a função interna usa a referência do variável externa ao invés de cópia, isso significa que quando eu defino o evento onclick para cada nó, passo a referência de i para o alert, quando eu clico no nó e ativo o evento onclick, o valor de i já se tornou o número total de nós...

var add_handlers = function (nodes) {
  var i;
  for (i = 0, l = nodes.length; i < l; i ++) {
    nodes[i].onclick = function (i) {
      return function() {
      alert(i);  
      }
 }(i);
  }
};

A razão pela qual a modificação está correta é porque neste momento, a cópia do valor de i é passada, na verdade, é como uma função comum, não se deixe confundir com a adição de encapsulamento, retorne ao pensamento original para entender, a origem é a passagem por referência que mencionamos acima

Por coincidência, não se deixe intimidar pelo nome estranho de 'encapsulamento', na verdade, ele é o mesmo que o princípio da função que usamos no dia a dia, afastando-se das supostas características do 'longo ciclo de vida' e 'proteção de variáveis privadas' do encapsulamento, e vendo-o como uma função comum (ou pode ver a função global como um encapsulamento especial), é fácil entender

A chave é deixar para trás todas as glórias, retornando ao essencial... e eu perdi o fio outra vez...

Este breve ensaio sobre referência e cópia (passagem por valor e por referência) na JS é tudo o que o editor compartilha com vocês. Espero que isso seja útil e que vocês apoiem o tutorial Gritar.

Você também pode gostar