[JS] shallow copy / deep copy

뚜벅맨·2021년 8월 15일
0

pass by Reference와 이어지는 글입니다.

요약

shallow copy(얕은 복사)deep copy(깊은 복사) 모두 복사한 대상에 대해서 새로운 객체를 생성하여 기존 객체에는 영향을 주지 않습니다. 그러나, 얕은 복사는 한 단계까지만 복사하고, 깊은 복사는 객체에 중첩된 객체까지 모두 복사하는 차이를 가집니다.
그렇기에 얕은 복사를 하면 한 단계만 복사하기 때문에 중첩된 객체에 대해서는 서로 영향을 주고, 깊은 복사는 중첩된 객체 역시 별개의 값으로서 서로 영향을 주지 않습니다.

원시값의 불변성

객체의 복사를 이야기하기 전에 앞서, 원시값(primitive)에 대해서 먼저 다루고 가겠습니다. 원시값변경 불가능한 불변의 값으로 String, Number, undefined, Boolean, Symbol, BigInt 등이 있습니다.
한번 생성된 원시 값은 read only 입니다.

변수 변경 ≠ 원시값의 변경

변수 값이 변경되는 것을 원시값이 변경된다고 생각하면 안 됩니다. 변수에 값이 할당되면 실제로는 메모리 공간에 값이 담기고 변수는 그 메모리 주소를 가리키게 됩니다.

원시 값을 할당한 변수에 새로운 원시 값을 재할당하면 메모리 공간에 저장되어 있는 재할당 이전의 원시 값을 변경하는 것이 아니라, 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후, 변수는 새롭게 재할당한 원시 값을 가르키게 됩니다.
위의 예시에서도 원시값인 undefined, 80, 90은 변경 불가능하므로 원시값을 재할당하였습니다. 이렇게 해서 원시값을 불변성을 유지하고, 변수는 가리키는 메모리 주소를 바꿔가며 변수 값을 변경합니다.

이러한 특성을 불변성(immutability)이라고 합니다. 이러한 원시 값의 특성은 데이터의 신뢰성을 보장합니다.

그렇기에 원시값을 갖는 변수를 다른 변수에 할당할 경우 원시값을 복사하면 값은 그대로 복사되지만, 같은 값을 가지는 별개의 메모리 공간을 가리킬 뿐이며, 각 변수는 서로에게 영향을 주지 않습니다.

객체

원시값과 달리 객체는 변경이 가능한 값입니다. 객체는 프로퍼티의 집합을 의미하기에 데이터가 동적으로 추가되면, 선언 당시의 프로퍼티 데이터 타입이나 순서가 프로퍼티에 접근할 때와는 달라질 수 있기 때문에 프로퍼티 값을 읽을 때마다 프로퍼티를 찾아야 합니다.

객체를 할당한 변수에는 생성된 객체가 실제로 저장된 메모리 공간의 주소가 저장되어 있습니다. 이 값을 참조 값(reference value)이라고 하며, 참조 값은 생성된 객체가 저장된 메모리 공간의 주소, 그 자체입니다.

객체는 원시값처럼 크기가 일정하지도 않고 프로퍼티 값이 객체인 경우 복사해서 생성하는 비용이 크고, 메모리 공간도 많이 차지하기 때문에 원시값처럼 할당할 때마다 생성하지 않고 참조해서 사용합니다. 다만 이런 경우 여러 변수가 하나의 객체를 참조함으로써 서로 영향을 주는 문제가 발생합니다.

얕은 복사와 깊은 복사

얕은 복사는 한 단계까지만 복사하고, 깊은 복사는 객체에 중첩된 객체까지 모두 복사합니다. 얕은 복사의 경우 참조된 값, 즉 객체의 메모리 주소를 복사하여 같은 객체를 참조합니다.

그림으로 확인하면 다음과 같습니다.

c0과 c1 모두 얕은 복사입니다. 그러나, c1의 경우와 같은 얕은 복사로 생성된 객체는 원본과는 다른 객체입니다. 즉, 원본과 복사본은 참조 값이 다른 별개의 객체이며 이것은 c2와 같은 깊은 복사도 마찬가지입니다.

c1의 경우와 같은 얕은 복사는 중첩되어 있는 것을 복사하지 않고 가장 상위의 있는 것만 복사가 됩니다. 따라서 중첩된 객체들은 원본 객체들과 같은 메모리 공간의 주소 값을 참조합니다.

c2의 경우와 같이, 깊은 복사는 데이터를 참조하는 것이 아닌 객체의 값 그대로 복사함으로서 한 객체가 변경되어도 다른 객체의 데이터에는 영향을 미치지 않습니다. 즉, 별개의 객체가 된다는 이야기입니다!!

profile
쉽게만 살아가면 재미없어 빙고🐝

0개의 댓글