[코어 자바스크립트] 데이터 타입(1)

OROSY·2021년 7월 27일
1

JavaScript

목록 보기
49/53
post-thumbnail

데이터 타입

1. 데이터 타입의 종류

  • 기본형(Primitive Type) - 숫자, 문자열, boolean, null, undefined, 심볼 등
  • 참조형(Reference Type) - 객체, 배열, 함수, 날짜, 정규표현식, Map, WeakMap, Set, WeakSet 등

데이터 타입의 구분 이유

  • 기본형: 값이 담긴 주솟값을 바로 복제
  • 참조형: 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제

불변성과 가변성

기본형은 불변성, 참조형은 가변성이라는 속성을 갖는다고 말합니다. 이를 잘 이해하려면 메모리와 데이터에 대한 지식이 필요하고, 나아가 '식별자'와 '변수'의 개념을 구분할 수 있어야 합니다. 이러한 과정을 통해 메모리 영역에서 자바스크립트의 데이터가 처리되는 과정을 살펴보겠습니다.

2. 데이터 타입에 관한 배경지식

메모리와 데이터

컴퓨터는 모든 데이터를 0과 1로 바꿔 기억합니다. 0 또는 1만 표현할 수 있는 하나의 메모리 조각을 비트라고 합니다. 메모리는 매우 많은 비트들로 구성되어 있는데, 각 비트는 고유한 식별자(unique identifier)를 통해 위치를 확인할 수 있습니다. 그런데 고작 0이나 1만 표현할 수 있는 비트 단위로 위치를 확인하는 것은 매우 비효율적입니다. 그보다는 몇 개씩 묶어 하나의 단위로 여긴다면 표현할 수 있는 값도 늘어나면서 동시에 검색 시간을 줄일 수도 있을 겁니다.

C/C++, 자바 등의 정적 타입 언어는 메모리의 낭비를 최소화하기 위해 데이터 타입별로 할당할 메모리 영역을 2바이트, 4바이트 등으로 나누어 정해놓았습니다. 한편 자바스크립트는 메모리 용량이 과거보다 월등하게 커진 상황에서 등장했기에 상대적으로 메모리 관리에서 자유로워졌습니다. 그래서 메모리 공간을 좀 더 넉넉하게 할당했습니다. 숫자의 경우 정수형인지 부동소수형인지 구분하지 않고 64비트, 즉 8바이트를 확보합니다.

위에서 비트는 고유한 식별자를 지닌다고 했습니다. 바이트 역시 시작하는 비트의 식별자로 위치를 파악할 수 있을 것입니다. 모든 데이터는 바이트 단위의 식별자, 더 정확하게는 메모리 주솟값(Memory Address)을 통해 서로 구분하고 연결할 수 있습니다.

식별자와 변수

보통 변수(Variable)식별자(Identifier)를 혼용하는 경우가 많습니다. 이에 대한 구분을 해보도록 합시다.

변수는 '변할 수 있는 수'입니다. 물론, 변수는 값이 반드시 '숫자'여야하는 것은 아닙니다. 영어 단어 Variable은 원래 '변할 수 있다라는 형용사이지만 컴퓨터 용어로 쓸 때는 '변할 수 있는 무언가'라는 명사로 확장시켰습니다. 여기서 '무언가'란 데이터를 말합니다. 숫자도 데이터이고, 문자열, 객체, 배열 모두 데이터입니다. 식별자는 어떤 데이터를 식별하는 데 사용하는 이름, 즉 변수명입니다.

변수란? 변할 수 있는 데이터
식별자란? 변수명

3. 변수 선언과 데이터 할당

변수 선언

// 변수 선언
let a;

위의 내용은 "변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a로 한다"가 됩니다. 변할 수 있는 데이터이므로 undefined라 하더라도 나중에 바꾸면 됩니다. 이렇게 보면 결국 변수는 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이라 할 수 있습니다.

주소...1002100310041005...
데이터이름: a
값:

데이터 할당

let a;              // 변수 a 선언
a = 'abc';          // 변수 a에 데이터 할당

let a = 'abc';      // 변수 선언과 할당을 한 문장으로 표현

위와 같은 두 가지 방법에서 자바스크립트 엔진은 결국 같은 동작을 수행합니다. a라는 이름을 가진 주소를 검색해서 그곳에 문자열 'abc'를 할당하면 됩니다.

하지만 실제로는 해당 위치에 문자열 'abc'를 직접 저장하지 않습니다. 데이터를 저장하기 위한 별도의 메모리 공간을 다시 확보해서 문자열 'abc'를 저장하고, 그 주소를 변수 영역에 저장하는 식으로 이뤄집니다. 이제는 데이터의 성질에 따라 '변수 영역', '데이터 영역'으로 구분해서 설명하겠습니다.

데이터 할당에 대한 메모리 영역의 변화

  • 변수 영역
주소...1002100310041005...
데이터이름: a
값: @5004

  • 데이터 영역
주소...5002500350045005...
데이터'abc'

  1. 변수 영역에서 빈 공간(@1003)을 확보한다.
  2. 확보한 공간의 식별자를 a로 지정한다.
  3. 데이터 영역의 빈 공간(@5004)에 문자열 'abc'를 저장한다.
  4. 변수 영역에서는 a라는 식별자를 검색한다.(@1003)
  5. 앞서 저장한 문자열의 주소(@5004)를 @1003의 공간에 대입한다.

변수 영역에 값을 직접 대입하지 않고 굳이 번거롭게 다른 메모리 주소를 할당하는 것일까요? 이는 데이터 변환을 자유롭게 할 수 있게 함과 동시에 메모리를 더욱 효율적으로 관리하기 위함입니다.

문자열 변환에 대한 메모리 영역의 변화

  • 변수 영역
주소...1002100310041005...
데이터이름: a
값: @5005 (변경)

  • 데이터 영역
주소...5002500350045005...
데이터'abc''abcdef'

위와 같이 문자열 'abc'에 'def'를 추가하라고 한다면, 'abcdef'라는 문자열을 새로 만들어 별도의 공간에 저장하고, 그 주소를 변수 공간에 연결합니다. 반대로 'c'를 제거하라해도 새로 만들게 됩니다. 기존 문자열에 어떤 변환을 가하든 상관 없이 무조건 새로 만들어 별도의 공간에 저장하는 것입니다.

기본형 데이터와 참조형 데이터

불변값

위에서 언급했던 것처럼 기본형 데이터인 숫자, 문자열, boolean, null, undefined, Symbol은 모두 불변값입니다. 그러나 기억해야할 것은 변경 가능성의 대상은 데이터 영역 메모리입니다.

let a = 'abc';
a = a + 'def';

let b = 5;
let c = 5;
b = 7;

먼저 위의 두 줄을 보면, 위의 예시와 같습니다. 'abc'에 'def'를 추가하면 기존의 'abc'가 'abcdef'로 바뀌는 것이 아니라(불변) 새로운 문자열 'abcdef'를 만들어 그 주소를 변수 a에 저장합니다. 두 개는 완전히 별개의 데이터인 것입니다.

b라는 변수에는 숫자 5를 할당합니다. 그러면 컴퓨터는 일단 데이터 영역에서 5를 찾고, 없으면 그때 데이터 공간을 하나 만들어 저장합니다. 그 주소를 b에 저장합니다. c라는 변수도 같은 숫자인 5를 할당하려 합니다. 컴퓨터는 데이터 영역에서 5를 찾습니다. 위에서 이미 만들어놨으니 그 주소를 재활용합니다.

마지막 줄에서는 변수 b의 값을 7로 바꾸고자 합니다. 그러면, 기존의 데이터인 5를 7로 바꾸는 것이 아니라 기존에 저장했던 7을 찾아서 있으면 재활용하고, 없으면 새로 만들어 b에 저장합니다. 결국 5와 7 모두 다른 값으로 변경할 수 없습니다.

위와 같은 내용이 기본 데이터의 불변성이라는 성질입니다. 한 번 만들어진 값은 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않습니다.

가변값

기본형 데이터와 달리 참조형 데이터는 모두 가변값이라 했습니다. 기본적인 성질은 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고, 아예 불변값으로 활용하는 방안도 있습니다. 우선 참조형 데이터를 변수에 할당하는 과정부터 살펴봅시다.

let obj1 = {
  a = 1,
  b = 'bbb'
};

참조형 데이터의 할당

  • 변수 영역
주소1001100210031004...
데이터이름: obj1
값: @5001

  • 데이터 영역
주소5001500250035004...
데이터@7103 ~ ?1'bbb'

  • 객체 @5001의 변수 영역
주소7103710471057106...
데이터이름: a이름: b
값: @5003값: @5004

  1. 변수 영역에서 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj1로 지정합니다.
  2. 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹입니다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소(@7103 ~ ?)를 @5001에 저장합니다.
    2-1. 객체의 프로퍼티들을 저장하기 위한 메모리 영역은 크기가 정해져 있지 않고 필요한 시점에 동적으로 확보합니다.
  3. @7103 및 @7104에 각각 a와 b라는 프로퍼티 이름을 지정합니다.
  4. 데이터 영역에서 숫자 1을 검색합니다. 검색 결과가 없으므로 @5003에 저장하고, 이 주소를 @7103에 저장합니다. 문자열 'bbb' 역시 임의로 @5004에 저장하고, 이 주소를 @7104에 저장합니다.

참조형 데이터의 프로퍼티 재할당

let obj1 = {
  a = 1,
  b = 'bbb'
};

obj1.a = 2;

위처럼 obj1의 a 프로퍼티에 숫자 2를 할당하려 합니다. 데이터 영역에서 숫자 2를 검색합니다. 검색 결과가 없으므로 빈 공간인 @5005에 저장하고, 이 주소를 @7103에 저장합니다.

  • 변수 영역
주소10011002100310041005...
데이터이름: obj1
값: @5001

  • 데이터 영역
주소50015002500350045005...
데이터@7103 ~ ?1'bbb'2

  • 객체 @5001의 변수 영역
주소71037104710571067107...
데이터이름: a이름: b
값: @5005값: @5004

이와 같이 프로퍼티에 재할당이 일어났지만, 변수 obj1이 바라보고 있는 주소는 @5001로 변하지 않았습니다. 즉, '새로운 객체'가 만들어진 것이 아니라 기존의 객체 내부의 값만 바뀐 것입니다.

이외에도 중첩된 참조형 데이터(객체)의 프로퍼티 할당 등에 대해 추가적으로 학습하시면 데이터 타입에 대해 더욱 자세히 이해하실 수 있습니다.

다음 시간에는 이러한 데이터의 가변성, 불변성에 따라 생기는 얕은 복사와 깊은 복사에 대해 살펴보도록 하겠습니다.🥸

출처: 코어 자바스크립트 (정재남)

profile
Life is a matter of a direction not a speed.

0개의 댓글