변수와 상수를 구분하는 성질은 '변경 가능성'이다.
불변값과 상수는 같은 개념인가?
변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이다.
한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건이다.
반면 불변성 여부를 구분할 때 변경 가능성의 대상은 데이터 영역 메모리이다.
숫자, 문자열, 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'
};
기본형 데이터와의 차이는 '객체의 변수(프로퍼티) 영역'이 별도로 존재한다는 점이다.
객체가 별도로 할애한 영역은 변수 영역일 뿐 '데이터 영역'은 기존의 메모리 공간을 그대로 활용한다.
데이터 영역에 저장된 값은 모두 불변값이다. 그러나 변수에는 다른 값을 얼마든지 대입할 수 있다.
이 부분이 참조형 데이터는 불변하지 않다라고 하는 이유이다.
프로퍼티 재할당
var = obj1 = {
a: 1,
b: 'bbb'
};
obj1.a =2;
obj1의 a 프로퍼티에 숫자 2를 할당하려 한다.
먼저 데이터 영역에서 숫잘 2를 검색한다. 겸색 결과가 없으므로 빈 공간인 @5005에 저장하고, 이 주소를 @7103에 저장한다.
변수 obj1이 가리키는 주소는 @5001로 변하지 않는다.
즉, 새로운 객체가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀐것이다.
참조형 데이터의 프로퍼티에 다시 참조형 데이터를 할당하는 경우
(중첩 객체)
var obj = {
x: 3,
arr: [3, 4, 5]
};
이후 obj.arr[1]을 검색하고자 하면 메모리에서는
- obj 검색 1: obj라는 식별자를 가진 주소를 찾는다.(@1002)
- obj 검색 2: 값이 주소이므로 그 주소로 이동(@5001)
- obj 검색 3: 값이 주소이므로 그 주소로 이동(@7103 ~ ?)
- obj.arr 검색 1: arr이라는 식별자를 가진 주소를 찾는다.(@7104)
- obj.arr 검색 2: 값이 주소이므로 그 주소로 이동(@5003)
- obj.arr 검색 3: 값이 주소이므로 그 주소로 이동(@8014 ~ ?)
- obj.arr[1] 검색 1: 인덱스 1에 해당하는 주소를 찾는다.(@8105)
- obj.arr[1] 검색 2: 값이 주소이므로 그 주소로 이동(@5004)
- obj.arr[1] 검색 3: 값이 숫자형 데이터이므로 4를 반환.
위 상태에서 다음과 같이 재할당 명령을 내리는 경우
obj.arr = 'str';
@5006에 문자열 'str'을 저장하고, 그 주소를 @7104에 저장한다.
그렇다면 @5003은 더이상 자신의 주소를 참조하는 변수가 하나도 없게 된다.
어떤 데이터에 대해 자신의 주소를 참조하는 변수의 개수를 참조 카운트라고 한다.
@5003의 참조 카운트는 이 시점에서 0이 되는 것이다.
참조 카운트가 0인 메모리 주소는 가비지 컬렉터의 수거 대상이 된다.
수거된 메모리는 다시 새로운 값을 할당할 수 있는 빈 공간이 된다.
참조 : 코어 자바스크립트