얕은 복사 VS 깊은 복사

younghyun·2022년 5월 21일
0

얕은 복사

주소 값을 새로운 메모리 공간에 복사 ( 참조하는 실제 값은 같음 )

Ex) 객체 타입은 새로운 변수에 대입 시 얕은 복사가 된다. 주소 값을 새로운 메모리 공간에 복사해 같은 객체를 참조함. (참조하는 실제 값은 같음)
( 객체는 원시값처럼 크기가 일정 하지도 않고 프로퍼티 값이 객체인 경우 복사해서 생성 하는 비용이 크고, 메모리 공간도 많이 차지하기 때문에 원시값처럼 할당할 때마다 생성하지 않고 참조해서 사용한다. 다만 이런 경우 여러 변수가 하나의 객체를 참조 함으로써 서로 영향을 주는 문제가 있다. )

Spread 연산자, Object.assign()메서드로 객체를 복사하면 1depth까지는 Deep Copy, 2depth 이상 이면 Shallow Copy가 됨. ( 객체에 중첩된 객체까지 복사하지 않음. )

const obj1 = { a: 1, b: 2};
const obj2 = obj1;

console.log( obj1 === obj2 ); // true

객체를 직접 대입하는 경우 참조에 의한 할당이 이루어지므로 둘은 같은 데이터 주소를 가지고 있음.

const obj1 = { a:1, b:2 };
const obj2 = obj1;

obj2.a = 100;

console.log( obj1.a ); // 100

두 객체는 같은 데이터(주소)를 가지고 있고, 그래서 같은 주소를 참조하고 있음.
obj2의 property를 수정하고, obj1를 출력해도 obj2 값과 동일함.

깊은 복사

실제 값을 새로운 메모리 공간에 복사 (실제 값이 다름)
원시 타입은 불변성에 의거 깊은 복사가 된다. ( 원시값을 복사하면 값은 그대로 복사되지만, 같은 값을 가지는 별개의 메모리 공간을 가리킬 뿐이다. 따라서 각 변수에 어떤 짓을 하든 서로에게 영향을 주지 않는다. )

방법 1. ...(spread)연산자를 통한 복사
const obj1 = { a:1, b:2 };
const obj2 = { ...obj };

obj2.a = 100;

console.log( obj1 === obj2 ) // false
console.log( obj1.a ) // 1

...(spread) 연산자를 통해 { }안에 obj1의 속성을 복사하여 obj2에 할당
obj1과 obj2는 다른 주소(딱, 1 depth까지만)

방법 2. Object.assign() 메소드를 통한 복사
const obj1 = { a:1, b:2 };
const obj2 = Object.assign({}, obj1);

obj2.a = 100;

console.log( obj1 === obj2 ) // false
console.log( obj1.a ) // 1
Object.assign() 메소드를 통해 첫 번째 인자로 빈 { } 객체를, 두 번째 인자로 obj1 넣고 obj2 에 할당.
obj1과 obj2는 다른 주소를 갖게됨. (그러나 딱, 1 depth 까지만)

즉, Object.assign() 메소드도 spread 연산자 둘 다 완벽한 Deep copy 되지 않음.
1 depth 까지는 확실하게 Deep copy.
2 depth 이상이면 Shallow copy.

👉 …(spread) 연산자를 이용해 depth 2까지 복사하는 방법
const obj1 = { a: { b:1, c:1 }, d: 2};
const obj2 = { ...obj1, a:{ ...obj1.a } };

obj1.a.b = 100;

console.log(obj1 === obj2) // false
console.log(obj2.a.b) // 1

👉 완벽한 Deep copy를 위한 다른 방법
재귀적으로 깊은 복사를 수행
Lodash의 cloneDeep 함수 사용
JSON.parse()와 JSON.stringify()함수 사용

Reference
https://hanamon.kr/javascript-shallow-copy-deep-copy/

profile
선명한 기억보다 흐릿한 메모

0개의 댓글