깊은 복사(deep copy) (TIL 19일차)

"원래 다루려고 했던 주제는 아니지만.."


Javascript는 원시 자료형(primitive)과 객체 자료형(object)을 구분하고 있는데요. 원시 자료형은 값 그 자체를 복사해 전달하지만, 객체 자료형은 자료형을 가리키는 주소를 복사해 전달합니다.

let a = { b: 'c', d: 'e' };
let b = a;

console.log(a === b);  // true
b.f = 'g';
console.log(a); // {b: 'c', d: 'e', f: 'g'}

따라서 b = a 와 같은 방식으로 객체를 복사하면, 사실은 객체 그 자체가 복사되는 것이 아니라 객체를 가리키는 주소가 복사됩니다. a === b 가 성립하는 것도 가리키는 주소가 같기 때문이죠.

이런 방법은 b를 이용해 새로운 객체 속성을 추가할 때, a 도 같이 변하는 문제가 있습니다. 전혀 다른 곳에서 자료를 수정할 수 있는 위험성이 있죠. 실제로 b.f = 'g'; 라는 구문을 추가하면 b 는 물론이고, a 객체를 확인해도 f: 'g' 라는 새로운 속성이 추가된 것을 알 수 있습니다.

이를 해결하는 방법이 깊은 복사(deep copy)입니다. 주소를 복사하는 것이 아닌 새로운 객체를 만들어 전달하는 방법이죠. deep copy 에 여러가지 방법이 있지만 spread 문법으로 아주 간단하게 사용할 수 있습니다.

let a = { b: 'c', d: 'e' };
let b = { ...a };

console.log(b);  // { b: 'c', d: 'e' }
console.log(a === b);  // false
b.f = 'g';
console.log(a);  // { b: 'c', d: 'e' }
consolg.log(b);  // {b: 'c', d: 'e', f: 'g'}

spread 문법은 ...을 이용해 객체 내부의 속성을 풀어서 전개합니다. 그래서 {} 로 감싸주고 사용하게 되면 새로운 객체에 a 내부의 속성을 복사하게 되죠. 이 때 b 는 주소를 전달받은 것이 아닌 전혀 새로운 객체이기 때문에 a === b 는 false 가 됩니다.

또한 b.f = 'g'; 라는 구문을 추가해도 a 는 전혀 변화하지 않고 원래 모양을 유지하죠. 깊은 복사는 이처럼 a 객체의 속성을 b 로 복사해도 a 와 b 가 상호간의 영향을 미치지 않는 상태를 만들어주는 복사입니다.


객체 자료형의 복사는 사실 매우 중요하고 또 복잡하면서도 쉽지 않은 개념이라고 합니다. 위에서 언급한 spread 문법도 사실 개념적으로 완벽한 deep copy를 해주지는 않는다고 해요. 그래서 본격적인 공부와 블로깅은 내일 이어가보려고 합니다.

좋은 웹페이지 즐겨찾기