#CutLongStoryShort
Dla spragnionych szybkiej odpowiedzi:
const newMobilePhones = JSON.parse(JSON.stringify(mobilePhones));
Cały artykuł dotyczący kopiowania obiektów w Javascript
Kopiowanie/duplikacja obiektów w języku JavaScript czasami zaskakuje. Nie wszystkie metody kopiowania sprawdzą się w każdym przypadku. Przeanalizujmy kilka sposobów kopiowania obiektów.
#1. Proste przypisane przy pomocy „=”
Załóżmy, że mamy obiekt mobilePhones i chcemy wartości tego obiektu przypisać do newMobilePhones a następnie zmienić wartości dla phone_1.
const mobilePhones = {
'phone_1' : {
brand: 'Samsung',
model: 'Galaxy Note 9'
},
'phone_2' : {
brand: 'Google',
model: 'Pixel 3'
},
'phone_3' : {
brand: 'Apple',
model: 'iPhone X'
}
}
const newMobilePhones = mobilePhones
newMobilePhones.phone_1 = {
brand: 'Nokia',
model: '3310'
}
console.log('Oryginal' , mobilePhones);
console.log('Duplicated' , newMobilePhones);
/*
**** Console log output ***
"Oryginal", {
!!!! Nadpisaliśmy wartość tego obiektu !!!!
phone_1: {
brand: "Nokia",
model: "3310"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
"Duplicated", {
phone_1: {
brand: "Nokia",
model: "3310"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
Powyższy kod przetestuj tutaj: https://jsfiddle.net/rytovsky/fckxut2g/
Podstawowe przypisanie const newMobilePhones = mobilePhones skutkuje tym, że nie kopiujemy wartości a jedynie referencje do obiektu.
Czym jest referencja? Jest to odwołanie newMobilePhones do mobilePhones. Jeżeli zmieniasz coś w newMobilePhones, finalnie zmieniasz wartości w mobilePhones.
#2. Przypisane przy pomocy spread separator { … }
A więc jak w bezpieczny sposób kopiować wartości obiektów, bez tworzenia referencji? Przedstawiam drugi przykład:
const mobilePhones = {
'phone_1': {
brand: 'Samsung',
model: 'Galaxy Note 9'
},
'phone_2': {
brand: 'Google',
model: 'Pixel 3'
},
'phone_3': {
brand: 'Apple',
model: 'iPhone X'
}
}
const newMobilePhones = {
...mobilePhones
}
newMobilePhones.phone_1 = {
brand: 'Nokia',
model: '3310'
}
console.log('Oryginal', mobilePhones);
console.log('Duplicated', newMobilePhones);
/*
**** Console log output ***
"Oryginal", {
phone_1: {
brand: "Samsung",
model: "Galaxy Note 9"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
"Duplicated", {
phone_1: {
brand: "Nokia",
model: "3310"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
Powyższy kod przetestuj tutaj: https://jsfiddle.net/rytovsky/fckxut2g/2/
W tym przypadku użyliśmy spread operator (trzykropek). Taki zapis pozwala nam na kopiowanie samych wartości obiektu (bez referencji do obiektu). Innymi słowy, trzykropek rozpakowuje obiekt mobilePhones a następnie jego wartości zostają przypisane do obiektu newMobilePhones.
const newMobilePhones = {
...mobilePhones
}
Ale!
Nie byłoby tego wpisu gdyby nie to, że powyższe rozwiązanie nie zadziała dla bardziej zagnieżdżonych obiektów.
Próbując zmienić wartość obiektu newMobilePhones w taki sposób:
newMobilePhones.phone_1.brand = 'Nokia'
newMobilePhones.phone_1.model = '3310'
Otrzymamy:
/*
**** Console log output ***
"Oryginal", {
phone_1: {
brand: "Nokia",
model: "3310"
}
...
}
"Duplicated", {
phone_1: {
brand: "Nokia",
model: "3310"
}
...
}
Sprawdź tutaj: https://jsfiddle.net/rytovsky/sgaxu81q/3/
Jak sobie z tym poradzić?
#3. Parsowanie obiektu do string a następnie konwertowanie do obiektu
const newMobilePhones = JSON.parse(JSON.stringify(mobilePhones));
Wygląda dziwnie ale działa, przeanalizujmy to.
Funkcja JSON.stringify() konwertuje obiekt mobilePhones w ciąg znaków (String), pozbywając się wszystkich własności obiektu, w tym referencji.
Funkcja JSON.parse() konwertuje ciąg znaków w nowy obiekt, bez referencyjnej przeszłości 😉
/*
**** Console log output ***
"Oryginal", {
phone_1: {
brand: "Samsung",
model: "Galaxy Note 9"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
"Duplicated", {
phone_1: {
brand: "Nokia",
model: "3310"
},
phone_2: {
brand: "Google",
model: "Pixel 3"
},
phone_3: {
brand: "Apple",
model: "iPhone X"
}
}
Czy działa?
Sam sprawdź tutaj: https://jsfiddle.net/rytovsky/sgaxu81q/4/