값 그 자체가 저장되는 String, Number, Boolen 등과 달리 Object, Array는 해당 데이터를 heap이라 불리우는 저장소에 보관해두고 그 주소값
을 저장해 둡니다.
const profile = {
name: '철수',
age: 8,
school: '다람쥐초등학교',
};
const profile2 = profile; // 주소값 복사
profile2.name; // '철수'
profile.name = '영희';
profile2.name; // '영희'
profile2에는 profile이라는 객체의 주소값
이 복사가 된 것이고 주소값 위치의 내용이 변한 것이기 때문에 원본의 변화가 같은 주소값을 참조하고 있는 복사본에게도 영향을 주게 됩니다.
const newProfile = {
name: '철수',
age: 13,
school: '다람쥐초등학교',
hobby: {
one: '수영',
two: '프로그래밍',
},
};
const newProfile2 = { ...newProfile };
newProfile2;
/*
{
name: '철수',
age: 13,
school: '다람쥐초등학교',
hobby: {
one: '수영',
two: '프로그래밍',
}
};
*/
profile.hobby.one = '공부';
profile2.hobby.one; // '공부'
위의 예시를 보면 spread 연산자를 사용했음에도 객체 내의 객체는 원본 객체와 같은 주소값을 공유하는 것을 확인할 수 있습니다. spread 연산자를 활용한 복사는 얕은 복사(Shallow copy)
이기 때문입니다.
객체를 그대로 복사하는 것에는 성공하였으나
만약 그 안에 또 다른 객체 혹은 배열이 존재한다면, 그 부분까지는 완전하게 복사하지 못하고 얕은 깊이만을 복사하는 방식을 이야기합니다.
실질적인 의미의 얕은 복사는 실제값이 아닌 주소값을 복사하는 방식을 의미하며,
spread 연산자를 통한 복사는 실제값을 복사하되 그 안의 객체, 배열은 주소값을 복사하기 때문에 얕은 복사라고 볼 수 있습니다.
newProfile
/*
{
name: '철수',
age: 13,
school: '다람쥐초등학교',
hobby: {
one: '수영',
two: '프로그래밍',
}
}
*/
JSON.stringify(newProfile);
// '{"name":"철수","age":13,"school":"다람쥐초등학교","hobby":{"one":"수영","two":"프로그래밍"}}'
JSON.stringify()
는 인자로 들어온 데이터를 문자열로 변환시켜줍니다.
JSON.stringify()
가 객체를 문자열로 변환시켜준다면,
그 반대의 역할을 하는 JSON.parse()
가 존재합니다.
JSON.parse()
는 JSON.stringify()
를 통해 얻어낸 문자열을 객체 형태로 변환시켜줍니다.
JSON.parse(JSON.stringify(newProfile))
/*
{
name: '철수',
age: 13,
school: '다람쥐초등학교',
hobby: {
one: '수영',
two: '프로그래밍',
}
}
*/
우리가 이전에 생성한 객체와 똑같은 모양, 값을 가진 객체를 복사했습니다.
이전의 얕은 복사를 통해 생성된 객체처럼 원본과 같은 주소값을 공유하는 객체가 아닌,
JSON.stringify()
, JSON.parse()
를 활용한 깊은 복사를 통해 생성된 완전히 독립적인 하나의 객체입니다.