JavaScript: Jak stworzyć głęboką kopię zagnieżdżonego obiektu?

Opublikowano: 18.08.2022 - tagi: JavaScript Obiekt Kopia

Kopiowanie obiektu

Stworzenie kopii obiekt jest proste:

const originalObj = {
	title: 'Foo',
	value: 100,
	tags: ['a', 'b', 'c']
};

const copyObj = {
	...originalObj
};

copyObj.title = 'Bar';
copyObj.value = 50;
copyObj.tags.push('d');

console.log('originalObj: ', originalObj); // { title: 'Foo', value: 100, tags: ['a', 'b', 'c'] }
console.log('copyObj: ', copyObj); // { title: 'Bar', value: 50, tags: ['a', 'b', 'c', 'd'] }

Za pomocą operatora spread: ... tworzymy kopię obiektu. Następnie zmieniamy w skopiowanym obiekcie jego parametry. Oryginał się nie zmieniał. I tak miało być :)

Niestety to nie zadziała dla obiektu zagnieżdżonego.

Kopiowanie obiektu zagnieżdżonego

Najpierw przykład:

const originalObj = {
	name: 'Janusz Kowalski',
	age: 57,
	address: {
		city: 'New York',
		street: '99 East Golf Street'
	}
};

const copyObj = {
	...originalObj
};

copyObj.name = 'Grażyna Kowalska';
copyObj.address.city = 'Chicago';
copyObj.address.street = '3109 15th St';

console.log('originalObj: ', originalObj); 
/* 
originalObj: 
{
  name: 'Janusz Kowalski',
  age: 57,
  address: {
    city: 'Chicago',
    street: '3109 15th St'
  }
}
*/

console.log('copyObj: ', copyObj);
/*
copyObj:
{
  name: 'Grażyna Kowalska',
  age: 57,
  address: {
    city: 'Chicago',
    street: '3109 15th St'
  }
}
*/

Kopia została stworzona, ale nie dla zagnieżdżonej części obiektu jak: address. Po zmianie danych w kopii zmieniły się też dane w oryginale!

Jak sobie z tym poradzić?

const originalObj = {
	name: 'Janusz Kowalski',
	age: 57,
	address: {
		city: 'New York',
		street: '99 East Golf Street'
	}
};

const copyObj = JSON.parse(JSON.stringify(originalObj))

copyObj.name = 'Grażyna Kowalska';
copyObj.address.city = 'Chicago';
copyObj.address.street = '3109 15th St';

console.log('originalObj: ', originalObj); 
/* 
originalObj: 
{
  ...,
	address: {
		city: 'New York',
		street: '99 East Golf Street'
	}
}
*/

console.log('copyObj: ', copyObj);
/*
copyObj:
{
  ...,
  "address": {
    "city": "Chicago",
    "street": "3109 15th St"
  }
}
*/

Kombinacja: JSON.parse i JSON.stringify rozwiązuje ten problem.

To rozwiązanie nie zadziała jeśli obiekt zawiera funkcje. Funkcje nie zostaną skopiowane.