코어 자바스크립트
책의 1장 데이터 타입 내용을 정리한 글이다.
변수(variable)
와 상수(constant)
를 구분하는 성질은 변경 가능성이다. 불변값
과 상수
를 같은 개념으로 오해하기 쉬운데, 이 둘은 명확히 구분할 필요가 있다. 변수
와 상수
를 구분 짓는 변경 가능성의 대상은 변수 영역의 메모리이다. 한번 데이터 할당이 이루어진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건이다. 반면 불변성
여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리이다.
기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변값이다. 그 중 숫자를 예로 들어 불변성의 개념을 알아보자.
var a = 5;
a = 7;
변수 a에 숫자 5를 할당했다. 그러면 컴퓨터는 일단 데이터 영역에서 5를 찾고, 없으면 그제서야 데이터 공간을 하나 만들어 저장한다. 그 주소를 a의 값으로 저장한다.
이후 변수 a의 값을 7로 바꾸고자 한다. 그러면 기존에 저장된 5 자체를 7로 바꾸는 것이 아니라 기존에 저장했던 7을 찾아서 있으면 재활용하고, 없으면 새로 만들어 a에 저장한다. 결국 5와 7 모두 다른 값으로 변경할 수 없다.
이처럼 문자열 값도 한 번 만든 값을 바꿀 수 없고, 숫자 값도 다른 값으로 변경할 수 없다. 변경은 새로 만드는 동작을 통해서만 이루어진다. 이것이 바로 불변값의 성질이다. 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.
기본형 데이터는 모두 불변값인데 그렇다면 참조형 데이터는 모두 가변값일것 같은 생각이 든다. 기본적인 성질은 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고, 아예 불변값으로 활용하는 방안도 있다. 우선 참조형 데이터를 변수에 할당하는 과정부터 살펴보자.
var obj = {
a: 1,
b: 'bbb'
};
변수 영역
주소 1001 1002 1003 1004 ··· 데이터 이름: obj
값:@5001데이터 영역
주소 5001 5002 5003 5004 ··· 데이터 @7103 ~ ? 1 'bbb' 객체 @5001의 변수 영역
주소 7103 7104 7105 7106 ··· 데이터 이름: a
값:@5003이름: b
값:@5004
참조형 데이터를 변수에 할당하는 과정은 다음과 같다.
obj
로 지정한다.a
와 b
라는 프로퍼티 이름을 지정한다.데이터 영역에 저장된 값은 모두 불변값이다. 그러나 변수에는 얼마든지 다른 값을 대입할 수 있다. 바로 이 부분 때문에 흔히 참조형 데이터는 불변(immutable)하지 않다(가변값이다)라고 하는 것이다.
프로퍼티를 재할당하는 예제로 확인해보자.
var obj = {
a: 1,
b: 'bbb'
};
obj.a = 2;
변수 영역
주소 1001 1002 1003 1004 ··· 데이터 이름: obj
값:@5001데이터 영역
주소 5001 5002 5003 5004 5005 ··· 데이터 @7103 ~ ? 1 'bbb' 2 객체 @5001의 변수 영역
주소 7103 7104 7105 7106 ··· 데이터 이름: a
값:@5005이름: b
값:@5004
obj
의 a
프로퍼티에 숫자 2를 할당하려고 한다. 데이터 영역에서 숫자 2를 검색한다. 검색 결과가 없으므로 빈 공간인 @5005에 저장하고, 이 주소를 @7103에 저장한다. 변수 obj
가 바라보고 있는 주소는 @5001로 변하지 않았다. 즉 '새로운 객체'가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀐 것이다.
동작 방식을 알았으니 이제 기본형 데이터와 참조형 데이터의 차이를 확인해보자.
먼저 변수를 복사할 때의 변화를 살펴보자.
var a = 10;
var b = a;
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;
변수 영역
주소 1001 1002 1003 1004 ··· 데이터 이름: a
값:@5001이름: b
값:@5001이름: obj1
값:@5002이름: obj2
값:@5002데이터 영역
주소 5001 5002 5003 5004 ··· 데이터 10 @7103 ~ ? 'ddd' 객체 @5002의 변수 영역
주소 7103 7104 7105 7106 ··· 데이터 이름: c
값:@5001이름: d
값:@5003
우선 기본형 데이터
부터 살펴보자.
a
로 지정한다.이렇게 a
에 대한 변수 선언 및 할당이 종료되고 이제 복사를 할 차례이다.
b
로 지정한다.a
를 검색해 그 값을 찾아와야 하는데, @1001에 저장된 값인 @5001을 @1002에 값으로 대입한다.다음으로 참조형 데이터
이다.
obj1
로 지정한다.c
를, @7104에는 식별자 d
를 입력한 다음, c
에 대입할 값 10을 데이터 영역에서 검색한다.이렇게 obj1
에 대한 선언 및 할당 과정이 종료되고 이제 복사를 할 차례다.
obj2
로 지정한다.obj1
을 검색해 그 값인 @5002를 @1004에 값으로 대입한다.변수를 복사하는 과정은 기본형 데이터와 참조형 데이터 모두 같은 주소를 바라보게 되는 점에서 동일하다. 하지만 데이터 할당 과정에서 이미 차이가 있기 때문에 변수 복사 이후의 동작에 큰 차이가 발생한다.
var a = 10;
var b = a;
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;
b = 15;
obj2.c = 20;
변수 영역
주소 1001 1002 1003 1004 ··· 데이터 이름: a
값:@5001이름: b
값:@5001이름: obj1
값:@5002이름: obj2
값:@5002데이터 영역
주소 5001 5002 5003 5004 5005 ··· 데이터 10 @7103 ~ ? 'ddd' 15 20 객체 @5002의 변수 영역
주소 7103 7104 7105 7106 ··· 데이터 이름: c
값:@5005이름: d
값:@5003
기본형 데이터
를 복사한 변수 b
의 값을 바꿨더니 @1002의 값이 달라진 반면, 참조형 데이터
를 복사한 변수 obj2
의 프로퍼티의 값을 바꿨더니 @1004의 값은 달라지지 않았다. 즉, 변수 a
와 b
는 서로 다른 주소를 바라보게 됐으나, 변수 obj1
과 obj2
는 여전히 같은 객체를 바라보고 있는 상태이다.
이를 코드로 표현하면 다음과 같다.
a !== b
obj1 === obj2
이 결과가 바로 기본형과 참조형 데이터의 가장 큰 차이점이다. 대부분의 자바스크립츠 책에서는 '기본형은 값을 복사하고 참조형은 주솟값을 복사한다'고 설명하고 있지만, 사실은 어떤 데이터 타입이든 변수에 할당하기 위해서는 주솟값을 복사해야 하기 때문에, 엄밀히 따지면 자바스크립트의 모든 데이터 타입은 참조형 데이터일 수밖에 없다. 다만 기본형은 주솟값을 복사하는 과정이 한 번만 이뤄지고, 참조형은 한 단계를 더 거치게 된다는 차이가 있다.