얕은 복사와 깊은 복사를 주제로 작성한 이 글은 정재남님의 저서 '코어 자바스크립트'를 참고하였다.
얕은 복사란 바로 아래 단계의 값만 복사하는 방법이다.
- 얕은 복사는 중첩 객체(객체인 프로퍼티를 갖는 객체)에서 참조형 데이터가 저장된 프로퍼티를 복사할 때 그 주소값만 복사한다는 의미이다.
- 이런 경우 해당 프로퍼티에 대해 원본과 사본이 모두 동일한 참조형 데이터의 주소를 가리키게 된다.
- 얕은 복사본을 바꾸면 원본도 바뀐다.
스프레드 연산자 ...를 사용하면 얕은 복사를 수행할 수 있다.
const origin = {
name: "캐비지",
gender: "남성",
favoriteFood: {
first: "라면",
second: "김밥",
},
};
const copy = {...origin};
copy.name = "cabbage";
copy.favoriteFood.first = "빵";
console.log(origin);
console.log(copy);
origin 객체를 얕은 복사해 copy 객체에 할당한다.copy 객체의 name 키에 해당하는 값을 "cabbage"로 변경한다.copy 객체의 중첩된 객체인 favoriteFood 객체의 first 키에 해당하는 값을 "빵"으로 변경한다.출력 결과
// origin
{
name: '캐비지',
gender: '남성',
favoriteFood: { first: '빵', second: '김밥' }
}
// copy
{
name: 'cabbage',
gender: '남성',
favoriteFood: { first: '빵', second: '김밥' }
}
copy 객체의 name 키에 해당하는 값만 변경된다.origin 객체의 name 키에 해당하는 값은 변경되지 않았음copy 객체의 중첩된 객체인 favoriteFood 객체의 first 키에 해당하는 값을 변경했더니, origin 객체의 favoriteFood 객체의 first 키에 해당하는 값도 변경되었다.이런 출력 결과가 나온 것은 얕은 복사를 수행하면 바로 아래 단계의 값까지만 복사되기 때문이다. origin 객체와 copy 객체의 중첩된 객체인 favoriteFood 객체는 동일한 참조형 데이터이다. 즉, 동일한 객체를 참조한다는 것이다.
깊은 복사는 내부의 모든 값들을 하나하나 전부 복사하는 방법이다.
어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고 싶은 경우, 객체의 프로퍼티에서 값이 기본형 데이터인 경우에는 그대로 복사하면 되지만 참조형 데이터는 다시 그 내부의 프로퍼티들을 복사해야 합니다.
- 정재남 '코어 자바스크립트', P26
객체의 프로퍼티 값이 원시 타입의 값이라면 그대로 복사해도 무관하지만, 객체의 프로퍼티 값이 참조형이라면 다시 그 내부의 프로퍼티들을 복사해야 한다.
간단한 깊은 복사 방법은 JSON.stringify() 메서드와 JSON.parse() 메서드를 사용하는 방법이다.
JSON.stringify() 메서드
JSON.parse() 메서드
두 메서드를 사용하여 깊은 복사를 수행하는 예시 코드입니다.
const origin = {
name: "캐비지",
gender: "남성",
favoriteFood: {
first: "라면",
second: "김밥",
},
};
const deepCopy = JSON.parse(JSON.stringify(origin));
origin.favoriteFood.second = "우유";
deepCopy.favoriteFood.first = "빵";
console.log(origin);
console.log(deepCopy);
출력 결과
// origin
{
name: '캐비지',
gender: '남성',
favoriteFood: { first: '라면', second: '우유' }
}
// deepCopy
{
name: '캐비지',
gender: '남성',
favoriteFood: { first: '빵', second: '김밥' }
}
origin 객체의 중첩 객체인 favoriteFood의 second 키에 해당하는 값을 "우유"로 변경한다.deepCopy 객체의 중첩 객체인 favoriteFood의 second 키에 해당하는 값이 변경되지 않았다.deepCopy 객체의 중첩 객체인 favoriteFood의 first 키에 해당하는 값을 "빵"으로 변경한다.origin 객체의 중첩 객체인 favoriteFood의 first 키에 해당하는 값이 변경되지 않았다.객체의 프로퍼티 값이 참조형이라면 깊은 복사를 수행해야 다시 그 내부의 프로퍼티들이 복사되는 것을 알 수 있다. 깊은 복사를 수행하면 원본 객체와 사본 객체는 서로 다른 참조형 데이터가 된다. 즉, 서로 다른 객체를 참조한다는 것이다.
메서드(함수)나 숨겨진 프로퍼티인 __proto__나 getter/setter 등과 같이 JSON으로 변경할 수 없는 프로퍼티들은 모두 무시합니다.
- 정재남, '코어 자바스크립트' P28