객체(배열포함)는 변수에 저장될 때 메모리의 주소 값이 저장됩니다.
따라서 const로 선언한 객체 자체를 새로운값으로 재할당 하는 것이 아닌 객체의 요소를 바꾸는 것은 가능합니다.
const a = { name: '철수' }
a.name = '영희'
console.log(a) // { name: '영희' }
하지만 복사할 때는 문제가 발생합니다.
const a = { name: '철수' }
const b = a;
console.log(b) // { name: '철수' }
b.name = '영희'
console.log(a) // { name: '영희' }
변수 b에 a를 복사한 뒤 b만 이름을 영희로 바꿔주고 싶지만 a도 같이 바뀝니다.
주소값이 복사되었기 때문에 서로 같은 주소를 참조하여 어느 쪽을 바꾸든 같이 바뀌게 됩니다.
이를 해결 하기위해 스프레드 연산자를 활용해 보았습니다.
스프레드 연산자는 객체 혹은 배열의 요소들을 펼치는 기능을 합니다.
const child1 = {
name: '철수',
age: 13,
school: '다람쥐초등학교'
}
const child2 = {
...child1,
name: '영희'
}
console.log(child1) // { name: '철수', age: 13, school: '다람쥐초등학교' }
console.log(child2) // { name: '영희', age: 13, school: '다람쥐초등학교' }
객체의 속성들만 펼쳐 새로운 객체를 선언 했기에 영희가 잘 변경된걸 확인할 수 있습니다.
객체 리터럴{} 내에서 같은 키(name)의 값(child2.name = '영희')은 덮어 씌워집니다.
const a = [1, 2, 3]
const b = [0, ...a, 4, ...a]
console.log(b) // [0, 1, 2, 3, 4, 1, 2, 3]
하지만 spread는 1레벨의 깊이에서의 속성만 복사가 되기에 다음과 같이 속성의 값으로 객체가 있다면 복사가 아닌 참조를 하게 됩니다.
const child1 = {
name: {
first: '김',
last: '철수',
},
age: 13,
school: '다람쥐초등학교',
}
const child2 = {
...child1
}
child2.name.first = '안'
console.log(child1);
/*
{
name: { first: '안', last: '철수' },
age: 13,
school: '다람쥐초등학교'
}
*/
const child1 = {
name: '철수',
age: 8,
etc: {
school: '다람쥐초등학교',
money: 2000,
hobby: '수영',
}
}
const child2 = JSON.parse(JSON.stringify(child1));
child2.etc.school = '토끼초등학교';
console.log(child1);
/*
{
name: '철수',
age: 8,
etc: { school: '다람쥐초등학교', money: 2000, hobby: '수영' }
}
*/
JSON.stringify()는 객체를 통째로 문자열로 바꿔주고
바꿔준 문자열 값을 다시 JSON.parse()를 사용해 새객체로 만들어 주기에 깊은복사가 됩니다.
객체뿐만 아니라 배열에도 사용이 가능합니다. (배열 -> 문자 -> 배열)
import lodash from 'lodash';
const a = { x: { y: 1 } };
const b = lodash.cloneDeep(a);