1-4. 기본형 데이터와 참조형 데이터
불변값, 변수, 상수의 차이점은?
변수와 상수를 구분하는 것은 변수 영역에 할당된 주소값을 바꿀 수 있는지에 대한 변경 가능성이다.
불변성 여부를 구분하는 것은 데이터 영역에 할당된 값이 변하지 않는다는 것을 의미한다.
자바스크립트의 기본형 데이터는 모두 불변성을 가진다. 그런데 기본형 데이터는 const
로 선언하지 않는 이상 모두 변경 가능하다. 그렇다면 불변성이란 무엇일까? 아래 그림으로 알아보자.
변수
그림-1
위에 그림에서 보는 것 처럼 변수는 값을 변경할 때 변수 영역에 저장된 주소 값을 바꿔서 데이터를 변경할 수 있다.
상수
그림-2
상수는 변수 영역에 할당된 주소 값을 변경할 수 없다.
불변성
불변성은 데이터 영역에 관한 것이다.
그림-1
에서 보는 것 처럼 변수에 새로운 값을 넣기 위해서는 데이터 영역에 새로운 값을 저장하고 그 주소를 변수영역에 저장한다. 즉, 데이터 영역에 할당된 값은 한 번 할당되면 가비지컬렉팅 당하지 않는 이상 변하지 않는다.
이것을 불변성이라고 한다.
가변값
참조형 데이터를 변수에 할당하는 방법
기본형 데이터는 모두 불변값이고, 참조형 데이터는 기본적으로는 가변값을 가진다. (Object.freeze 등의 설정을 하면 불변값) 일단 참조형 데이터가 어떻게 메모리에 저장되는지 아래 예시를 통해 알아보자.
let obj = {
a: 1,
b: 'bbb'
};
<!-- Code-1 -->
그림-3
책 11page 내용 참고
- 변수 영역의 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj로 지정한다.
- 임의의 데이터 저장 공간(@2001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소(@3001 ~ ?)를 @2001에 저장한다. (객체의 프로퍼티들을 저장하기 위한 메모리 영역은 크기가 정해져 있지 않고 필요한 시점에 동적으로 확보함)
- @3001과 @3002에 a와 b라는 프로퍼티 이름을 지정한다.
- 데이터 영역에서 숫자 1을 검색한다. 검색 결과가 없으므로 임의로 @2004에 저장하고, 이 주소를 @3001에 저장한다. 문자열 ‘bbb’또한 임의로 @2005에 저장하고, 이 주소를 @3002에 저장한다.
참조형 데이터의 프로퍼티 재할당
참조형 데이터의 프로퍼티를 재할당 할 때는 아래 예시처럼 동작한다.
const obj = {
a: 1,
b: 'bbb'
};
obj.a = 2;
<!-- Code-2 -->
그림-4
중첩 객체인 경우는 어떻게 저장될까?
중첩 객체란 참조형 프로퍼티 안에 참조형 데이터가 있는 경우를 말한다. 이 경우에는 메모리에 어떻게 저장되는지 아래 예시를 통해 살펴보자
const obj = {
x: 3,
arr: [3, 4, 5]
};
<!-- Code-3 -->
그림-5
- 변수 영역에 빈 공간(@1002)을 확보하고 이름을 obj로 지정한다.
- obj값을 데이터 영역에 저장하려고 하니 객체임을 인지한다. 따라서 객체의 프로퍼티들을 저장할 공간을 메모리 힙에 마련하고(@3001 ~ ?) 그 주소 값을 데이터 영역의 @2001에 저장한다.
- @3001과 @3002에 각각 x, arr라는 이름을 지정한다.
- 데이터 영역에서 숫자 3을 검색한다. 현재 데이터 영역에는 숫자 3이 없으므로 임의로 @2002에 저장하고 그 주소값을 @3001에 저장한다.
- @3002에 데이터를 저장하려고 하니 배열이다. 따라서 배열의 각 프로퍼티들을 저장하기 위해 메모리 힙에 공간을 마련한다.(@4001 ~ ?) 그리고 이 주소를 임의의 공간(@2003)에 저장하고, @3002에 @2003을 저장한다.
- 배열의 요소가 총 3개이므로 변수 공간을 확보하고 각각의 이름을 배열의 인덱스로 저장한다.
- 데이터 영역에서 숫자3을 검색한다(@2002) 그리고 이 주소를 @4001에 저장한다.
- 데이터 영역에서 숫자 4를 검색했으나 존재하지않으므로 임의의 공간(@2004)에 4를 저장하고 이 주소를 @4002에 저장한다.
- 데이터 영역에서 숫자 5를 검색했으나 존재하지않으므로 임의의 공간(@2005)에 5를 저장하고 이 주소를 @4003에 저장한다.
기본형 데이터와 참조형 데이터의 변수 복사
기본형 데이터와 참조형 데이터의 변수 복사에는 어떤 차이가 있는지 아래 예시를 통해 알아보자
let a = 10;
let b = a;
const obj1 = { c:10, d: 'ddd' };
const obj2 = obj1;
<!-- Code-4 -->
그림-6
Code-4가 실행되고 나면 메모리에 위와 같이 저장된다.
기본형 데이터의 복사 후 변경
Code-4의 아래 줄에 b = 15;
코드를 추가해서 b의 값을 재할당하면 메모리에서 어떤 변화가 일어나게 될까?
아래 그림을 통해 알아보자
그림-6
15라는 데이터가 아직 데이터영역에 존재하지 않으므로 새로운 공간 @2004에 15라는 숫자를 저장하고 변수 영역에서 식별자가 b인 주소를 찾아 값을 @2004로 변경해준다.
참조형 데이터의 복사 후 변경
Code-4의 아래에 obj2.c = 20;
라는 코드를 작성해서 참조형 데이터 내부의 값을 변경한다면 메모리에서 어떤 변화가 일어나게 될지 아래 그림을 통해 알아보자.
그림-7
기본형 데이터를 변경했을 때는 b의 주소값이 @2001 → @2004로 달라진 반면, 참조형 데이터는 obj1과 obj2의 주소값은 그대로인 채로 메모리 힙 안에 있는 c의 주소값만 @2001 → @2005로 변경되었다.
기본형 데이터와 참조형 데이터의 복사 후 변경 결과를 코드로 나타내면 다음과 같다.
a !== b
obj1 === obj2
참조형 데이터에서 객체 자체를 변경한다면?
참조형 객체를 복사한 후 내부 프로퍼티가 아니라 객체 자체를 변경한다면 메모리에 어떻게 저장되는지 다음 예시를 통해 알아보자.
const obj1 = { c:10, d: 'ddd' };
const obj2 = obj1;
obj2 = { c:20, d: 'ddd' };
obj2에 아예 새로운 객체를 할당했기 때문에 변수영역의 주소가 변경된다.