본문으로 건너뛰기

Data Type

목차

데이터 타입의 종류

Primitive type

  • Number
  • String
  • Boolean
  • null
  • undefined
  • Symbol (ES6 추가)

Reference type

  • Object
    • Array
    • Function
    • Date : 날짜
    • RegExp : 정규표현식
    • Map, WeakMap (ES6 추가)
    • Set, WeakSet (ES6 추가)

기본형과 참조형의 구분

일반적으로 기본형은 할당이나 연산시 복제되고 참조형은 참조된다고 한다. 하지만 엄밀히 말하면 둘 모두 복제되는 것으로, 기본형은 주솟값이 담긴 주솟값을 바로 복제하는 반면 참조형은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다는 차이가 있다.

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

1. 메모리와 데이터

컴퓨터는 모든 데이터를 0 또는 1로 바꿔 표현하는 메모리 조각 bit 를 사용하고 각 비트는 고유한 식별자(unique identifier)를 통해 위치를 확인할 수 있다. 하지만 비트 단위로 위치를 확인하면 매우 비효율적이므로 몇 개씩 묶어 하나의 단위로 만들어 표현할 수 있는 값도 늘어나면서 검색 시간을 줄이기 위해 byte가 생겨났다.

많은 비트를 한 단위로 묶으면 검색 시간도 줄이고 표현할 수 있는 데이터의 개수도 늘어나겠지만 동시에 낭비되는 비트가 발생한다. 이러한 낭비를 최소화하기 위해 C/C++, 자바 등의 정적 타입 언어는 데이터 타입별로 메모리 영역을 2 bytes, 4 bytes 등으로 나누어 정해놓았다.

반면 JavaScript의 경우 메모리 용량이 과거보다 월등히 커진 상황에서 등장하여 메모리 압박이 적었고 숫자의 경우 C에서 short, int, longlong 등으로 구분하는 것과 달리 JS에서는 8 bytes를 확보한다.

정리하자면 모든 데이터는 바이트 단위의 식별자 메모리 주솟값(memory address) 을 통해 서로 구분하고 연결할 수 있다.

2. 식별자와 변수

변수(variable)와 식별자(identifier)를 혼용해서 사용하는 경우가 많다.

대부분의 경우 문맥에 따라 정확히 무엇을 말하고자 하는지 유추할 수 있기 때문에 문제없지만 둘의 차이를 정확히 모른다면 혼란 스러울 수 있다.

  • 변수(variable) : "변할 수 있는 무언가"

    컴퓨터에서 변할 수 있는 무언가란 데이터를 의미하고 변수는 즉 데이터 자체를 말한다.

  • 식별자(identifier) : "사용하는 이름"

    어떤 데이터를 식별하는데 사용하는 이름, 즉 변수명을 의미한다.

변수 선언과 데이터 할당

1. 변수 선언

변수 선언에 관한 것은 Web/basic 에서 다루었다. 여기서는 방법이 아닌 동작 원리를 알아본다.

var a;

을 말로 풀어쓰면 변할 수 있는 데이터를 만든다. 이 데이터의 식별자는 a로 한다 가 된다. 변수란 변할 수 있는 데이터이니 선언할 때 undefined이더라도 나중에 다른 값으로 바꿔 줄 수가 있다.

결국 변수란 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이라고 생각할 수 있겠다.

2. 데이터 할당

위와 같이 변수를 선언해주면 메모리 영역에 다음과 같이 데이터가 저장될 것 이다.(간략히 표현)

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

여기서 다음과 같이 변수에 데이터를 할당해주면 어떻게 될까

var a; // 변수 a 선언
a = "abc"; // 변수 a에 데이터 할당

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

변수 선언과 할당을 위와 같이 두 문장으로 명령하든, 아래와 같이 한 문장으로 명령하든 JavaScript 엔진은 결국 같은 동작을 수행한다.

그리고 그 과정은 아마도 변수 선언에서와 같이 메모리 공간을 확보하고 이름을 a로 선언해준 후 그 값에 abc를 할당해주면 될 것 같다.

하지만 실제로는 값에 바로 문자열 abc를 저장하지는 않는다. 실제로는 데이터를 저장하기 위한 별도의 메모리 공간을 다시 확보해서 문자열 abc를 저장하고 그 주소를 변수 영역의 값:에 저장하는 식으로 이루어진다.

  • 변수 영역

    주소...100210031004...
    데이터이름: a
    값: @5004
  • 데이터 영역

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

데이터 영역을 분리하는 이유

JavaScript는 Number 데이터에 대해 8 bytes 의 공간을 확보한다고 하였다. 반변 String 에 대해서는 정해진 규격이 없다.

글자는 영어의 경우 1 byte, 한글의 경우 2 bytes 로 글자 하나당 용량도 다르고 길이가 얼마나 될지 알 수 없기 때문에 확보한 공간에서만 데이터 변환을 할 수 있다면 데이터가 클 경우 '확보된 공간을 변환된 데이터 크기에 맞게 늘리는 작업'이 선행돼야 할 것이다.

따라서 효율적으로 문자열 데이터의 변환을 처리하기 위해 데이터를 별도의 공간에 나누어 저장한다.

이번엔 문자열 abcdef를 추가해보자 컴퓨터는 abc가 저장된 공간에 abcdef를 할당하지 않고 새로운 공간에 abcdef라는 문자열을 새로 만들어 그 주소를 변수 공간에 연결한다.

  • 변수 영역

    주소...100210031004...
    데이터이름: a
    값: @5004
  • 데이터 영역

    주소...500350045005...
    데이터abcabcdef

이렇게 새로운 공간을 만들어주며 저장하면 비효율적으로 보일 수 있다 다음 예를 보자

500개의 변수 공간이 있고 모든 변수에 숫자 5를 할당해야 한다. 이 때는 데이터 할당이 어떤 식으로 이루어질까?

만약 각 변수마다 숫자 5데이터를 만들어서 할당하려고 하면 숫자형은 8 bytes가 필요하므로 총 500 * 8 = 4000 bytes가 필요할 것이다. 하지만 데이터를 하나의 영역에 저장해주고 각 변수에 그 데이터 영역의 주소를 입력한다면 500 * 2 + 8 = 1008 bytes 만 필요하게 된다. 이처럼 변수 영역과 데이터 영역을 분리하면 중복된 데이터에 대한 처리 효율이 높아진다.

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

1. 불변값

변수(variable)과 상수(constant)를 구분하는 성질은 '변경 가능성'이다. 이러한 개념 때문에 불변값과 상수를 같은 개념으로 오해하기 쉬운데, 변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이고, 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리이다.

기본형 데이터인 Number, String, Boolean, null, undefined, Symbol은 모두 불변값이다. 다음의 예를 보자

var a = "abc";
a = a + "def";

var b = 5;
var c = 5;
b = 7;

위의 데이터 영역을 분리하는 이유에서 봤듯 변수 a에 문자열 abc를 할당했다가 뒤에 def를 추가하면 기존의 abcabcdef로 바뀌는 것이 아니라 새로운 문자열 abcdef를 만들어 그 주소를 변수 a에 저장한다.

4번째 줄에서는 변수 b에 숫자 5를 할당한다. 그리고 그 아래에서 또 c에 숫자 5를 할당한다. 그럼 처음에 컴퓨터가 데이터 영역에서 데이터 공간을 만들어 5를 넣고 이후에 c에 할당할 때는 이미 만들어진 데이터 영역이 있으므로 그 주소를 재활용한다.

6번째 줄에서는 변수 b의 값을 다시 7로 변경하고자 한다. 그럼 저장된 데이터 57로 바꾸는 것이 아니라 새로운 데이터 영역을 생성하고 숫자 7을 저장하여 그 주소를 변수 b의 값으로 넣어준다.

이처럼 불변형 데이터는 그 데이터 값은 변경할 수 없다.

2. 가변값

기본형 데이터는 모두 불변값이다. 그렇다면 참조형 데이터는 모두 가변값일까?

그렇지 않다 기본적인 성질은 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우(Object.defineProperty, Object.freeze 등)도 있고 아예 불변값으로 활용하는 방안도 있다.

이번에는 가변값의 경우만 본다.

var obj1 = {
a: 1,
b: "bbb",
};
  • 변수 영역

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

    주소5001500250035004...
    데이터@7103 ~ ?1bbb
  • 객체 @5001의 변수 영역

    주소7103710471057106...
    데이터이름: a
    값: @5003
    이름: b
    값: @5004
  1. 컴퓨터는 우선 변수 영역의 빈 공간(@1002)을 확보하고, 그 주소의 이름을 obj1로 지정한다.

  2. 임의의 데이터 저장 공간(@5001)에 데이터를 저장하려고 보니 여러 개의 프로퍼티로 이뤄진 데이터 그룹이다. 이 그룹 내부의 프로퍼티들을 저장하기 위해 별도의 변수 영역을 마련하고, 그 영역의 주소(@7103 ~ ?)를 @5001에 저장한다.

    객체의 프로퍼티들을 저장하기 위한 메모리 영역은 크기가 정해져 있지 않고
    필요한 시점에 동적으로 확보한다.
  3. @7103 및 @7104에 각각 ab라는 프로퍼티 이름을 지정한다.

  4. 데이터 영역에서 숫자 1을 검색한다. 검색 결과가 없으므로 임의로 @5003에 저장하고, 이 주소를 @7103에 저장한다. 문자열 bbb 역시 임의로 @5004에 저장하고, 이 주소를 @7104에 저장한다.