얕은 복사와 깊은 복사
객체나 배열을 복사할 때 인지하고 있어야하는 중요한 개념이다.
우선 참조타입(Reference Type), 타입 값(Value Type)의 차이를 알아야한다.
Value Type
- number, string, boolean, null, undefined 등은 value type이다.
- 값을 그대로 복사할 때 새로운 메모리 공간에 값을 복사한다.
- 값을 복사한 뒤에는 두 값이 서로 독립적으로 존재한다.
Reference Type
- object, array, function 등은 reference type 이다.
- 변수에 값을 할당할 때 객체의 메모리 주소를 복사한다.
- 두 변수가 동일한 객체를 참조하게 되어, 하나의 변수를 수정하면 다른 변수도 영향을 받게 된다.
Shallow Copy
얕은 복사는 최상위 수준의 값만 복사한다.
객체 내부의 중첩된 객체나 배열 등은 참조만 복사하는 방식이다.
따라서 최상의 속성을 변경하면 영향을 받지 않지만, 내부 객체가 변경되면 복사본과 원본 모두에 영향을 준다.
const original = { a: 1, b: {c: 2} };
const shallowCopy = { ...original };
shallowCopy.a = 100;
shallowCopy.b.c = 200;
console.log(original);
// { a: 1, b: { c: 200 } }
console.log(shallowCopy);
// { a: 100, b: { c: 200 } }
console.log(original.b.c);
// 200
shallowCopy.a 는 최상위 속성이며 독립적이다.
shallowCopy.b.c 는 참조가 복사(실제 값이 아닌 메모리 주소를 복사)되었기 때문에 원본 객체 original.b.c.도 변경된다.
original.b는 객체이고, 얕은 복사를 하게되면 shallowCopy.b는 값을 복사하지 않고 original.b의 메모리 주소를 그대로 가져간다.
따라서 shallowCopy와 original은 b라는 객체의 같은 메모리 주소를 참조하고 있다.
const arr = [1, 2, {x: 10, y: 20 }];
const shallowArr = [...arr];
shallowArr[2].x = 50;
console.log(arr);
// [1, 2, {x: 10, y:20} ]
console.log(shallowArr);
// [1, 2, {x: 50, y: 20}]
배열의 얕은 복사를 하면 배열의 객체 요소는 참조가 복사되므로, shallowArr[2]를 수정하면 arr[2] 도 영향을 받게 된다.
Deep Copy
깊은 복사는 객체의 모든 수준에서 값을 완전히 복사하는 방식이다.
객체 안에 중첩된 객체나 배열까지도 새로운 메모리 공간에 복사되므로, 복사본과 원본은 완전히 독립적으로 존재한다.
이 때 배열이나 중첩된 객체를 깊은 복사 할때는 재귀적으로 처리하거나, lodash의 cloneDeep() 메서드를 사용하면 깊은 복사를 쉽게 할 수 있다.
const _ = require('lodash');
const original = { a: 1, b: {c: 2} };
const deepCopy = _.cloneDeep(original);
deepCopy.b.c = 200;
console.log(original)
// { a: 1, b: { c: 2 } }
console.log(deepCopy)
// { a: 1, b: { c: 200 } }
정리
| 구분 | 얕은 복사 | 깊은 복사 |
| 복사 범위 | 최상위 객체만 복사 (중첩된 객체는 참조 복사) |
모든 레벨에서 객체를 새로 복사 |
| 독립성 | 중첩된 객체가 원본과 공유되어짐 | 원본과 복사본이 완전히 독립적 |
| 사용 예시 | 스프레드 연산자( ... ), slice() 등 | 재귀복사, JSON.parse(JSON.stringify()), lodash.cloneDeep() 등 |
| 성능 | 깊은 복사보다 빠르지만 원본에 의존적인 객체일 수 있다. | 더 느릴 수 있으나, 복사본과 원본이 완전히 독립적이므로 안전하다. |
| 제한 사항 | 중첩된 객체나 배열을 독립적으로 다루고 싶을 때는 부적합하다. | 성능이 중요한 경우 비효율적일 수 있다. 일부 데이터 타입(함수, undefined, symbol) 은 JSON 방식에서 손실 발생 |
얕은 복사와 깊은 복사의 차이는 깊은 복사는 완전히 새로운 메모리 주소를 가지기 때문에 원본과 복사본이 완벽히 독립적이라 서로 영향을 주지 않는 것이고, 얕은 복사의 경우 내부 객체는 원본 객체와 같은 것을 공유하기 때문에 얕은 복사 본에서 내부 객체가 변경될 경우 원본의 것 까지 변경이 된다는 것이다.
즉, 얕은 복사와 깊은 복사의 결정적인 차이는 원본의 내부 객체가 완전히 독립적이냐 아니냐 차이로 볼 수 있다.
'Typescript' 카테고리의 다른 글
| [TypeScript] module/ moduleResolution 에러 해결과 옵션 정리 (1) | 2025.09.01 |
|---|---|
| [TypeScript] TS Cheat Sheet (Type, Interface) (0) | 2025.08.19 |
| 배열 관련 메서드 (0) | 2024.10.22 |
| forEach vs for (0) | 2024.10.22 |
| 유틸리티 타입 (0) | 2024.07.08 |