JS에서 데이터 타입은 크게 기본형과 참조형으로 나뉜다.
이 구분 기준은 메모리 저장 방식과 불변성 여부이다.
기본형의 경우 불변성을 띄며 값을 복사하고, 참조형의 경우 비불변성을 띄고 메모리에 담긴 주소값을 복사한다.
var a;
a = 10;
변수 선언 영역
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 |
변수 선언의 경우 변수 영역 메모리에 기록이 되고 값이 담긴 메모리 주소를 가진다.
값의 경우 데이터 영역의 메모리 공간에 기록이 된다.
변수의 값을 수정할 때 바뀌는 것은 데이터 영역에 새로운 값을 5003에 할당하고 1002 번지에
기록되어 있는 주소값만 바꿔주게 된다.
🟥 여기서 중요한 점은 값이 변경되면서 사용을 안하는 5002번지의 데이터의 경우 가비지 컬렉터가 삭제를 진행한다. 🟥
var object1 = {
a = 10,
b = 20
};
변수 선언 영역
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | object1 / @8002~ |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 | 20 |
참조형 데이터 영역
Address | ... | 8002 | 8003 | 8004 | 8005 | 8006 | ... |
---|---|---|---|---|---|---|---|
Data | a | b |
참조형 데이터인 객체의 경우 메모리 할당 시 참조형 데이터 영역이 별도로 생성되어 다음과 같이
구성된다.
var a;
a = 10;
var b = 10;
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 | b/@5002 |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 |
변수를 생성하고 같은 값이 있다면, 데이터 영역에서 해당 값의 주소를 참조한다.
var a= 10;
var b = 10;
b=20;
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 | b/@5003 |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 | 20 |
변수의 값을 변경한경우 데이터 영역에 새로 메모리가 할당되고 해당 주소를 변수에 참조한다.
var object1 = {
a = 10,
b = 20
};
var object2 = object1;
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | object1 / @8002~ | object2 / @8002~ |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 | 20 |
참조형 데이터 영역
Address | ... | 8002 | 8003 | 8004 | 8005 | 8006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 | b/@5003 |
객체를 복사할 경우 참조형 데이터 영역을 참조하는 주소값이 그대로 복사되기 때문에,
object2.a를 변경하면 object1.a 도 값이 변경되게 된다.
따라서 객체 자체를 변경해야 원본 데이터 값을 보존할 수 있다.
var object1 = {
a = 10,
b = 20
};
var object2 = object1;
object2 = {
a = 10,
b= 30
};
Address | ... | 1002 | 1003 | 1004 | 1005 | 1006 | ... |
---|---|---|---|---|---|---|---|
Data | object1 / @8002~ | object2 / @9002~ |
데이터 영역
Address | ... | 5002 | 5003 | 5004 | 5005 | 5006 | ... |
---|---|---|---|---|---|---|---|
Data | 10 | 20 | 30 |
참조형 데이터 영역1
Address | ... | 8002 | 8003 | 8004 | 8005 | 8006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 | b/@5003 |
참조형 데이터 영역2
Address | ... | 9002 | 9003 | 8004 | 8005 | 8006 | ... |
---|---|---|---|---|---|---|---|
Data | a/@5002 | b/@5004 |
위와 같이 하나하나 수작업으로 할 수는 없고, for..in 문으로 하나씩 꺼내어 복사하는 방법을 사용해야 한다.
다만 객체 안에 객체가 있는 경우를 대비하여 얕은 복사와 깊은 복사가 있다.
1. 얕은 복사
var copyObj = function (target) {
var res = {};
for (var idx in target) {
res[idx] = target[idx];
}
return res;
}
객체 안에 객체가 있는 경우에는 완벽한 복사가 진행되지 않는다.
var deepCopy = function(target) {
var res = {};
if (typeof target === 'object' && target !== null) {
for (var idx in target) {
res[idx] = deepCopy(target[idx]);
}
} else {
res = target;
}
return res;
}
위 코드와 같이 한줄씩 요소를 뽑았을 때 object인 경우에 재귀하여 함수를 실행하고 아닌 경우(기본형 데이터)에는 일반적인 복사를 진행한다.