데이터 타입은 크게 참조형
과 기본형
으로 나뉜다.
데이터 타입은 어떤 기준으로 구분하는 걸까?
불변성
을 띈다.<aside>
💡 Javascript에서 모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값
을 통해 서로 구분하고 연결할 수 있다.
</aside>
메모리와 데이터
고작 0과 1만 표현할 수 있는 비트 단위로 위치를 확인하는 것은 매우 비효율적이다.
비트를 몇 개씩 묶어 한 단위로 여긴다면 표현할 수 있는 값도 늘어나면서 동시에 검색 시간도 줄일 수 있다.
낭비되는 데이터 없이
적절하게 묶은 단위가 8개의 비트로 구성된 바이트(byte)
이다.
<aside> 💡 식별자와 변수는 혼용하는 경우가 많다. 둘의 차이를 모른다면 혼란스러울 수 있다.
</aside>
var a;
주소 | … | 1002 | 1003 | 1004 | 1005 | … |
---|---|---|---|---|---|---|
데이터 | 이름 : a | |||||
값 : |
var a; // 변수 a 선언
a = 'abc' // 변수 a에 데이터 할당
var a = 'abc' // 변수 선언과 할당을 한 문장으로 표현
변수 영역 | 주소 | 1002 | 1003 | 1004 |
---|---|---|---|---|
데이터 | 이름 : a | |||
값 : @5004 | ||||
데이터 영역 | 주소 | 5002 | 5003 | 5004 |
데이터 | ‘abc’ |
@1003
을 확보한다.@5004
에 문자열 ‘abc’를 저장한다.@1003
@5004
를 @1003
의 공간에 대입한다.변경 가능성
이다.데이터 영역 메모
리이다.불변값
이다.
새로 생성하는 것.
영원히 변하지 않는다.
참조형 데이터를 할당하는 과정
<aside> 💡 기본형 데이터와의 차이는 객체의 변수 영역이 별도로 존재한다.
아래 예시를 보면 객체가 별도로 할애한 영역은 변수 영역일 뿐 데이터 영역은 기존의 메모리 공간을 그대로 활용하고 있다. 데이터 영역에 저장된 값은 모두 불변값이다. 그러나 변수영역에는 다른 값을 얼마든지 대입할 수 있다. 바로 이 부분 때문에 참조형 데이터는 불변하지 않다. (가변값이다.)
</aside>
var obj1 = {
a: 1,
b: 'bbb',
};
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 | … |
---|---|---|---|---|---|---|
데이터 | 이름 : obj1 | |||||
값 : @5001 | ||||||
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 | … |
데이터 | @7103 ~ ? | 1 | ‘bbb’ | |||
객체 @5001의 변수 영역 | 주소 | 7103 | 7104 | 7105 | 7106 | … |
데이터 | 이름 : a | |||||
값 : @5003 | 이름 : b | |||||
값 : @5004 |
@1002
을 확보하고 그 주소의 이름을 obj1로 지정한다.@5001
에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터의 그룹이다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소 (@7103 ~ ?)
를 @5001
에 저장합니다.@5003
에 저장하고, 이 주소를 @7103
에 저장한다. 문자열 ‘bbb’역시 임의로 @5004
에 저장하고, 이 주소를 @7104
에 저장한다.가비지 컬렉터로 가는 순간
얕은 복사 : 바로 아래 한단계의 값만 복사하는 방법
깊은 복사 : 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법
중첩된 객체에서 얕은 복사
var user = {
name: 'chul',
urls: {
portfolio: '<http://github.com/abc>',
blog: '<http://blog.com>',
facebook: '<http://facebook.com/abc>',
}
};
var user2 = copyObject(user);
user2.name = 'sujin';
// 바로 아래 단계에 대해서는 불변성을 유지하기 때문에 값이 달라지죠.
console.log(user.name === user2.name); // false
// 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같아요.
// 더 혼란스러워 지는거죠 ㅠㅠ
user.urls.portfolio = '<http://portfolio.com>';
console.log(user.urls.portfolio === user2.urls.portfolio); // true
// 아래 예도 똑같아요.
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog); // true
중첩된 객체에서 깊은 복사하기
var user = {
name: 'wonjang',
urls: {
portfolio: '<http://github.com/abc>',
blog: '<http://blog.com>',
facebook: '<http://facebook.com/abc>',
}
};
// 1차 copy
var user2 = copyObject(user);
// 2차 copy -> 이렇게까지 해줘야만 해요..!!
user2.urls = copyObject(user.urls);
user.urls.portfolio = '<http://portfolio.com>';
console.log(user.urls.portfolio === user2.urls.portfolio);
user2.urls.blog = '';
console.log(user.urls.blog === user2.urls.blog);
결론
결국에는 중첩된 참조형 데이터는 재귀 방식으로 모두 복사하는 것이 정답이다.
var copyObjectDeep = function(target) {
var result = {};
if (typeof target === 'object' && target !== null) {
for (var prop in target) {
result[prop] = copyObjectDeep(target[prop]);
}
} else {
result = target;
}
return result;
}
추가적인 방법
JSON을 이용하는 방법도 존재한다.
장점
단점
undefined와 같은 속성 값은 복사되지 않는다.
결론
JSON을 이용한 깊은 복사는 객체의 구조가 간단하고, 함수
나 undefined
와 같은 속성 값이 없는 경우에 적합한 방법이다. 만약 객체 구조가 복잡하거나 순환 참조가 있는 경우에는 다른 깊은 복사 방법을 고려해야 한다.
없음
을 나타내는 값이다.