2020-12-10 JS 데이터타입과 변수저장방식
데이터타입
-
Primitive : number, string, boolean, null, undefined, symbol => 기본형은 메모리 스택영역에 값이 함께 할당되고 연산시 복제된다.
-
reference : object, array, function, date, regex가 있다. Map, WeakMap, Set 등은 Object의 하위개념이다. => 참조형은 주소값이 저장된다. 참조형 객체들을 복사하면 값이 복사되는게 아닌 주소값이 복사된다.
-
JS에서는 Number에서 8바이트를 확보한다. 이렇게 확보하는 이유는 과거에 비해 메모리가 넉넉해졌기 때문이다.
-
변수와 식별자. 변수는 변할 수 있는 값을 의미하고 식별자는 변수의 이름을 지칭한다.
-
const identifier = "hello world"; let tmp = 1; tmp = "1";
-
위의 코드처럼 tmp, identifier는 값을 구별할 수 있는 식별자이고, 안에 있는 데이터는 변수라고 이야기한다.
-
데이터의 변화에 대해 효율적으로 관리하기 위해 변수영역과 데이터영역을 따로 분리한다. identifier, tmp는 변수영역의 특정 주소값에 저장되고, 각각의 값들은 데이터영역의 주소값이 저장된다.
- String의 경우 영어, 한글이냐에 따라 각각 1바이트, 2바이트로 구분되고 전체글자수와 필요한 메모리양이 다르기 때문에 데이터영역, 변수영역으로 분리를 해야 가변적으로 대응이 가능하다.
-
-
불변과 상수 : 변수와 상수를 구분 짓는 대상은 변수영역의 메모리다. 한번 데이터할당이 이루어진 다시 데이터를 재할당 여부이고, 불변은 데이터영역의 메모리를 구분한다. 기본값들은 모두 불변이다.
- 변수가 가변하다는건 변수영역의 데이터 주소값이 달라질 수 있다는 의미이다.
-
참조형 : 참조형은 기본값과 달리 객체의 프로퍼티 영역이 별도로 존재한다.
-
let obj { number: 1, tmp : "tmp" };
-
위와 같은 obj가 있다고 가정하자. 변수 obj는 변수영역의 특정 주소에 저장되고, 값은 데이터영역의 특정주소값이 매핑이 된다. 하지만 프로퍼티들이 존재하기 때문에 데이터 영역의 특정주소가 매핑되는건, @새로운주소값~?까지 각 프로퍼티들에 대한 주소값을 가지게 된다.
- 만약 number에 대한 주소값이 4000이고 tmp에 대한 주소값이 4001라고 하면, 변수영역의 4000과 4001은 1, “tmp”를 가지고 있는 주소값을 찾아서 저장하고 없으면 데이터영역에 1, tmp를 새로 할당하여 저장한다.
-
-
데이터에 의해 자신의 주소를 참조하는 변수 갯수를 참조카운트라고 정의한다. 참조카운트가 0이면 GC의 대상이된다.
-
변수의 복사
-
let a = 10; let b = a; let obj1 = {c : 10, d: 'hello'} obj2 = obj1; b = 20; obj2.c = 30; // 해결하기 obj2 = {c: 30, d: 'hello'}
-
주소 1001 1002 1003 1004 1005 데이터 name : a
value: @5001name:b
value: @5004name: obj1
value: @5002name: obj2
value: @5002주소 5001 5002 5003 5004 5005 데이터 10 @7103~? ‘hello’ 20 30 주소 7103 7104 데이터 name: c
value: @5005name: d
value: @5003b에 있는 값을 20으로 할당할때, 데이터영역에서 20이 있는지 확인하고 있으면 20에 해당하는 주소값 @5004를 할당한다. 없으면 데이터영역의 새로운 주소에 값을 할당
-
obj2.c를 변경할때 문제가 발생한다. obj는 변수영역의 1002주소값에 저장되어있고 값은 5002에 저장되어있다. 5002를 보면 @7103~?까지 참조를 하고 있고, 프로퍼티 c는 7103에 저장되어있고 @5004에 값이 할당되어있다. 30으로 변경하면 @5005로 변경한다. 하지만 obj1 역시도 @5002를 참조하고 있고, @5002에서 7103~으로 바라보고 있기때문에 obj1.c도 30으로 변한다. 이게 가장 큰 차이다.
-
기본형도 참조형도 모두다 주소값을 복하한다. 하지만 기본형은 주소값을 1번만 복사하고, 참조형은 단계가 더 있어서 이런 상황이 발생한다.
- 마지막줄에 있는 코드처럼 재할당을 하면 위의 이슈가 해결된다.
-
-
얕은 복사는 바로 아래단계 값만 복사하고 깊은복사는 내부의 모든 값을 복사한다. JS의 copyObject는 얕은복사만 수행. 이런경우 nestedObject에서 복사할때 주소값만 복사하기 때문에 원본 사본이 모두 동일한 주소값을 가리키게 된다.
-
let user = { name: 'jimmy', assets: { facebook: 200, google: 1000, apt: "apt" } } let user2 = copyObject(user); user2.name = 'test'; user.name === user2.name => false; user.assets.facebook = 10000; user.assets.facebook === user2.assets.facebook => true
- 복제한 객체에 대한 변경 이슈를 해결하기 위해서는 내부적으로 모두 복사하는 깊은복사가 필요하다.
-
-
JS에서 undefined를 리턴하는 경우
- 값을 할당하지 않은 변수
- 객체 내부에 존재하지 않는 프로퍼티에 접근할때
- return이 없거나 호출되지 않는 함수의 실행결과
-
null은 typeof가 object => JS버그