*얕은 복사(Shallow Copy)**와 **깊은 복사(Deep Copy)**는 자바스크립트에서 객체나 배열을 복사할 때 사용되는 중요한 개념입니다. 두 가지 방식의 차이는 복사된 객체가 원본 객체와 어떤 식으로 연결되는지에 따라 달라집니다.
1. 얕은 복사 (Shallow Copy)
얕은 복사는 객체의 최상위 레벨 속성만 복사하는 방식입니다. 원본 객체와 복사된 객체는 같은 참조를 공유하는 중첩된 객체를 가집니다. 즉, 얕은 복사는 1단계만 복사하기 때문에, 객체나 배열 내부에 중첩된 객체나 배열이 있을 경우, 원본과 복사된 객체가 같은 참조를 공유하게 됩니다.
얕은 복사의 특징
• 객체의 최상위 레벨 속성만 복사됩니다.
• 중첩된 객체나 배열은 참조만 복사되므로, 복사된 객체와 원본 객체는 내부 중첩된 객체를 공유하게 됩니다.
• 원본 객체의 중첩된 속성을 수정하면, 복사된 객체에도 영향을 미칩니다.
얕은 복사 방법
1. Object.assign()
2. 스프레드 연산자(…)
예시 1: Object.assign()을 사용한 얕은 복사
const original = { name: 'Alice', address: { city: 'Seoul' } };
const copy = Object.assign({}, original);
console.log(copy); // { name: 'Alice', address: { city: 'Seoul' } }
copy.name = 'Bob'; // 복사본의 최상위 속성 변경
console.log(original.name); // 'Alice' (원본은 영향 없음)
copy.address.city = 'Busan'; // 중첩 객체의 속성 변경
console.log(original.address.city); // 'Busan' (원본도 변경됨, 참조 공유)
예시 2: 스프레드 연산자를 사용한 얕은 복사
const original = { name: 'Alice', address: { city: 'Seoul' } };
const copy = { ...original };
console.log(copy); // { name: 'Alice', address: { city: 'Seoul' } }
copy.address.city = 'Busan'; // 중첩 객체 수정
console.log(original.address.city); // 'Busan' (원본도 변경됨, 참조 공유)
위 예시들에서 복사된 객체와 원본 객체는 중첩된 객체인 address 속성을 공유하고 있습니다. 따라서 copy.address.city를 변경하면, 원본 객체의 address.city도 변경됩니다.
2. 깊은 복사 (Deep Copy)
깊은 복사는 객체의 모든 속성을 완전히 복사하여, 원본과 독립된 새로운 객체를 만드는 방식입니다. 중첩된 객체나 배열까지 모두 복사되어, 복사된 객체와 원본 객체는 참조를 공유하지 않습니다. 따라서 원본 객체의 중첩된 속성을 변경하더라도 복사된 객체에는 영향을 미치지 않습니다.
깊은 복사의 특징
• 객체 내부의 모든 레벨의 중첩된 속성까지 새로운 참조로 복사됩니다.
• 원본과 복사된 객체는 서로 독립적입니다.
• 원본을 수정해도 복사본에 영향을 미치지 않고, 복사본을 수정해도 원본에 영향을 미치지 않습니다.
깊은 복사 방법
1. **JSON.stringify()와 JSON.parse()**를 사용하는 방법
2. lodash 등의 라이브러리 사용
3. 재귀 함수를 통한 직접 구현
예시 1: JSON.stringify()와 JSON.parse()를 사용한 깊은 복사
const original = { name: 'Alice', address: { city: 'Seoul' } };
const copy = JSON.parse(JSON.stringify(original));
copy.address.city = 'Busan'; // 중첩 객체 수정
console.log(original.address.city); // 'Seoul' (원본은 영향 없음)
JSON.stringify()로 객체를 문자열로 변환한 후, JSON.parse()로 다시 객체로 변환하는 방식은 가장 간단한 깊은 복사 방법 중 하나입니다. 하지만 함수, undefined, Symbol과 같은 비직렬화 가능한 값은 제외되므로 주의가 필요합니다.
예시 2: Lodash의 _.cloneDeep()을 사용한 깊은 복사
lodash 라이브러리의 _.cloneDeep() 메서드는 깊은 복사를 위한 강력한 도구입니다.
const _ = require('lodash');
const original = { name: 'Alice', address: { city: 'Seoul' } };
const copy = _.cloneDeep(original);
copy.address.city = 'Busan'; // 중첩 객체 수정
console.log(original.address.city); // 'Seoul' (원본은 영향 없음)
_.cloneDeep()은 객체 내부의 모든 속성을 재귀적으로 복사하여 깊은 복사를 수행합니다.
예시 3: 재귀 함수로 직접 구현한 깊은 복사
객체가 중첩된 속성을 가지는 경우, 직접 재귀 함수를 사용해 깊은 복사를 구현할 수도 있습니다.
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
const clone = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key]);
}
}
return clone;
}
const original = { name: 'Alice', address: { city: 'Seoul' } };
const copy = deepClone(original);
copy.address.city = 'Busan'; // 중첩 객체 수정
console.log(original.address.city); // 'Seoul' (원본은 영향 없음)
위 코드는 객체가 중첩된 경우에도 모든 속성을 재귀적으로 깊은 복사하는 방법입니다.
3. 얕은 복사와 깊은 복사의 차이
| 비교항목 | 얕은 복사(Shallow Copy) | 깊은 복사(Deep Copy) |
| 복사방식 | 최상위 속상만 복사, 중첩 객체는 참조를 공유 | 객체의 모든 레벨을 재귀적으로 완전 복사 |
| 중첩된 객체 | 원본과 복사본이 동일한 참조를 공유 | 원본과 복사본이 독립적인 참조를 가짐 |
| 원본 변경 영향 | 원본 객체의 중첩 속성 변경 시 복사본에도 영향 | 원본 객체와 복사본은 서로 영향을 주지 않음 |
| 복사 방법 | Object.assign(), 스프레드 연산자(...)등 | JSON.stringify() + JSON.parse(), _.cloneDeep() 등 |
4. 언제 얕은 복사와 깊은 복사를 사용해야 할까?
• 얕은 복사는 객체의 최상위 레벨 속성만 변경될 때 사용해도 괜찮습니다. 예를 들어, 중첩된 속성이 없는 경우, 얕은 복사는 효율적이고 빠르게 동작합니다.
• 깊은 복사는 객체에 중첩된 객체나 배열이 포함되어 있으며, 복사된 객체가 원본 객체와 독립적으로 동작해야 할 때 사용해야 합니다.
5. 주의할 점
• **JSON.stringify()와 JSON.parse()**는 함수, undefined, Symbol과 같은 직렬화되지 않는 값들을 무시하므로, 이런 값들이 포함된 객체에 대해서는 사용하지 않는 것이 좋습니다.
• 깊은 복사는 얕은 복사보다 성능적으로 더 비용이 많이 들 수 있습니다. 특히 큰 객체나 깊이 중첩된 구조에서는 성능에 영향을 줄 수 있으므로, 필요에 따라 적절한 복사 방식을 선택해야 합니다.
결론
• 얕은 복사는 객체의 최상위 속성만 복사하고, 중첩된 객체는 원본과 참조를 공유하는 방식입니다. 스프레드 연산자나 **Object.assign()**을 사용해 쉽게 구현할 수 있습니다.
• 깊은 복사는 중첩된 객체까지 모두 복사하여 원본과 완전히 독립적인 객체를 만드는 방식입니다. **JSON.stringify()와 JSON.parse()**를 사용하거나 **_.cloneDeep()**과 같은 라이브러리를 사용할 수 있습니다.
• 어떤 복사 방식을 선택할지에 따라 코드의 동작 방식
'JavaScript' 카테고리의 다른 글
| [JS] async/await (1) | 2024.09.20 |
|---|---|
| [JS] Promise (0) | 2024.09.08 |
| [JS] 자바스크립트의 동작방식(비동기,동기) (0) | 2024.09.08 |
| [JS] Callback (1) | 2024.09.08 |
| [JS] 함수와 클래스(this) (0) | 2024.09.08 |