본문 바로가기
FE/Javascript

Shallow Copy & Deep Copy

by ideal_string 2022. 9. 24.

객체를 열심히 만들고 새로운 객체에 이전 객체 값을 복사해 사용하다보면 난감한 일이 생긴다. 복사본을 수정했음에도 원본 객체가 바뀌는 일이다. 이때 깊은 복사(Deep Copy)와 얕은 복사(Shallow Copy)를 알아야할 때다. 이는 지난 번에 올렸던 원시 타입과 참조 타입을 알고 있다면 상대적으로 이해하기 쉽다. 참조 타입 특성으로 인해 나타나는 차이기 때문이다. 

얕은 복사

const first = {
	name:"코난",
    age:8,
    school:"타이탄초등학교"
}

const second = first;
console.log(second) // { name: '코난', age: 8, school: '타이탄초등학교' }

위와 같이 코드를 작성했다면 second에 first에 객체가 그대로 복사된다. 복사가 완료됐으니 우리는 그런줄 알고 second를 열심히 수정한다. 아래처럼.

second.name = "유명한"
second.age = 40
second.school = "유명한명탐정사무소"

console.log(second) // { name: '유명한', age: 40, school: '유명한명탐정사무소' }

보통 이렇게 바꿔두고 혼자 뿌듯해 한다. first를 찍기 전까지는.

const first = {
	name:"코난",
    age:8,
    school:"타이탄초등학교"
}

const second = first;
console.log(second) // { name: '코난', age: 8, school: '타이탄초등학교' }

second.name = "유명한"
second.age = 40
second.school = "유명한명탐정사무소"

console.log(second) //{ name: '유명한', age: 40, school: '유명한명탐정사무소' }
console.log(first) //{ name: '유명한', age: 40, school: '유명한명탐정사무소' }

분명 second를 바꿨음에도 first에 있는 값이 바뀌었다. second로 복사한 게 바로 얕은 복사기 때문이다. 참조 타입은 복사할 때 객체 자체가 아닌 객체가 담긴 주소가 복사되었기에 second를 바꿔도 first도 함께 바뀐 것이다. 다만 원시타입이라면 정상적으로 복사된다.

 

깊은 복사

얕은 복사 같은 일 없이 제대로 복사하려면 깊은 복사가 필요하다. 깊은 복사하는 방법은 반복문을 돌리며 엘리먼트 각각을 복사해오거나, 전개연산자를 쓰기도 한다. 다만 전개연산자의 경우 이중 객체(중첩 객체)라면 안에 있는 객체는 얕은 복사가 된다. 이중 가장 쉬운 깊은 복사 방법은 JSON.stringify()와 JSON.parse()를 이용하는 거다.

const first = {
	name:"코난",
    age:8,
    school:"타이탄초등학교"
}

const convert = JSON.stringify(first);
const second = JSON.parse(convert)
console.log(second) // { name: '코난', age: 8, school: '타이탄초등학교' }


second.name = "남도일"
second.age = 19
second.school = "청솔고등학교"
console.log(second) // { name: '남도일', age: 19, school: '청솔고등학교' }
console.log(first) // { name: '코난', age: 8, school: '타이탄초등학교' }

JSON을 이용해 모든 값을 문자열로 바꾼 후 다시 객체화 시킨다. 이게 되는 이유는 참조 타입을 생각하면 쉽다. 객체화 시키는 순간, 주소 값이 사라지고 객체가 문자열만 남기 때문이다. 이를 다시 원본화 시킨다면 새로운 주소 값에 해당 객체가 담기게 된다. 이로써 기존 first 객체와 second 객체는 다른 주소를 가진 각각의 객체가 되었다. 제대로 된 복사가 된 것. 이런 원리로 인해 이중 객체라 하더라도 깊은 복사된다.

 

마무리

깊은 복사와 얕은 복사도 은근히 놓치기 쉬운 부분 같다. 특히 배우는 초반에 의도치 않은 오류를 나타내는 일등공신이다. 알고나면 왜 틀렸는지 알 수 있으나, 모른다면 자괴감에 빠지기 쉽다. 그게 바로 나다. 그래서 다시는 잊지 않기 위해 정리해둔다.

※ 잘못된 내용이 있을 경우 댓글로 알려주세요. 배우고 익히고 수정하겠습니다:)

'FE > Javascript' 카테고리의 다른 글

Throttling & Debouncing at Search  (1) 2022.10.04
Object.keys, values, entries, assign  (0) 2022.10.03
== & ===  (1) 2022.09.23
Primitive type & Reference type  (0) 2022.09.20
null & undefined  (0) 2022.09.15