정리용/js
[js 자주 사용되는 ES6+문법] 얕은 복사, 깊은 복사
hee-ya07
2025. 1. 10. 18:00
1. 얕은 복사 (Shallow Copy)
: 객체나 배열의 첫번째 수준 복사
: 객체의 최상위 값만 복사, 내부 참조된 객체나 배열은 복사X → 원본과 동일한 참조
1.1 얕은 복사 예시
1) 배열의 얕은 복사
const arr = [1, 2, 3];
const shallowCopy = arr.slice(); // 또는 [...arr]
shallowCopy[0] = 100;
console.log(arr); // [1, 2, 3] - 원본 배열은 변경되지 않음
console.log(shallowCopy); // [100, 2, 3] - 복사본은 변경됨
arr[0] = 90;
console.log(arr); // [90, 2, 3]
console.log(shallowCopy); // [100, 2, 3]
2) 객체의 얕은 복사
const obj = { a: 1, b: 2 };
const shallowCopy = { ...obj };
shallowCopy.a = 100;
console.log(obj); // { a: 1, b: 2 } - 원본 객체는 변경되지 않음
console.log(shallowCopy); // { a: 100, b: 2 } - 복사본은 변경됨
obj.a = 90;
console.log(obj); // { a: 90, b: 2 }
nsole.log(shallowCopy); // { a: 100, b: 2 }
1.3 얕은 복사의 단점
: 앝은 복사의 경우 1차원적인 것은 각각 독립적으로 바뀜
: But, 2차원으로 들어갈 경우(중첩된 객체 또는 배열) 그 내부 값 변경 시, 서로 영향
1) 복사본의 값을 변경할 경우
const obj = { a: 1, b: 2, c: { d: 4 } };
const shallowCopy = { ...obj };
shallowCopy.c.d = 100;
console.log(obj); // { a: 1, b: 2, c: { d: 100 } } - 원본도 변경
console.log(shallowCopy); // { a: 1, b: 2, c: { d: 100 } }
2) 원본 값을 변경할 경우
const obj = { a: 1, b: 2, c: { d: 4 } };
const shallowCopy = { ...obj };
obj.c.d = 100;
console.log(obj); // { a: 1, b: 2, c: { d: 100 } }
console.log(shallowCopy); // { a: 1, b: 2, c: { d: 100 } } - 복사본도 변경
2. Object.assign() VS Spread Syntax (배열 및 객체 펼치기)
2.1 Object.assign()
: 과거에 사용된 앝은 복사 방법
: 1번째 인수는 대상 객체, 두번째 이후는 복사하려는 객체
const object = Object.assign({}, { name: 'Aaron', age: 10 })
const refers = object
const copied = Object.assign({}, object)
console.log(object)
console.log(refers)
console.log(object === refers) //true
console.log(object)
console.log(copied)
console.log(object === copied) // false
더 간단한 예시는
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const mergedObj = Object.assign({}, obj1, obj2);
console.log(mergedObj); // { a: 1, b: 2, c: 3, d: 4 }
2.2 Spread Syntax
2-1) 배열 펼치기: 배열 복사 + 배열 연결 + 배열 요소 추가
const array = [1, 2, 3]
// array = [1, 2, 3]
// ...array = 1, 2, 3 => 대괄호 [] 제거
const added = [...array, 4, 5]
console.log(added)
/* [ 1, 2, 3, 4, 5 ] */
2-2) 객체 펼치기: 객체 복사 + 객체 연결 + 객체 프로퍼티(Property) 추가
const object = { name: 'Aaron', age: 10 }
// object = { name: 'Aaron', age: 10 }
// ...object = name: 'Aaron', age: 10 => 중괄호 {} 제거
const modified = {...object, name: 'Baron'}
console.log(modified)
/* { name: 'Baron', age: 10 } */
2.3 비교
특성 | Spread Syntax | Object.assign() |
주요 용도 | 배열 및 객체 복사, 병합 | 객체 복사 및 병합 |
앝은 복사 | O | O |
배열 사용 여부 | O | O |
객체 병합 | O | O |
참조 복사 여부 | 중첩된 객체 or 배열에 대한 참조 복사 | 중첩된 객체 or 배열에 대한 참조 복사 |
반환값 | 새로운 배열 or 객체 | 새로운 객체(=새 병합 객체) |
문법 | 간결, 직관 | 길고, 명시적 |
3. 깊은 복사
: 객체나 배열 내의 모든 값을 재귀적으로 복사하여 새로운 객체를 생성
: 원본 객체와 복사본은 완전히 독립적인 객체
더보기
- 깊은 복사 → 직렬화 || 역직렬화
: 객체 or 배열에서 중첩된 배열이 있을 경우
: JSON.parse() 와 JSON.stringify()를 활용하여 깊은 복사 가능
3.1 깊은 복사 예시
1. 배열의 깊은 복사
const arr = [1, 2, [3, 4]];
const deepCopy = JSON.parse(JSON.stringify(arr));
deepCopy[2][0] = 100;
console.log(arr); // [1, 2, [3, 4]] - 원본 배열은 변경되지 않음
console.log(deepCopy); // [1, 2, [100, 4]] - 복사본은 변경됨
But, 함수나 undefind, 순환 참조를 포함한 객체에서는 동작하지 않을 수 있음.
2. 객체의 깊은 복사
const obj = { a: 1, b: { c: 2 } };
const deepCopy = JSON.parse(JSON.stringify(obj));
deepCopy.b.c = 100;
console.log(obj); // { a: 1, b: { c: 2 } } - 원본 객체는 변경되지 않음
console.log(deepCopy); // { a: 1, b: { c: 100 } } - 복사본은 변경됨
3. 수동으로 깊은 복사
⇒ 복잡한 객체 or 배열의 경우, 재귀를 사용하여 깊은 복사
function deepClone(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 객체가 아니면 그대로 반환
}
const clone = Array.isArray(obj) ? [] : {}; // 배열과 객체 구분
for (const key in obj) {
clone[key] = deepClone(obj[key]); // 재귀 호출로 깊은 복사
}
return clone;
}
const original = { a: 1, b: { c: 2 } };
const deepCopy = deepClone(original);
deepCopy.b.c = 100;
console.log(original); // { a: 1, b: { c: 2 } }
console.log(deepCopy); // { a: 1, b: { c: 100 } }
참조
ASAC 수업자료