자바스크립트 코어 - 데이터 타입
자바스크립트 코어 - 데이터 타입
목차
데이터 타입의 종류
- 자바스크립트의 데이터 타입에는 크게
기본형(원시형)
과참조형
2가지가 있음 - 기본형은 할당이나 연산시 복제되고 참조형은 데이터가 참조됨
- 기본형은 값이 담긴 주솟값을 바로 복제함
- 참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제함
- 기본형 데이터는
불변성
을 띔
불변성(Immutable) 이란 기존의 값을 그대로 유지하면서 새로운 값을 추가하는 것으로 객체가 생성된 이후 그 상태를 변경할 수 없는 디자인 패턴
데이터 타입의 종류 | ||
---|---|---|
Primitive type (기본형) | Reference type (참조형) | |
Number | Array | |
String | Function | |
Boolean | Date | |
null | RegExp | |
undefined | Map, WeakMap | |
Symbol | Set, WeakSet |
데이터 타입의 배경지식
1. 메모리와 데이터
- 메모리는 매우 많은
Bit
들로 구성되어 있고 각 Bit는고유한 식별자
를 통해 위치를 확인 할 수 있음 - 1비트마다 0 또는 1의 두 가지 값을 표현할 수 있으므로 1바이트는 총 256(2에8승)개의 값을 표현할 수 있음
- 2바이트는 비트 16개이므로 65536(2에16승)개의 값을 표현할 수 있음
- 모든 데이터는 바이트 단위의 식별자,
메모리 주솟값
을 통해 서로 구분하고 연결할 수 있음
비트(Bit) : 0 또는 1만 표현할 수 있는 하나의 메모리 조각
바이트(Byte) : 8개의 비트로 구성되는 단위
2. 식별자와 변수
- 변수(variable) 란
변할 수 있는 수
임 (반드시 숫자여야 하는 것은 아니며변할 수 있는 무언가
) - 식별자란 어떤 데이터를 식별하는데 사용하는 이름, 즉
변수명
을 말함
변수와 데이터 할당
1. 변수 선언
var a;
- 변수를 선언하는 것은
변할 수 있는 데이터를 만든다
로 알수 있음 - 변할 수 있는 데이터이니 선언할 때는
undefined
이더라도 나중에 다른 값으로 변경가능 - 즉 변수란 결국
변경 가능한 데이터가 담길 수 있는 공간 또는 그릇
으로 정의할 수 있음
변수 선언에 대한 메모리 영역의 변화
주소 | ··· | 1002 | 1003 | 1004 | 1005 | ··· |
데이터 | 이름: a 값: |
- 변수 선언을 하면 명령을 받은 컴퓨터는 메모리에서 비어있는 공간 하나를 확보함
- 위 표에서는 임의로 1003번으로 정함 (이 공간의 이름 (식별자)을 a라고 지정)
- 이후에 사용자가 a에 접근하고자 하면 컴퓨터는 메모리에서 a라는 이름을 가진 주소를 검색해 해당 공간에 담긴 데이터를 반환함
2. 데이터 할당
var a; // 변수 a선언
a = "abc"; // 변수 a에 데이터 할당
var a = "abc"; // 변수 선언과 할당을 한 문장으로 표현
- a라는 이름을 가진 주소를 검색해서 그곳에 문자열 ‘abc’를 할당하는 과정을 알 수 있음
- 그러니 실제로는 해당 위치에 문자열 ‘abc’를 직접 저장하지는 않음 (그 주소를 변수 영역에 저장하는 식으로 이뤄짐)
데이터 할당에 대한 메모리 영역의 변화
변수 영역 | 주소 | ··· | 1002 | 1003 | 1004 | 1005 | ··· |
변수 영역 | 데이터 | 이름: a 값: @5004 |
|||||
데이터 영역 | 주소 | ··· | 5002 | 5003 | 5004 | 5005 | ··· |
데이터 영역 | 데이터 | ‘abc’ |
-
데이터 할당의 흐름
- 변수 영역에서 빈 공간(@1003)을 확보
- 확보한 공간의 식별자를 a로 지정
- 데이터 영역의 빈 공간(@5004)에 문자열 ‘abc’를 저장
- 변수 영역에서 a라는 식별자를 검색(@1003)
- 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입
- 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위하여 변수 영역에 값을 직접 대입하지 않고 한단계를 더 거침
- 효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 최적
문자열 반환에 대한 메모리 영역의 변화
주소 | ··· | 1002 | 1003 | 1004 | 1005 | ··· |
데이터 | 이름: a 값: @5005(변경됨) |
|||||
주소 | ··· | 5002 | 5003 | 5004 | 5005 | ··· |
데이터 | ‘abc’ | ‘abcdef’ |
- 문자열 ‘abc’의 마지막에 ‘def’를 추가하라고 하면 ‘abc’가 저장된 공간에 ‘abcdef’를 할당하는 대신 ‘abcdef’라는 문자열을
새로
만들어 별도의 공간에 저장하고 그 주소를 변수 공간에 연결 - 기존 문자열에 어떤 변환을 가하든 상관 없이 무조건
새로 만들어 별도 공간에 저장
함
기존(@5004) 데이터는 자신의 주소를 저장하는 변수가 하나도 없게 되면 가비지 컬렉터의 수거 대상이 됨
데이터 타입의 종류
1. 불변값
변수
와상수
를 구분하는 성질은변경 가능성
임- 값을 바꿀 수 있으면 변수, 바꿀 수 없으면 상수
- 변수와 상수를 구분 짓는 변경 가능성의 대상은
변수 영역
메모리 임 (한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건) - 불변성 여부를 구분할 떄의 변경 가능성의 대상은
데이터 영역
메모리 임 - 기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol 모두
불변값
불변성
var a = "abc";
a = a + "def";
- 변수 a에 문자열 ‘abc’를 할당했다가뒤에 ‘def’를 추가하면 기존의 ‘abc’가 ‘abcdef’로 바뀌는 것이 아니라
새로운 문자열
‘abcdef’를 만들어 그 주소를 변수 a에 저장 (‘abc’와 ‘abcdef’는 완전히별개의 데이터
) - 문자열 값도 한 번 만든 값을 바꿀 수 없고, 숫자 값도 다른 값으로 변경할 수 없음
- 변경은 새로 만드는 동작을 통해서만 이뤄지며 이것이
불변값의 성질
임 - 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않음
2. 가변값
- 참조형 데이터는 모두 가변값일 것 같지만 기본적인 성질은 설정에 따라 변경 불가능한 경우(Object.defineProperty, Object.freeze)도 있고, 아예 불변값으로 활용하는 방안도 있음
- 기본형 데이터와의 차이는
객체의 변수(프로퍼티) 영역
이 별도로 존재한다는 점 - 참조형 자료형이 중첩된 경우를
중첩 객체
라고 함
3. 변수 복사
var a = 10;
var b = a;
var obj1 = { c: 10, d: "ddd" };
var obj2 = obj1;
변수 영역 | 주소 | 1001 | 1002 | 1003 | 1004 | ··· |
변수 영역 | 데이터 | 이름: a 값: @5001 |
이름:b 값: @5001 |
이름: obj1 값: @5002 |
이름:obj2 값:@5002 |
|
데이터 영역 | 주소 | 5001 | 5002 | 5003 | 5004 | ··· |
데이터 영역 | 데이터 | 10 | @7103 ~ ? | ‘ddd’ |
객체 @5002의 변수 영역 | 주소 | 7103 | 7104 | ··· |
객체 @5002의 변수 영역 | 데이터 | 이름:c 값:@5001 |
이름:d 값:@5003 |
- 변수를 복사하는 과정은 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 되는 점은 동일함
- 하지만 복사과정은 동일하지만 데이터 할당 과정에서 차이가 있기 때문에 변수 복사 이후의 동작에도 큰 차이가 있음
- 변수복사 이후 객체 자체를 직접 변경하면 메모리의 데이터 영역의 새로운 공간에 새 객체가 저장되고 그 주소를 변수 영역의 위치에 저장함 (
객체에 대한 변경임에도 값이 달라짐
) - 참조형 데이터의 가변값은 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 때를 의미하는 것을 알수 있음
불변 객체
- 값으로 전달받은 객체에 변경을 하더라도 원본 객체는 변하지 않아야 하는 경우가 생기는데 이럴 때 사용하는 것이 불변 객체
- 개발자들이 객체 내부의 변경을 필요할때 직접 불변 객체를 만들어 사용할 수 있지만 장기적으로 봤을때 위험 리스크가 크기 때문에 시스템적 제약을 거는게 안전함
- 자바스크립트 내장 객체가 아닌 라이브러리 자체에서 불변성을 지닌 별도의 데이터 타입과 그에 따른 메서드를 제공 해주는 라이브러리 등을 사용하는 것이 좋음
얕은 복사
var copyObject = function (target) {
var result = {};
for (var prop in target) {
result[prop] = target[prop];
}
return result;
};
var user = {
name: "Jaenam",
urls: {
portfolio: "http://github.com/abc",
blog: "http://blog.com",
facebook: "http://facebook.com/abc",
},
};
var user2 = copyObject(user);
user2.name = "Jung";
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
- user 객체에 직접 속한 프로퍼티에 대해서는 새로운 데이터가 만들어지지만 한 단계 더 들어간 urls의 내부 프로퍼티들은 기존 데이터를 그대로 참조하여 말그대로 얕은복사 이므로 불변성을 보장하지 않음
- 불변성을 위해 user.urls 프로퍼티도 불변 객체로 만들 필요가 있음
깊은 복사
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;
};
// 결과
var obj = {
a: 1,
b: {
c: null,
d: [1, 2],
},
};
var obj2 = copyObjectDeep(obj);
obj2.a = 3;
obj2.b.c = 4;
obj.b.d[1] = 3;
console.log(obj); // { a: 1. b: { c: null, d: [1, 3] } }
console.log(obj2); // { a: 3. b: { c: 4, d: { 0: 1, 1: 2 } } }
- 기본형 데이터는 그대로 복사하면 되지만 참조형 데이터는 내부의 프로퍼티들을 복사해야 함
- 참조형 데이터가 있을 때마다 재귀적으로 함수를 호출하도록 구현하면 얕은 복사에서 없던 불변성을 지닌 객체를 복사할 수 있음
undefined 와 null
1. undefined
- 자바스크립트 엔진이 자동으로 undefined를 부여하는 경우
- 값을 대입하지 않은 변수 (데이터 영역의 메모리 주소를 지정하지 않은 식별자에 접근할 때)
- 객체 내부의 존재하지 않는 프로퍼티에 접근할 때
- return 문이 없거나 호출되지 않은 함수의 실행 결과
- 값으로 할당된 undefined는 실존하는 데이터이고 자바스크립트 엔진이 반환해주는 undefined는 문자 그대로 값이 없음을 의미
let, const 키워드는 LE가 활성화 될 때 생성되지만 실제 변수가 평가되기 전까지는 해당변수에 접근 불가
2. null
- 사용자가 명시적으로 ‘없음’ 을 표현하기 위해 대입한 값
- 값이 null 인지 판별할 경우에는
일치 연산자(===)
로 판별
typeof null 로 타입 체크시 object 라는점에 유의 (자바스크립트 자체 버그)