본문 바로가기
개인공부/JavaScript

불변값 & 가변값

by 왕큰새 2020. 7. 27.
728x90

불변 값

변수(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 대상이 되어 사라질것이다.