자바스크립트의 데이터 타입에는 크게 두 가지가 있습니다.
기본형은 불변성(immutability)을 가집니다. 기본형인 숫자 10을 담은 변수 a에 다시 숫자 15를 담으면 a의 값은 문제없이 15로 변하는데, "변하지 않는다"는 게 어떤 의미일까요?
const a = 1;
- 메모리에서 빈 공간(@1001)을 확보하고 식별자 a를 저장합니다.
- 또 다른 빈 공간(@5001)을 확보한 뒤 숫자 1을 저장합니다.
- @1001에 @5001을 저장합니다.
식별자가 저장된 공간에 직접 값을 대입하지 않는 이유는 메모리를 효율적으로 관리하기 위해서입니다.
만약 천 개의 변수를 생성해서 모든 변수에 숫자 1을 할당하는 상황을 생각해 보세요. 각 변수의 식별자가 저장된 공간에 매번 숫자 1을 할당하는 것보다는 숫자 1을 별도의 공간에 한 번만 저장하고 해당 주소만 입력하는게 더 효율적이겠죠?
앞서 기본형은 불변성을 가진다고 했죠. 이게 무슨 의미일까요?
let a = 1;
a = 2;
- 변수 a에 숫자 1을 할당합니다. 그러면 컴퓨터는 메모리 공간에서 숫자 1을 찾고, 없으면 새로 공간을 하나 만들어 저장하고 그 주소를 a에 저장합니다.
- 변수 a의 값을 2로 바꾸고자 합니다. 그러면 기존에 저장된 1을 2로 바꾸는 것이 아니라 2를 새로운 공간에 저장한 후 그 주소를 a에 저장합니다.
1과 2는 완전히 별개의 데이터이며, 모두 다른 값으로 변경할 수 없습니다.
변경은 새로 만드는 동작을 통해서만 이루어집니다. 이를 불변성이라고 합니다.
const obj = { a: 1, b: 2 };
- 메모리에 빈 공간(@1001)을 확보하고, 식별자 obj를 저장합니다.
- 또 다른 빈 공간(@5001)에 데이터를 저장하려고 보니 데이터가 여러 프로퍼티로 이뤄진 데이터 그룹입니다. 이 그룹 내부의 프로퍼티들을 저장하기 위한 별도의 공간들을 마련한 뒤 그 공간들의 주소(@7001~)를 @5001에 저장하고 @5001은 @1001에 저장합니다.
- @7001에 프로퍼티 a, @7002에 프로퍼티 b를 저장합니다.
- 메모리 공간에서 숫자 1을 검색합니다. 없으므로 @5003에 저장 후 이 주소를 @7001에 저장합니다. 숫자 2도 마찬가지로 @5004에 저장 후 이 주소를 @7002에 저장합니다.
기본형 데이터와의 차이점은 객체의 프로퍼티를 저장하는 영역이 따로 존재한다는 점이겠네요.
const a = 10;
let b = a;
const obj1 = { c: 10, d: 2 };
const obj2 = obj1;
기본형 데이터
1. 빈 공간(@1001)을 확보 후 식별자 a를 저장하고 다른 빈 공간(@5001)을 확보 후 숫자 10을 저장한 뒤 해당 주소를 @1001에 저장합니다.
2. 빈 공간(@1002)을 확보 후 식별자 b를 저장하고 식별자 a 공간에 저장된 숫자 10의 주소(@5001)를 @1002에 저장합니다.
참조형 데이터
1. 빈 공간(@1003)을 확보 후 식별자 obj를 저장하고 다른 빈 공간(@5002)을 확보 후 프로퍼티 그룹이 저장될 주소(@7001~)를 @5002에 저장하고 @5002를 @1003에 저장합니다.
2. @7001에 프로퍼티 c, @7002에 프로퍼티 d를 저장하고 @7001에는 @5001이, @7002에는 새로 확보해서 숫자 2를 저장한 @5003이 저장됩니다.
3. 빈 공간(@1004)을 확보 후 식별자 obj2를 저장하고 식별자 obj1(@1003)을 검색해 그 값인 @5002를 @1004에 저장합니다.
변수를 복사하는 과정은 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 되는 점에서 동일합니다.
@1001과 @1002는 모두 값이 @5001이 됐고, @1003과 @1004는 모두 값이 @5002가 됐습니다.
const a = 10;
let b = a;
const obj1 = { c: 10, d: 2 };
const obj2 = obj1;
b = 15;
obj2.c = 20;
- 15를 새로운 공간 @5004에 저장하고 식별자가 b인 주소를 찾습니다. @1002의 값이 @5004가 되겠네요.
- 20을 새로운 공간 @5005에 저장하고 식별자가 c인 주소를 찾습니다. @7001의 값이 @5005가 되겠네요.
차이점이 보이시나요? 기본형 데이터의 값은 달라진 반면, 참조형 데이터의 값은 달라지지 않았습니다.
이를 코드로 표현하면 다음과 같습니다.
a !== b
obj1 === obj2
프로퍼티가 아닌 객체 자체를 변경한다면 어떨까요?
const a = 10;
let b = a;
const obj1 = { c: 10, d: 2 };
let obj2 = obj1;
b = 15;
obj2 = { ...obj1 };
이번에는 b의 경우와 마찬가지로 obj2에 새로운 객체를 할당함으로써 값을 직접 변경했습니다.
그러면 메모리의 빈 공간에 새로운 객체가 저장되고 그 주소를 obj2에 저장하겠죠.
a !== b
obj1 !== obj2
흔히 참조형 데이터를 가변값이라고 하는데 여기서의 "가변"은 참조형 데이터 자체를 변경할 경우가 아니라 그 내부의 프로퍼티를 변경할 경우에만 성립합니다.