Jak poradzić sobie z odniesieniem do wartości w JavaScript

W tym artykule omówiono, jak zachowują się różne typy danych JavaScript, gdy są przypisane do zmiennej. W zależności od typu danych, pamięć jest przydzielana różnie w celu ich przechowywania. Może zarezerwować nowe miejsce do przechowywania kopii wartości lub może w ogóle nie tworzyć kopii i po prostu wskazywać istniejącą wartość (odniesienie).

Oto moje notatki zrobione podczas kursu Javascript30 przez Wesa Bosa.

Liczby, ciągi znaków i wartości logiczne

W JavaScript, prymitywnych typów, takich jak undefined, null, string, number, booleani symbolsą przekazywane przez wartość.

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

Kiedy zmienna namejest przypisana, miejsce w pamięci o adresie 0x001jest zarezerwowane do przechowywania tej wartości. Zmienna namewskazuje następnie na ten adres. Zmienna name2jest następnie ustawiana na równą name. Nowa przestrzeń w pamięci z nowym adresem 0x002jest przydzielana i przechowuje kopię wartości przechowywanej w adresie, na który namewskazuje.

Tak więc, ilekroć chcemy zmodyfikować wartość name, wartość przechowywana przez name2nie zostanie zmieniona, ponieważ jest to kopia przechowywana w innym miejscu.

Obiekty i tablice

Obiekty w JavaScript są przekazywane przez odwołanie. Gdy więcej niż jedna zmienna jest ustawiona na przechowywanie albo object, arrayalbo function, te zmienne będą wskazywać na to samo przydzielone miejsce w pamięci.

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']}

Gdy animalsustawione jest przechowywanie tablicy, alokowana jest pamięć i adres jest powiązany z tą zmienną. Następnie animals2jest ustawiony na równy animals. Ponieważ animalsprzechowuje tablicę, zamiast tworzyć kopię tej tablicy i nowy adres w pamięci, animals2jest po prostu wskazywany na ten sam obiekt w istniejącym adresie. W ten sposób wszelkie zmiany wprowadzone do animals2będą odzwierciedlać animals, ponieważ wskazują na tę samą lokalizację.

Zobaczysz to samo zachowanie dla obiektów:

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 }}

Kopiowanie obiektów i tablic

Ponieważ proste przypisanie nie wystarczy do utworzenia kopii obiektu, można to osiągnąć innymi podejściami:

Tablice

plasterek()

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

concat ()

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

rozprzestrzenianie się (ES6)

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

Zmiany będą miały wpływ tylko na zmodyfikowany obiekt:

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']}

Obiekty

przydzielać()

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

Deep Clone

Należy zauważyć, że te metody mają tylko jeden poziom głębokości. W przypadku głębokich klonów metoda jest źle widziana. Używaj ostrożnie.

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

Bibliografia

  • WesBos - Javascript 30
  • You Don't Know JS: Scope & Closures autorstwa Kyle'a Simpsona

Pierwotnie opublikowane na marina-ferreira.github.io.