자바스크립트의 데이터 타입은 아래와 같습니다.
이번 포스팅에서 사용하는 @ 기호는 "참조한다" 라는 뜻을 가지고있습니다. 메모리 할당 부분을 보실 때 참고해주세요^^
| Primitive Type ( 원시타입 ) | Reference Type ( 참조타입 ) |
|---|---|
| Number : 숫자 String : 문자열 Boolean : 논리형 null : 빈값 (개발자가 의도적으로 빈 값을 할당할 때 사용) Undefined : 정의되지 않은 값 (변수를 초기화하지 않으면 쓰레기값이 할당) Symbol : |
Object - Array, Function, RegExp, Set / WeakSet, Map, Weak Map 등등 |
메모리에 할당되는 메커니즘에따라 데이터타입이 구분됩니다.
Stack memory : 변수, 원시타입 데이터, 정적 할당
Heap memory : 참조타입 데이터, 동적 할당
스택 메모리, 힙 메모리는 추후에 깊게 파고들어보겠습니다.
데이터가 저장되는 공간, Memory
컴퓨터에는 다양한 메모리의 종류가 있는데요, 반영구 데이터를 저장하는 HDD, 잠시동안 데이터를 저장하는 플래시메모리 등이 있습니다. 우리는 플래시 메모리를 주로 다루게 될것으로 생각됩니다.
설명에 앞서 아래부터 나오는 표는 메모리의 형태를 대략적으로 그려놓은 것 입니다
메모리는 각각의 셀마다 고유주소를 가지고있습니다.
변수의 선언과 초기화
const a=10; //자바스크립트는 선언과 초기화를 한번에 하여도 내부적으로 아래와같이 선언, 초기화를 별도로 진행합니다. const a; // 1. 변수를 선언함과 동시에 임의의 메모리( 1003 )에 식별자 a 를 저장합니다. a = 10; // 2. 초기화와 동시에 임의의 메모리 ( 5004 )에 값 10을 할당하고, // 3. 메모리에 식별자 a를 찾아서 a에 값에 10의 메모리주소 ( 5004 )를 할당합니다.
주소 ... 1002 1003 1004 1005 ... 데이터 1. 이름:a
3. 값:@5004
주소 ... 5002 5003 5004 5005 ... 데이터 2. 10 위와 같이 a 식별자가 저장된 메모리는 값 10을 직접 가지고있는게 아니라 10이라는 값의 메모리주소를 저장하고 간접적으로 참조하고있습니다.
선언된 변수의 값을 변경하면 어떻게 될까요? 5004번 메모리에 값이 변경될까요?? 정답은 '아니다' 입니다.
변수값의 변경
const a=10; const a; // 1. 변수를 선언함과 동시에 임의의 메모리( 1003 )에 식별자 a 를 저장합니다. a = 10; // 2. 초기화와 동시에 임의의 메모리 ( 5004 )에 값 10을 할당하고, // 3. 메모리에 식별자 a를 찾아서 a에 값에 10의 메모리주소 ( 5004 )를 할당합니다. a = 20; // 4. 임의의 메모리 ( 5005 ) 번에 새로운 값 20을 저장하고 식별자 a의 매핑된 메모리 주소를 5005번으로 다시 매핑합니다.
주소 ... 1002 1003 1004 1005 ... 데이터 1. 이름:a
3. 값:@5004 -> 5.@5005
주소 ... 5002 5003 5004 5005 ... 데이터 2. 10 4. 20
만약 같은 값을 가지는 변수를 여러개 만든다면 어떻게 될까요?
변수의 복사
const a=10; const a; // 1. 변수를 선언함과 동시에 임의의 메모리( 1003 )에 식별자 a 를 저장합니다. a = 10; // 2. 초기화와 동시에 임의의 메모리 ( 5004 )에 값 10을 할당하고, // 3. 메모리에 식별자 a를 찾아서 a에 값에 10의 메모리주소 ( 5004 )를 할당합니다. const b = 10;// 4. 메모리상에 값 10이 있는지 먼저 확인해보고 있다면 그 주소를 참조합니다.
주소 ... 1002 1003 1004 1005 ... 데이터 1. 이름:a
3. 값:@50041. 이름:b
3. 값:@5004
주소 ... 5002 5003 5004 5005 ... 데이터 2. 10 20
원시타입 데이터는 위와같은 메커니즘으로 할당되기 때문에 메모리상에 중복되는 값이 존재하지 않습니다. 이미 존재하는 값이라면 참조하면되고, 새로운 값을 만들었다면 다른 메모리에 할당하기 때문입니다. 엄청난 메모리 효율이죠^^?
참조타입 데이터의 메모리 할당 방식은 조금 더 복잡합니다. 원시타입 데이터보다 한단계 더 메모리에 접근해야하거든요^^.
변수의 선언과 초기화
const obj = { a:1 , b:'text' }
주소 ... 1002 1003 1004 1005 ... 데이터 이름:obj / 값:@5002
주소 ... 5002 5003 5004 5005 ... 데이터 값: @7002 ~ ...
주소 ... 7002 7003 7004 7005 ... 데이터 이름:a / 값:@9002 이름:b / 값:@9003
주소 ... 9002 9003 9004 9005 ... 데이터 1 text
- 1002 메모리에 obj 변수의 식별자, 값( 메모리 주소 )을 저장합니다.
- 메모리 한칸에 저장되는 값은 1개를 초과할 수 없기때문에 7002 ~ ... ( 값이 얼마나 될지 모르기에 많은 메모리 확보 ) 값을 나누어 담을 메모리 블럭을 참조합니다.
- 확보된 메모리 블럭 한칸 한칸에 객체 프로퍼티의 식별자,값( 메모리 주소 )를 할당합니다.
- 각 객체 프로퍼티의 값이 임의에 메모리에 저장됩니다.
객체 프로퍼티의 변경
const obj = { a:1 , b:'text' } obj.a = 100; //객체 프로퍼티의 값 변경
주소 ... 1002 1003 1004 1005 ... 데이터 이름:obj / 값:@5002
주소 ... 5002 5003 5004 5005 ... 데이터 값: @7002 ~ ...
주소 ... 7002 7003 7004 7005 ... 데이터 이름:a / 값:@9002 -> @9005 이름:b / 값:@9003
주소 ... 9002 9003 9004 9005 ... 데이터 1 text 100
- 객체프로퍼티의 값을 변경하면 메모리에 같은 값이 있는지 확인하고, 없다면 새로 할당합니다. / 9005번 임의로 선정
- 9005번의 값이 obj 객체 -> 5002 -> 7002 를 찾아가서 @9005를 참조하도록 변경합니다.
객체 프로퍼티의 복사와 복사된 객체의 값 변경
복사한 객체의 값을 변경했더니 원본의 값이 같이 변경되는건 왜일까요?? 이유는 아래와 같습니다.const obj = { a:1 , b:'text' } const obj2 = obj ; // Obj 복사 obj2.b = '텍스트'
주소 ... 1002 1003 1004 1005 ... 데이터 이름:obj / 값:@5002 이름:obj2 / 값:@5002
주소 ... 5002 5003 5004 5005 ... 데이터 값: @7002 ~ ...
주소 ... 7002 7003 7004 7005 ... 데이터 이름:a / 값:@9002 이름:b / 값:@9003 -> @9005
주소 ... 9002 9003 9004 9005 ... 데이터 1 text 텍스트
- 복사한 obj2.b 의 값을 변경하면 임의의 메모리에 원시타입 데이터 '텍스트'를 생성합니다.
- 7003으로 찾아가 b 가 참조하는 메모리주소를 @9005로 변경합니다.
어떤가요 여러분?
원시타입과 참조타입의 메모리 할당을 보다보니 이상한점을 느끼셨나요? 네 맞습니다.
예제에서 원시타입 데이터의 식별자인 a 는 메모리상에서 참조하는 메모리가 직접적으로 변경되어 "값"이 변하게 되었구요,
참조타입 데이터의 식별자인 obj 는 메모리상에서 참조하는 메모리가 직접적으로 변경되지 않아 "값"이 변하지 않았습니다.
원시타입 데이터는 메모리상에 같은 값이 중복되어 존재하지 않는다. ( 불변성 )
원시타입 데이터를 가진 변수는 값이 변경되면 참조하는 메모리 주소가 변경된다.
참조타입 데이터는 복제한 객체의 값을 변경하면 원본 객체의 값이 변경된다. ( 식별자가 참조하는 메모리가 변경되지 않고 같은 메모리를 보고있기 때문에. )