#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/