불변 값
변수(variable)와 상수(constant)를 구분하는 성질은 '변경 가능성'이다.
바꿀 수 있으면 변수, 바꿀 수 없으면 상수이다. 불변 값과 상수를 같은 개념으로 오해하기 쉬운데,
이 둘을 명확히 구분할 필요가 있다.
변수와 상수를 구분 짓는 변경 가능성의 대상은 '변수 영역' 메모리이다.
데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건이다.
불변성 여부를 구분할 때의 변경 가능성의 대상은 '데이터 영역' 메모리이다.
기본형인 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변 값이다.
var a = 'abc';
a = a + 'def';
var b = 5;
var c = 5;
b = 7;
변수 a에 문자열 'abc'를 할당했다가 뒤에 'def'를 추가하면 기존의 'abc'가 'abcdef'로 바뀌는 것이 아니라 새로운
문자열 'abcdef'를 만들어 그 주소를 변수 a에 저장한다. 여기서, 'abc'와 'abcdef'는 완전히 별개의 데이터이다.
변수 b에 숫자 5를 할당한다. 컴퓨터는 데이터 영역에서 5를 찾고 되고, 없으면 데이터 공간을 하나 만들어 저장한다.
그 주소를 b에 저장하게 되는 것이다. c에서도 같은 수인 5를 할당하려고 한다. 컴퓨터는 데이터 영역에서
5를 찾고, 이미 만들어 놓은 값이 있으니 그 값을 재활용하게 되는 것이다.
b의 값을 7로 바꾸려 한다. 기존에 저장된 5 자체를 7로 바꾸는 것이 아니라
기존에 저장했던 7을 찾아 있으면 재활용, 없으면 새로 만들어서 b에 저장하는 것이다.
결국, 5와 7 모두 다른 값으로 변경할 수 없는 것이다.
문자열 값, 숫자 값 모두 다른 값으로 변경할 수 없다. 변경은 새로 만드는 동작을 통해서만 이루어진다.
이것이 불변 값의 성질인 것이다.
한번 만들어진 값은 가비지 셀렉팅을 당하지 않는 한 영원히 변하지 않는다.
가변 값
기본형 데이터는 모두 불변 값이다. 그렇다면, 참조형 데이터는 모두 가변 값인 것일까?
꼭 그렇지는 않다. 설정에 따라 변경 불가능한 경우도 있고, 아예 불변 값으로 활용하는 방안도 있다.
이런 내용들을 나중에 살펴보고, 일단 참조형 데이터를 변수에 할당하는 과정부터 확인해 볼 것이다.
var obj1 = {
a: 1,
b: 'bbb'
};
변수 영역
주소 | 1001 | 1002 | 1003 | 1004 | ---- |
이름: obj1 값 : @5001 |
데이터 영역
주소 | 5001 | 5002 | 5003 | 5004 | 5005 |
데이터 | @7103 ~ ? | 1 | 'bbb' |
객체 @5001의 변수 영역
주소 | ---- | 7103 | 7104 | 7105 | 7105 |
데이터 | 이름:a 값 : @5003 |
이름: b 값: @5004 |
1. 컴퓨터는 변수 영역의 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj1로 지정한다
2. 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다.
이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고 , 그 영역의 주소(@7103 ~?)를
@5001에 저장한다.
3. @7103 및 @7104에 각각 a와 b라는 프로퍼티 이름을 지정한다.
4. 데이터 영역에서 숫자 1을 검색한다. 검색 결과가 없으므로 임의로 @5003에 저장하고 이 주소를 @7103에 저장.
문자열 'bbb'도 마찬가지이다.
참조형 데이터가 왜 불변(immutable) 하지 않다고 하는지 예제를 통해 살펴보자.
var obj1 = {
a: 1,
b: 'bbb'
};
obj1.a = 2;
obj1의 a 프로퍼티에 숫자 2를 할당하려고 한다. 데이터 영역에서 숫자 2를 검색하고, 검색 결과가 없으니 빈 공간인
@5005에 저장하고, 이 주소를 @7103에 저장한다.
이때 변수 obj가 바라보고 있는 주소는 @5001로 변하지 않았다. '새로운 객체'가 만들어진 것이 아니라,
객체 내부의 값만 바뀐 것이다.
주소 | 1001 | 1002 | 1003 | 1004 | 1005 |
데이터 | 이름:obj 값 : @5001 |
||||
주소 | 5001 | 5002 | 5003 | 5004 | 5005 |
데이터 | @7103 ~ ? | 1 | 'bbb' | 2 | |
주소 | 7103 | 7104 | 7105 | 7107 | 7107 |
데이터 | 이름:a 값: @5005 |
이름:b 값: @5004 |
중첩된 참조형 데이터(객체)의 프로퍼티 할당
var obj = {
x: 3,
arr: [ 3, 4, 5 ]
};
1. 컴퓨터는 변수 영역의 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj로 지정한다.
2. 임의의 데이터 저장공간(@5001)에 데이터를 저장하려는데 , 이 데이터는 여러 개의 변수와 값들을
모아놓은 그룹(객체)이다. 이 그룹의 변수(프로퍼티)들을 저장하기 위해 별도의 변수 영역을 마련하고(@7103 ~?) ,
그 영역의 주소를 @5001에 저장한다.
3. @7103에 이름 x를, @7104에 이름 arr를 지정한다.
4. 데이터 영역에서 숫자 3을 검색한다. 없으므로 임의로 @5002에 저장하고, 이 주소를 @7103에 저장한다.
5. @7104에 저장할 값은 배열로서 역시 데이터 그룹이다. 이 그룹 내부의 프로퍼티들을 젖아하기 위해 별도의
변수 영역을 마련하고(@8104 ~ ? ), 그 영역의 주소를 @7104에 저장한다.
6. 배열의 요소가 총 3개이므로 3개의 변수 공간을 확보하고 각각 인덱스를 부여한다.(0,1,2)
7. 데이터 영역에서 숫자 3을 검색해서(@5002) 그 주소를 @8104에 저장한다.
8. 숫자 4, 5 검색해서 각 @5004, @5005 에 저장하고 이 주소를 @8105, @8106에 저장한다.
주소 | 1001 | 1002 | 1003 | 1004 | 1005 | ---- |
데이터 | 이름 : obj 값 : @5001 |
|||||
주소 | 5001 | 5002 | 5003 | 5004 | 5005 | ---- |
데이터 | @7103 ~ ? | 3 | @8104 ~ ? | 4 | 5 |
객체 @5001의 변수 영역
주소 | 7103 | 7104 | ---- |
데이터 | 이름: x 값: @5002 |
이름: arr 값 : @5003 |
배열 @5003의 변수 영역
주소 | 8104 | 8105 | 8106 | ----- |
데이터 | 이름: 0 값: @5002 |
이름: 1 값: @5004 |
이름:2 값 : @5005 |
obj.arr = 'str';
이런식으로, 재할당 명령을 내리면 어떤 현상이 발생할까?
@5006에 문자열 'str'을 저장하고, 그 주소를 @7104에 저장한다.
그러면 @5003은 더이상 자신의 주소를 참조하는 변수가 하나도 없게 된다.
어떤 데이터에 대해 자신의 주소를 참조하는 변수의 개수를 참조 카운트라고 한다.
@5003의 참조 카운트는 @7104에 @5003이 저장돼 있던 시점까지는 1이었다가 @7104에 @5006이 저장되는
순간 0 이 된다. 참조 카운트가 0인 메모리 주소는 가비지 컬렉터(garbage collector , GC)의 수거 대상이 된다.
가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모리 사용량이 포화 상태에 임박할 때마다
자동으로 수거 대상들을 수거(collecting)한다. 수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 되는 것이다.
즉, @5003은 참조 카운트가 0 이 됨에 따라 GC 대상이 되고, "@8104~ ? " 라는 값이 사라지게 될 것 이다.
이 과정에서 연쇄적으로 @8104 ~? 의 각 데이터들의 참조 카운트가 0이 되고, 이들 역시 GC 대상이 되어 사라질것이다.
'개인공부 > JavaScript' 카테고리의 다른 글
얕은 복사와 깊은 복사 (0) | 2020.07.29 |
---|---|
변수 복사 비교(기본형, 참조형) (0) | 2020.07.29 |
메모리와 데이터 (0) | 2020.07.27 |
ES6 에서의 추가된 Javscript 데이터 타입 및 기본 데이터 타입 (0) | 2020.07.27 |
Core JavaScript (0) | 2020.07.27 |