Se o JavaScript é uma passagem por referência ou uma passagem por tipo de valor

  1. Tipos de dados primitivos em JavaScript são passados ​​por valor
  2. Valores não primitivos em JavaScript são passados ​​por referência
  3. JavaScript é tanto passagem por valor quanto passagem por referência

Antes de nos aprofundarmos em se a linguagem de programação JavaScript é um tipo de passagem por referência ou não, vamos primeiro ver a diferença entre passagem por valor e passagem por referência.

Essas coisas geralmente entram em cena quando estamos fazendo operações de atribuição ou lidando com as próprias funções. Como na maioria das vezes, realizamos operações de atribuição, criamos várias funções e passamos várias variáveis ​​para essas funções, saber como essas coisas funcionam internamente nos daria uma compreensão mais profunda da linguagem de programação.

Sempre que atribuímos ou passamos o valor de uma variável para outra variável ou função, isso é conhecido como passagem por valor. Quando atribuímos ou passamos o endereço de uma variável para outra variável ou função, isso é conhecido como passagem por referência.

Agora que vimos a definição básica dos tipos de passagem por valor e passagem por referência, vamos entender melhor como eles são usados ​​nos exemplos a seguir abaixo.

Tipos de dados primitivos em JavaScript são passados ​​por valor

Observe que existem dois tipos de dados em JavaScript: o tipo de dados primitivo e o tipo de dados não primitivo. Os tipos de dados primitivos consistem em números, booleanos, strings, indefinidos e nulos.

Esses tipos de dados não têm métodos predefinidos como temos em objetos ou matrizes. Os tipos de dados primitivos são imutáveis; isso significa que sempre que você armazena ou atribui o valor de uma variável primitiva a outra e faz algumas modificações no valor da segunda variável, o valor da primeira variável não muda. Ele permanecerá como está até e a menos que você altere o valor da própria variável. Só então a segunda variável será alterada.

Você pode encontrar mais informações relacionadas aos tipos de dados primitivos em MDN.

// Example 1
let a = 10;
let b = a;
b = b + 1;

console.log(a);
console.log(b);


// Example 2
let name = "Google";

let greet = (val) => {
   val = "Hi " + name +"!";
   return val;
 }

console.log(name);
console.log(greet(name));

Produção:

10
11
Google
Hi Google!

O código acima pode ser melhor compreendido com a ajuda da ilustração abaixo. Observe que isso explica apenas o primeiro exemplo de código; o segundo exemplo funcionará basicamente da mesma maneira que o exemplo um.

visualização de exemplo de tipo primitivo

Em nosso primeiro exemplo, temos duas variáveis: a e b. Atribuímos um valor numérico de 10 à nossa variável a; isso alocará um espaço para a variável a na memória, representada pela cor amarela com um endereço 0x01 (que é apenas um endereço arbitrário tomado para este exemplo).

Em seguida, atribuímos a variável a à variável b. Este processo alocará o novo espaço de memória para a variável b. Aqui, ele armazenará o valor da variável a, que é 10.

A partir do exemplo acima, podemos ver claramente que o endereço de ambas as variáveis ​​a e b é diferente, o que significa que elas atribuíram espaços diferentes na memória. Este resultado implica que sempre que você alterar ou modificar o valor da variável b como b = b + 1, o valor dentro da variável a não será alterado. Apenas o valor da variável b mudará e se tornará 11, pois estamos incrementando em um.

Em nosso segundo exemplo, temos uma variável name com um valor Google dentro. Também temos uma função chamada greet(), que recebe um valor de string como argumento e retorna uma nova string. Como argumento para esta função, passamos a variável a (note que passar uma variável significa passar seu valor e não seu endereço). O valor Google será armazenado dentro da variável local da função chamada val.

Atualmente, a variável val contém o valor Google. Na função, estamos alterando esse valor para Hi Google! e, em seguida, retornando esse valor. Agora, se você produzir o valor das variáveis ​​name e as funções, junto com o valor retornado, ambos serão diferentes. As variáveis ​​name permanecem inalteradas porque ambas as variáveis ​​name e val são armazenadas em locais diferentes, e estamos apenas passando o valor Google para a função e o endereço.

Anteriormente, vimos a definição de passagem por valor, que dizia que apenas passamos o valor da variável durante uma atribuição ou enquanto o passamos para uma função. Os dois exemplos acima demonstraram isso na prática.

Valores não primitivos em JavaScript são passados ​​por referência

Os tipos de dados não primitivos consistem em matrizes, objetos ou classes. Esses tipos de dados têm funções internas predefinidas que nos permitem manipular os dados dentro dos arrays ou dos objetos.

Os tipos de dados primitivos são mutáveis; isso significa que os tipos de dados que podem ser modificados posteriormente são conhecidos como mutáveis. Além disso, os tipos de dados não primitivos são chamados por referência. Vamos entender isso com o exemplo abaixo.

let a = [1,2];
let b = a;
b.push(3);

console.log(a)
console.log(b)

Produção:

[ 1, 2, 3 ]
[ 1, 2, 3 ]

A imagem do exemplo acima é mostrada abaixo.

exemplo de tipo não premitiv

Neste exemplo, criamos um array a com dois elementos: [1,2]. Visto que um array é um tipo de dados não primitivo, a variável a não armazenará todos os elementos do array. Em vez disso, os valores [1,2] serão armazenados em outro local na memória. Neste caso, o endereço inicial desse array, neste caso, 0x01, será armazenado na variável a, conforme mostrado no diagrama acima. Uma vez que a variável a tem o endereço onde os elementos reais do array são armazenados, ela apontará para esse local.

Quando atribuímos a variável a à variável b, estamos armazenando o endereço presente dentro de a na variável b. Agora, a variável b também apontará para a mesma localização de memória, 0x011 como aquela da variável a, uma vez que ambas têm o mesmo endereço de memória. Portanto, se você alterar os elementos de um array apontado por b, então a também será afetado porque ambos estão apontando para o mesmo local.

Aqui, estamos inserindo um novo elemento na matriz usando a variável b como b.push(3). Agora, a variável b percorrerá todo o array começando do primeiro elemento, 1, até o último elemento, 2. Após o último elemento, ele irá inserir o novo elemento 3 no array. Se você imprimir as variáveis ​​a e b, verá que ambas mostrarão o mesmo valor que [1,2,3] por causa da referência.

Isso é conhecido como passagem por referência porque estamos passando o próprio endereço de memória e não o valor.

JavaScript é tanto passagem por valor quanto passagem por referência

A linguagem de programação JavaScript suporta passagem por valor e passagem por referência. Valores primitivos como números, booleanos, strings, undefined e null são todos passados ​​por valores. Tipos não primitivos, como matrizes, objetos e classes, são passados ​​por referência.