자바스크립트 얕은 복사 vs 깊은 복사, 완벽 정리!
자바스크립트에서 객체를 복사할 때, "얕은 복사(Shallow Copy)"와 "깊은 복사(Deep Copy)"라는 용어를 자주 접하게 됩니다.
이 두 가지 복사 방식의 차이점을 제대로 이해하지 못하면, 예상치 못한 버그를 만날 수도 있는데요.
이 글에서는 얕은 복사와 깊은 복사의 차이점을 쉬운 예시를 통해 명확하게 설명하고, 각 방식의 장단점과 사용 시 주의할 점까지 꼼꼼하게 알려드리겠습니다.
얕은 복사(Shallow Copy), 겉핥기식 복사?
얕은 복사는 원본 객체의 최상위 속성 값만 복사합니다. 즉, 객체 내부에 중첩된 객체나 배열은 참조(Reference)만 복사됩니다.
얕은 복사 예시:
const original = {
name: "Alice",
details: {
age: 25,
city: "Boston"
}
};
const shallowCopy = { ...original }; // 스프레드 연산자 사용
// 복사 후 값 변경
shallowCopy.details.age = 30;
console.log(original.details.age); // 출력: 30 (원본 객체도 변경됨)
위 예시에서 스프레드 연산자({ ...original }
)를 사용하여 shallowCopy
객체를 생성했지만, details
객체는 참조로 복사되었습니다.
따라서 shallowCopy
에서 details.age
값을 변경하면, original
객체의 details.age
값도 함께 변경됩니다.
얕은 복사 방법:
- 스프레드 연산자:
{ ...original }
Object.assign({}, original)
얕은 복사 주의 사항:
얕은 복사는 객체의 중첩된 속성을 제대로 복사하지 않으므로, 원본 객체를 변경할 수 있는 위험이 있습니다.
특히 중첩된 객체나 배열이 많을 경우, 예상치 못한 동작이 발생할 수 있으므로 주의해야 합니다.
깊은 복사(Deep Copy), 완벽한 복제!
깊은 복사는 객체의 모든 속성을 재귀적으로 복사합니다.
즉, 원본 객체와 복사된 객체는 완전히 독립적이며, 중첩된 객체나 배열을 변경해도 서로 영향을 미치지 않습니다.
깊은 복사 예시:
const original = {
name: "Alice",
details: {
age: 25,
city: "Boston"
}
};
const _ = require('lodash'); // lodash 라이브러리 사용
const deepCopy = _.cloneDeep(original);
// 복사 후 값 변경
deepCopy.details.age = 30;
console.log(original.details.age); // 출력: 25 (원본 객체는 변경되지 않음)
위 예시에서는 lodash 라이브러리의 cloneDeep
함수를 사용하여 깊은 복사를 수행했습니다.
따라서 deepCopy
의 details.age
값을 변경해도, original
객체는 영향을 받지 않습니다.
깊은 복사 방법:
- lodash의
cloneDeep
함수:const deepCopy = _.cloneDeep(original);
깊은 복사 주의 사항:
깊은 복사는 객체의 모든 속성을 재귀적으로 복사하므로, 객체가 매우 크거나 중첩이 너무 깊으면 성능에 영향을 줄 수 있습니다.
따라서 대규모 데이터 구조를 복사할 때는 주의해야 합니다.
단순 변수 대입, 값 복사 vs 참조 복사
자바스크립트에서 number
, string
, boolean
, null
, undefined
와 같은 기본 자료형(Primitive Type)을 대입할 때는 값 자체가 복사됩니다.
이를 값 복사(Pass by Value)라고 합니다. 따라서 복사 후 값을 변경해도 원본 변수에 영향을 주지 않습니다.
반면에, 객체나 배열과 같은 복합 자료형(Reference Type)의 경우, 참조가 복사됩니다.
이를 참조 복사(Pass by Reference)라고 합니다. 이 경우, 복사된 변수는 동일한 객체를 가리키므로, 한쪽을 변경하면 다른 쪽에도 영향을 미칩니다.
예시:
// 값 복사 (기본 자료형)
let a = 10;
let b = a;
b = 20;
console.log(a); // 출력: 10
// 참조 복사 (객체)
const obj1 = { value: 10 };
const obj2 = obj1;
obj2.value = 20;
console.log(obj1.value); // 출력: 20
기본 자료형은 복사 시 새로운 값이 생성되므로 안전하지만, 객체나 배열을 다룰 때는 얕은 복사 또는 깊은 복사를 사용하여 의도하지 않은 변경을 방지해야 합니다.
얕은 복사 vs 깊은 복사, 어떤 상황에 사용할까요?
- 중첩이 적고 단순한 데이터 구조: 얕은 복사
- 중첩된 객체나 배열이 포함되어 있고, 이들을 독립적으로 관리: 깊은 복사
- 복사한 데이터의 일부만 변경: 깊은 복사 (원본 데이터 변경 방지)
성능도 고려해야 합니다. 필요 이상으로 깊은 복사를 사용하면 성능 저하가 발생할 수 있으므로, 상황에 맞게 효율적으로 사용하는 것이 중요합니다.
관련 주제
- 불변성(Immutability): React와 같은 프레임워크에서 중요한 개념으로, 데이터를 직접 변경하지 않고 복사하여 사용하는 것이 좋습니다. 깊은 복사는 객체를 불변 상태로 유지하면서 새로운 복사본을 만들 때 유용합니다.
- 참조와 값의 차이: 자바스크립트에서 객체와 배열은 참조로 처리되므로, 복사 방법에 따라 동작이 달라집니다. 이를 이해하면 얕은 복사와 깊은 복사를 적절하게 사용할 수 있습니다.
- 라이브러리 선택: 깊은 복사를 위한 라이브러리로는 lodash 외에도 ramda, immer 등 다양한 유틸리티 라이브러리가 있습니다. 각 라이브러리의 특징을 파악하고, 용도에 맞는 라이브러리를 선택하는 것이 좋습니다.
마무리
얕은 복사: 최상위 속성만 복사, 중첩된 객체는 참조 복사
깊은 복사: 모든 속성을 재귀적으로 복사, 원본 객체와 독립
객체를 복사할 때는 데이터 구조에 따라 얕은 복사와 깊은 복사를 적절하게 선택해야 합니다.
특히 중첩된 데이터를 다룰 때는 의도하지 않은 변경이 발생하지 않도록 주의해야 합니다.
'Javascript' 카테고리의 다른 글
reduce로 날짜별 정보 배열 만들기 (0) | 2024.11.09 |
---|---|
실무에서 바로 쓸 수 있는 TypeScript 타입 8선 (1) | 2024.11.09 |
Next.js 15, 달라진 점 싹 다 훑어보기! (1) | 2024.10.30 |
Next.js "use cache" 한방에 이해하기! (0) | 2024.10.30 |
Next.js 15의 혁신적인 캐시 기능 (0) | 2024.10.30 |