🧩

Value Types and Reference Types

Como vimos na página
🐵
Primitives
, a linguagem Javascript tem dois tipos de valores:
  • Primitivos
    • Variáveis do tipo primitivo são passadas por valor
  • Não primitivos
    • Variáveis do tipo não primitivo são passadas por referência

Stack e Heap

Quando declaramos variáveis, o engine aloca memória em duas regiões diferentes: call stack e heap.
Dados estáticos são aqueles que tem tamanho fixo em tempo de compilação, e pelo fato de não sofrerem alterações, são armazenados na call stack:
  • Valores primitivos
  • Valores da referência para objetos

Primitivos

O exemplo abaixo declara e inicializa duas variáveis e seus valores são uma string e um número, ambos literais. Ambas são variáveis com valores primitivos, então são armazenadas na call stack.
const name = "John" const age = 20
Para variáveis do tipo primitivo podemos dizer que a variável contém o valor:
  • name contém John
  • age contém 20
Quando atribuímos essas variáveis à outras variáveis, copiamos o valor para a nova variável
const name = "John" const anotherName = name
Tanto name quanto anotherName contém o valor John. O valor John foi copiado para a variável anotherName. Alterar uma não afeta a outra, pois ambas não tem relação
let name = "John" let anotherName = name name = "Mary" console.log(name, anotherName) // Output: Mary John

Não primitivos

Variáveis atribuídas com valores não primitivos recebem uma referência para aquele valor. Essa referência aponta para um objeto na memória. A variável não contem o valor do qual foi atribuída.
Os objetos são alocados no heap de memória. Quando escrevemos cont users = [], esse array é criado no heap de memória. O que a variável users recebe é o endereço de memória desse array.
Diferente do que acontece para primitivos, a engine não aloca um tamanho fixo de memória para os objetos, mas sim incrementa mais espaço conforme necessário.
const name = "John" const age = 20 const person = { name, age, }
Internamente, a engine irá alocar e armazenar na call stack as variáveis name e age. Já o objeto person terá seu valor alocado em um endereço de memória no heap. Esse endereço de memória será atribuído à variável person e armazenado no call stack.
Por isso, dizemos que a variável person é uma referência para um objeto.
Devido a esse motivo, quando atribuímos uma variável com valor não primitivo à uma outra, estamos apenas copiando o endereço de memória, e não o valor em si.
const person = { name: "John" } const anotherPerson = person console.log(person) // Output: { name: "John" } console.log(anotherPerson) // Output: { name: "John" } person.name = "Mary" console.log(person) // Output: { name: "Mary" } console.log(anotherPerson) // Output: { name: "Mary" }
No exemplo acima modificamos apenas a variável person, porém a variável anotherPerson também refletiu a alteração, já que seu valor é o endereço de memória do objeto inicializado pela variável person.

Passando parâmetros para funções

Quando passamos uma variável com valor primitivo para uma função, esse valor é copiado para seus parâmetros. Alterar esse parâmetro não irá refletir na variável original.
const first = 1 const second = 2 function multiply(a, b) { a = 3 console.log(a * b) } multiply(first, second) // Output: 6 console.log(first, second) // Output: 1 2
Quando passamos uma variável com valor não primitivo, essa variável pode ser usada como valor ou referência dependendo das condições:
  • Se alterarmos o valor desse parâmetro com um novo objeto, então o parâmetro será usado como valor, e o objeto original não será modificado, pois estamos atribuindo um novo valor para o parâmetro
const object = { name: "John" } function modify(param) { param = [1,2,3] console.log(param) } modify(object) // Output: [1,2,3] console.log(object) // Output: { name: "John" }
  • Se alterarmos alguma propriedade desse parâmetro, estamos modificando o objeto referenciado pela variável que foi passada. Logo, usamos o parâmetro como referência e o objeto original será modificado.
const object = { name: "John" } function modify(param) { param.name = "Mary" console.log(param) } modify(object) // Output: { name: "Mary" } console.log(object) // Output: { name: "Mary" }

Referências