객체 복사의 두 가지 방식
JavaScript를 비롯한 대부분의 프로그래밍 언어에서 객체를 복사하는 방법은 크게 두 가지로 나뉩니다. 바로 얕은 복사(shallow copy)와 깊은 복사(deep copy)입니다.
이 두 개념은 특정 언어에 종속되지 않는 보편적인 개념입니다. 얕은 복사는 최소한의 정보만 복제합니다. 즉, 컬렉션을 얕게 복사하면 컬렉션의 구조만 새로 만들어질 뿐, 내부 요소들은 그대로 유지됩니다. 그 결과 원본과 복사본이 동일한 내부 객체를 함께 참조하게 됩니다.
얕은 복사 예제
let innerObj = {
a: 'b',
c: 'd'
}
let obj = {
x: "test",
y: innerObj
}
// 얕은 복사 생성
let copyObj = Object.assign({}, obj);
// copyObj와 obj의 y 속성은 이제 같은 innerObj를 참조합니다.
innerObj.a = "test"
console.log(obj)
console.log(copyObj)실행 결과
{ x: 'test', y: { a: 'test', c: 'd' } }
{ x: 'test', y: { a: 'test', c: 'd' } }출력 결과를 보면 innerObj.a 값을 변경했을 때 원본(obj)과 복사본(copyObj) 모두에 변경 사항이 반영되는 것을 확인할 수 있습니다.
주의: 얕은 복사는 하위 객체를 재귀적으로 복제하지 않으며, 최상위 속성만 복사한다는 점을 기억해야 합니다.
깊은 복사(Deep Copy)란?
깊은 복사는 모든 것을 복제합니다. 컬렉션을 깊게 복사하면 원본 컬렉션의 모든 요소가 재귀적으로 복제되어, 원본과 완전히 독립적인 새로운 컬렉션이 생성됩니다.
깊은 복사 예제
let innerObj = {
a: 'b',
c: 'd'
}
let obj = {
x: "test",
y: innerObj
}
// 깊은 복사 생성
let copyObj = JSON.parse(JSON.stringify(obj))
// innerObj를 변경해도 copyObj에는 영향이 없습니다.
innerObj.a = "test"
console.log(obj)
console.log(copyObj)실행 결과
{ x: 'test', y: { a: 'test', c: 'd' } }
{ x: 'test', y: { a: 'b', c: 'd' } }이번에는 innerObj.a를 변경해도 복사본인 copyObj에는 아무런 영향을 주지 않습니다. 깊은 복사를 통해 복사본이 원본으로부터 완전히 분리되었기 때문입니다.
참고: 더 안전한 깊은 복사 방법
JSON.parse(JSON.stringify()) 방식은 간편하지만 함수, undefined, Symbol, Date 객체 등을 올바르게 처리하지 못하는 한계가 있습니다. 최신 JavaScript 환경에서는 전역 함수인 structuredClone()을 사용하는 것이 권장됩니다.
let copyObj = structuredClone(obj);
structuredClone()은 순환 참조까지 지원하며 다양한 데이터 타입을 안정적으로 복제할 수 있어, 실무에서 깊은 복사가 필요할 때 가장 신뢰할 수 있는 선택지입니다.