원시타입의 깊은 복사
let num = 1;
let num2 = num;
num = 3;
console.log(num); // 3
console.log(num2); // 1
1이라는 데이터가 주소값이 3001인 메모리에 있다고 가정할 때, num은 1이 저장된 주소값(3001)을 갖고있다.
num2에 num의 값을 복사하기위해 num2 = num을 실행한 경우 num2은 마찬가지로 1이 저장된 주소값(3001)을 갖게된다.
각 식별자가 독립적으로 데이터 1의 위치를 알고있으므로, 둘중 하나가 다른 데이터를 할당받더라도 나머지 하나는 그대로 1에 접근할 수 있다.
위 예시처럼 num = 3을 새로 대입해준 경우 num은 3이라는 데이터가 위치한 주소(ex. 3002)를 갖게되고, 이 변화는 num2가 갖고있는 정보에 영향을 미치지 않는다.
참조타입의 얕은 복사
let obj = {
num: 1,
};
let obj2 = obj;
obj.num = 3;
console.log(obj); // { num: 3}
console.log(obj2); // { num: 3}
참조타입은 객체의 속성들이 모여있는 묶음의 주소값을 알고있다.
따라서 obj의 속성들을 복사하기위해 obj2 = obj를 실행한 경우 obj2는 obj의 속성묶음의 주소를 갖게된다.
이 때 원시타입의 복사(깊은 복사)와 차이가 발생한다. obj.num과 obj2.num은 결국 데이터를 받아올 메모리 주소를 같은 공간에서 관리하기 때문에 두 변수 중 하나가 변경되는 경우 나머지 하나도 변경된 값을 가지게 된다.
다른 객체에서 값을 복사해오지만, 독립적으로 관리하고 싶은 경우 반복문을 통해 객체 내부를 돌면서 값을 복사해올 수 있다!
let obj = {
num: 1,
};
function copyObj() {
let newObj = {};
for(let key in obj) {
newObj[key] = obj[key];
}
return newObj;
}
let obj2 = copyObj();
obj.num = 3;
console.log(obj); // { num: 3 }
console.log(obj2); // { num: 1 }
하지만 위의 방법을 사용한다면 객체의 속성 중 참조타입이 있는 경우가 문제가 된다. 이를 중첩된 객체라고 한다.
참조타입의 깊은 복사
중첩된 객체를 대비해 깊은 복사를 수행하려면 재귀적인(recursive) 방법이 필요하다.
let otherRef = {
data1: 1,
data2: 2,
};
let obj = {
num: 1,
refInfo: otherRef,
};
function copyObj(target) {
let newObj = {};
if(typeof target === 'object' && target != null) {
for(let key in target) {
newObj[key] = copyObj(target[key]);
}
} else {
newObj = target;
}
return newObj;
}
let obj2 = copyObj(obj);
obj.refInfo.data1 = 10;
console.log(obj); // { num: 1, refInfo: { data1: 10, data2: 2 } }
console.log(obj2); // { num: 1, refInfo: { data1: 1, data2: 2 } }
이 방법을 활용하면 복사하고자하는 값의 타입이 참조타입일 때 그 객체의 내부까지 접근하여 복사해올 수 있다.
'JavaScript' 카테고리의 다른 글
[JavaScript] this (정의, 활용, 바인딩, call, apply, bind) (2) | 2024.07.23 |
---|---|
[JavaScript] 실행 컨텍스트 및 콜스택 (0) | 2024.07.23 |
[JavaScript] Map과 Set (0) | 2024.07.22 |
[JavaScript] 일급 객체로서의 함수 (0) | 2024.07.22 |
[JavaScript] ES6 추가 문법들 (0) | 2024.07.22 |