Cómo controlar la referencia frente al valor en JavaScript

Este artículo analiza cómo se comportan los distintos tipos de datos de JavaScript cuando se asignan a una variable. Dependiendo del tipo de datos, la memoria se asigna de manera diferente para almacenarlos. Puede reservar un nuevo espacio para almacenar una copia del valor, o puede que no cree una copia en absoluto y solo apunte al valor existente (referencia).

Aquí están mis notas tomadas mientras seguía el curso Javascript30 de Wes Bos.

Números, cadenas y booleanos

En JavaScript, tipos primitivos como undefined, null, string, number, booleany symbolse pasan por valor.

let name = ‘Marina’;let name2 = name;
console.log({name, name2}); >> { name: ‘Marina’, name2: ‘Marina’ }
name = ‘Vinicius’;
console.log({name, name2});>> { name: ‘Vinicius’, name2: ‘Marina’ }

Cuando namese asigna la variable , 0x001se reserva un espacio en la memoria con una dirección de para almacenar ese valor. La variable nameluego apunta a esa dirección. name2Luego, la variable se establece en igual name. Se 0x002asigna un nuevo espacio en la memoria, con una nueva dirección y se almacena una copia del valor almacenado en la dirección a la que nameapunta.

Entonces, siempre que queramos modificar el valor de name, el valor almacenado por name2no cambiará, ya que es una copia, almacenada en una ubicación diferente.

Objetos y matrices

Los objetos en JavaScript se pasan por referencia. Cuando se establece más de una variable para almacenar una object, arrayo function, esas variables apuntarán al mismo espacio asignado en la memoria.

const animals = ['Cat', 'Dog', 'Horse', 'Snake'];
let animals2 = animals;console.log({animals, animals2});>>{ animals: ['Cat', 'Dog', 'Horse', 'Snake'], animals2: ['Cat', 'Dog', 'Horse', 'Snake']}
animals2[3] = 'Wale';console.log(animals, animals2);>>{ animals: ['Cat', 'Dog', 'Horse', 'Wale'], animals2: ['Cat', 'Dog', 'Horse', 'Wale']}

Cuando animalsse configura para almacenar una matriz, se asigna memoria y se asocia una dirección a esa variable. Entonces animals2se establece en igual animals. Dado que animalsalmacena una matriz, en lugar de crear una copia de esa matriz y una nueva dirección en la memoria, animals2simplemente se apunta al mismo objeto en la dirección existente. De esa manera, los cambios realizados en animals2se reflejarán animals, ya que apuntan a la misma ubicación.

Verá el mismo comportamiento para los objetos:

const person = { name: 'Marina', age: 29};
let femme = person;femme.age = 18;
console.log({person, femme});>>{ person: { name: 'Marina', age: 18 }, femme: { name: 'Marina', age: 18 }}

Copiar objetos y matrices

Dado que una simple asignación no es suficiente para producir una copia de un objeto, eso se puede lograr mediante otros enfoques:

Matrices

rebanada()

let animals2 = animals.slice();animals2[3] = 'Shark';

concat ()

let animals3 = [].concat(animals);animals3[3] = 'Tiger';

propagación (ES6)

let animals4 = [...animals];animals4[3] = 'Lion';

Los cambios afectarán solo al objeto modificado:

console.log({animals, animals2, animals3, animals4});>>{ animals: ['Cat', 'Dog', 'Horse', 'Snake'], animals2: ['Cat', 'Dog', 'Horse', 'Shark'], animals3: ['Cat', 'Dog', 'Horse', 'Tiger'], animals4: ['Cat', 'Dog', 'Horse', 'Lion']}

Objetos

asignar()

let human = Object.assign({}, person, { age: 20 });
console.log(person, human);>>{ person: { name: 'Marina', age: 29 }, human: { name: 'Marina', age: 20 }}

Clon profundo

Es importante tener en cuenta que esos métodos tienen solo un nivel de profundidad. Para los clones profundos, existe un método mal visto. Úselo con cuidado.

let femme3 = JSON.parse(JSON.stringify(person));femme3.name = 'Leslie';
console.log(person, femme3);>>{ person: { name: 'Marina', age: 29 }, femme3: { name: 'Leslie', age: 29 }}

Referencias

  • WesBos - Javascript 30
  • No conoces JS: alcance y cierres por Kyle Simpson

Publicado originalmente en marina-ferreira.github.io.