데이터 타입(data type)
일반적으로 기본형은 할당이나 연산시 복제되고, 참조형은 참조된다.
기본형은 값이 담긴 주솟값을 바로 복제
하는 반면 참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제
한다.
기본형을 불변성(immutability)을 띈다.
| 0 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | (= 1byte = 8bit)
각 비트는 고유한 식별자를 지니고, 바이트 역시 시작하는 비트의 식별자로 위치를 파악할 수 있다.
모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값(memory address)
를 통해 서로 구분하고 연결할 수 있다.
var a;
변수란 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이다.
var a;
a = 'abc';
var a = 'abc';
데이터 할당에 대한 메모리 영역의 변화
1. 변수 영역에서 빈 공간(@1003)을 확보한다.
2. 확보한 공간의 식별자를 a로 지정한다.
3. 데이터 영역의 빈 공간(@5004)에서 문자열 'abc'를 저장한다.
4. 변수 영역에서 a라는 식별자를 검색한다(@1003)
5. 앞서 저장한 문자열의 주소 (@5004)를 @1003의 공간에 대입한다.
왜 변수 영역에 값을 직접 대입하지 않고 굳이 번거롭게 한 단게를 더 거치는 걸까?
기존 문자열에 어떤 변환을 가하든 무조건 새로 만들어 별도의 공간에 저장한다.
예를 들어 500 개의 변수를 생성 후 모든 변수에 숫자 5를 할당한다고 했을 때
각 변수 공간마다 숫자 5를 할당하려고 한다면 4000(500개의 변수 * 숫자 8비트)바이트를 써야 한다.
그 대신 5를 별도의 공간에 저장하고 해당 주소만 입력한다면?
1008(500개의 변수 * 2주소 공간 + 숫자 8비트)바이트만 이용하면 된다.
이처럼 변수 영역과 데이터 영역을 분리하면 중복된 데이터에 대한 처리 효율이 높아진다.
변수와 상수를 구분하는 성질은 '변경 가능성'이다.(바꿀수 있으면 변수, 없으면 상수)
변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이다. 한 번 데이터 할당이 이뤄진 변수 공간에 다른 데이터를 재할당할 수 있는지 여부가 관건이다.
반면 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리
입니다.
기본형 데이터인 숫자, 문자열, 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로 바꾸려고 한다. 기존에 저장했던 7을 찾아 있으면 재활용하고, 없으면 새로 만들어 b에 저장한다.
결국 5와 7 모두 다른 값으로 변경할 수 없다.
변경은 새로 만드는 동작을 통해서만 이루어진다. 이것이 불변값의 성질이다.
한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.
var obj1 = {
a: 1,
b: 'bbb'
};
obj1.a = 2;
참조형 데이터의 할당 및 프로퍼티 재할당
1. 변수 영역에서 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj1로 지정한다.
2. 데이터 저장공간(@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다. 이 그룹 내부의 프로퍼티를 저장하기 위해 별도 변수 영역을 마련하고, 그 영역의 주소(@7103 ~ ?)를 @5001에 저장한다.
3. @7103 및 @7104에 각각 a와 b를 저장한다.
4. a의 값인 1을 데이터 영역에서 검색한다. 검색결과가 없으므로 @5003에 저장하고, 이 주소를 @7103에 저장한다. b의 값은 'bbb' 역시 임의로 @5004에 저장한 후, 이 주소를 @7104에 저장한다.
5. 데이터 영역에서 숫자 2를 검색한다. 검색결과가 없으므로 @5005에 2를 저장하고 이 주소를 @7103에 저장한다.
=> 변수 obj1이 바라보고 있는 주소는 @5001로 변하지 않았다. 즉 새로운 객체가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀌었다.
var obj = {
x: 3,
arr: [3, 4, 5]
};
obj.arr = 'str';
중첩 객체의 프로퍼티 할당 및 재할당
1. 변수 영역의 빈 공간(@1002)를 확보하고, 그 주소의 이름을 obj로 지정한다.
2. 임의의 데이터 공간(@5001)에 데이터를 저장하려는데, 여러 개의 변수와 값들로 이루어진 객체이다. 이 그룹의 각 변수들(x, arr)을 저장하기 위하여 별도의 변수 영역을 마련하고(@7103 ~ ?), 그 영역의 주소를 @5001에 저장한다.
3. @7103에 x를 @7104에 arr을 저장한다.
4. 데이터 영역에서 숫자 3을 검색 후 없으므로 @5002에 저장하고 이 주소를 @7103에 저장한다.
5. @7104에 저장할 값은 배열이므로 이 그룹의 내부 프로퍼티를 저장하기 위해 별도의 변수 영역을 마련하고(@8104 ~ ?) 그 주소 정보를 @5003에 저장한다. 그 다음 @7104에 @5003을 저장한다.
6. 배열의 요소가 3개 이므로 3개의 변수공간을 확보하고 @8104 ~ @8106에 각각 인덱스를 부여한다.
7. 데이터 영역에서 숫자 3을 검색 후 그 주소(@5002)를 @8104에 저장한다.
8. 데이터 영역에서 숫자 4를 검색 후 없으므로 @5004에 저장하고, 이 주소를 @8105에 저장한다.
9. 데이터 영역에서 숫자 5를 검색 후 없으므로 @5005에 저장하고, 이 주소를 @8106에 저장한다.
10. @1002 -> @5001 -> @7103~? -> @7104 -> @5003
@5003에 저장된 값이 배열의 요소로 지정되어 있으므로, 값 'str'을 다른 데이터 영역에서 검색한 후 없으므로 @5006에 값을 저장하고, 그 주소를 @7104에 저장한다.
이때 @5003의 참조 카운트는 1 -> 0이 됨에 따라 GC 대상이 되고, 연쇄적으로 @8104 ~ ? 데이터들도 같이 사라진다.
어떤 상황에서 불변 객체가 필요할까?
값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우
얕은 복사(Shallow Copy)는 바로 아래 단계의 값만 복사하는 방법
이고,
깊은 복사(Deep Copy)는 내부의 모든 값들을 하나 하나 전부 복사하는 방법
이다.
어떤 객체를 복사할 때, 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들고자 할 때,
객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우에는 그대로 복사하면 되지만
참조형 데이터일 경우에는 다시 그 내부의 프로퍼티들을 복사해야 한다.
깊은 복사 하는 방법
1. 객체를 복사할 경우 내부 프로퍼티를 순회하여 그 값이 참조형일 경우 다시 그 내부의 프로퍼티들을 복사하도록 한다.
2. hasOwnProperty 메서드를 활용해 프로토타입 체이닝을 통해 상속된 프로퍼티를 복사하지 않게끔 한다.
3. 객체를 JSON 문법으로 표혀된 문자열로 전환했다가 다시 JSON 객체로 바꾼다.var copyObjectViaJSON = function(target) { return JSON.parse(JSON.stringify(target)); };
자바스크립트에서 '없음'을 나타내는 값 두 가지.
자바스크립트 엔진은 사용자가 어떤 값을 지정할 것이라고 예상되는 상황임에도 실제로는 그렇게 하지 않았을 때 undefined를 반환한다.
'비어있는 요소'와 'undefined를 할당한 요소'는 출력 결과부터 다르며, '비어있는 요소'는 순회와 관련된 많은 배열 메서드들의 순회 대상에서 제외된다.
'비어있음'을 명시적으로 나타내고 싶을 때는 null을 사용한다.
null의 typeof 값은 object이므로(자바스크립트 버그) 어떤 변수가 실제로 null인지 아니면 undefined인지는 일치연산자(===)를 이용해야 정확히 판별할 수 있다.