코어 자바스크립트 - 데이터 타입

SangHun Han·2023년 4월 27일
0
post-thumbnail

데이터 타입



데이터 타입의 종류

자바스크립트의 데이터 타입은 크게 2가지로 나뉘어져 있어 하나는 기본형(Primitive type),
다른 하나는 참조형(Reference type)이다.

이 둘을 어떤 기준으로 구분할 수 있을까?

엄밀히 말해서 둘 다 모두 복제가 가능하며, 기본형(Primitive type)은 할당이나 연산시 복제가 되는데 값이 담긴 주솟값을 바로 복제하고 참조형(Reference type)은 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복제한다는 점이 차이점이라고 말할 수 있다.



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

메모리와 데이터

컴퓨터는 모든 데이터를 0과 1로 바꿔 기억하는데, 0 또는 1만 표현할 수 있는 하나의 메모리 조각을
비트(bit) 라고 하며, 메모리는 매우 많은 비트들로 구성되어 있고 각 비트는 고유한 식별자(Unique indentifier)를 통해 위치를 확인할 수 있다.

여기서 매우 많은 비트를 한 단위로 묶으면 검색 시간은 줄일 수 있으며, 표현할 수 있는 데이터의 개수가 늘어날 수 있지만 동시에 낭비되는 비트도 생긴다.

이러한 고민의 결과로 바이트(byte)라는 단위가 생기게 되는데, 1바이트는 8개의 비트로 구성되어
1비트 마다 0 또는 1의 두 가지 값을 표현할 수 있으므로 결국, 1바이트는 총 256(2^8)개의 값을 표현한다.

C/C++, 자바 등의 정적 타입 언어는 메모리의 낭비를 최소화하기 위해 데이터 타입별로 할당할 메모리 영역을 정해놓아야 하는데, 일정 이상의 큰 수를 입력하게 되면 정수형 타입(int)으로 형변환을 해야하는 번거로움이 있다.

하지만, 메모리 용량이 과거보다 월등히 커진 상황에서 등장한 자바스크립트는 상대적으로 메모리 관리에 대한 압박에서 자유로워졌기에 개발자가 앞서 말한 형변환을 걱정해야 하는 상황이 덜 발생하게 되었다.

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


식별자와 변수

  • 식별자 - 어떤 데이터를 식별하는 데 사용하는 이름, 즉 변수명이다.

  • 변수 - "변할 수 있는 수" 또는 "변할 수 있는 무언가"
    여기서 무언가는 데이터이며 데이터는 숫자, 문자열, 객체, 배열 등이 있다.



변수 선언과 데이터 할당

변수 선언

var a;

변수란 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이라고 정의할 수 있다.
위의 예시는 "변할 수 있는 데이터를 만들며, 이 데이터의 식별자는 a로 한다."로 설명할 수 있다.


<변수 선언에 대한 메모리 영역의 변화>


컴퓨터는 메모리에서 비어있는 공간 하나를 확보한다. (위의 그림에서는 임의로 1003번을 정함)
이 공간의 이름(식별자)을 a라고 지정하며, 여기까지가 변수 선언 과정이다.



데이터 할당

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

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

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

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

다시 말해서, 변수 영역에 저장된 주소 값에는 데이터를 새로 할당하지 않는다는 점이다.



var a = 'abc'
a = 'abcdef';

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

  • 데이터 영역의 빈 공간(5005번)에 문자열 'abcdef'를 저장한다.
  • 변수 a의 데이터를 찾고 해당 데이터 값을 5004에서 5005로 교체한다.


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

불변값

변수와 상수를 구분하는 성질 = "변경 가능성" (바꿀 수 있으면 변수, 없으면 상수)

변수와 상수를 구분 짓는 변경 가능성의 대상은 변수 영역 메모리이고, 불변성 여부를 구분할 때의 변경 가능성의 대상은 데이터 영역 메모리이다.


<불변성 예시>

var a = 'abc';
a = a + 'def';

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

문자열 값과 숫자 모두 다른 값으로 변경할 수 없으며, 여기서 변경은 새로 만드는 동작을 통해서만 이루어진다.



가변값

참조형 데이터에 대해서 기본적인 성질은 가변값인 경우가 많지만 설정에 따라 변경 불가능한 경우도 있고 아예 불변값으로 활용하는 방안도 있다.


<참조형 데이터의 할당 예시>

var obj1 = {
    a: 1,
    b: 'bbb'
};

기본형 데이터와의 차이는?
-> 객체의 변수인 프로퍼티 영역이 별도로 존재한다는 점이다.
데이터 영역에 저장된 값은 모두 불변값(숫자, 문자열)이지만 변수에는 다른 값을 얼마든지 대입할
수 있기 때문에 불변하지 않다. (= 가변적이다)


<참조형 데이터의 프로퍼티 재할당 예시>

var obj1 = {
    a: 1,
    b: 'bbb'
};
obj1.a = 2;

위 코드와 다른점으로는 obj1의 a 프로퍼티에 숫자 2를 할당한다는 점이고, 이러한 경우를
중첩 객체(Nested object) 라고 한다.


<중첩된 참조형 데이터(객체)의 프로퍼티 할당 예시>

var obj = {
    x: 3,
    arr: [3, 4, 5]
};

이 상태에서 아래의 코드를 추가하여 재할당을 하게되면 어떻게 될까?

obj.arr = 'str';

어떠한 데이터에 대해 자신의 주소값을 참조하는 변수의 개수를 참조 카운트라고 한다.

해당 결과에서는 참조 카운트가 1에서 0이 되므로, 참조 카운트가 0인 메모리 주소값은
가비지 컬렉터(Garbage Collector, GC)로 수거대상이 된다.

수거 대상이 된 가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모리 사용량이 포화 상태에 임박할 때마다 자동으로 수거 대상들을 수거하며, 수거된 메모리는 다시 빈 공간이 되어 새로운 값을 할당받을 수 있다.



변수 복사 비교


<변수 복사>

var a = 10;
var b = a;

var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;
  • 각각의 변수 영역의 빈 공간을 확보하고 a, b를 지정한다.
  • 둘은 각각의 공간을 가지고 같은 주솟값을 갖는다.
  • 참조형 데이터는 ob1, obj2에 해당하는 각각의 변수 영역의 빈 공간을 확보하고 데이터 영역의 묶음 주소는 같은 주솟값을 갖는다.

<변수 복사 이후 값 변경 결과 - 객체의 프로퍼티 변경시>

var a = 10;
var b = a;

var obj1 = { c: 10,d: 'ddd' };
var obj2 = obj1;

b = 15;
obj2.c = 20;
  • 다음과 같이 객체의 프로퍼티를 변경했을 때에는 다르게 동작한다.
  • 기본형 데이터를 복사한 변수는 b는 값이 달라져 서로 다른 주솟값을 가진다.
  • 반면 obj1과 obj2는 프로퍼티가 저장된 메모리의 값만 바뀌어 메모리 주솟값만 변경될 뿐
    ojb1과 obj2는 같은 주솟값
    을 가진다.

<변수 복사 이후 값 변경 결과 - 객체 자체 변경시>

var a = 10;
var b = a;

var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;

b = 15;
obj2 = { c: 20, d: 'ddd' }
  • 이와 같이 객체 자체를 변경했을 때에는 객체를 새롭게 만들었기 때문에 obj1 !== obj2가 성립한다.

참조형 데이터의 '가변값'이 언제를 의미할까?
'가변'은 참조형 데이터 자체를 변경했을 때가 아닌 내부의 프로퍼티를 변경했을 때만 성립 가능하다.



불변 객체

불변 객체를 만드는 간단한 방법

위에서 언급했듯이 참조형 데이터의 '가변'은 데이터 자체가 아닌 내부 프로퍼티를 변경할 때만 성립하는데, 이는 데이터 자체를 변경하고자 한다.
다시 말해서, 새로운 데이터를 할당하고자 하면 기본형 데이터와 마찬가지로 기존 데이터는 변하지 않는다.

그래서, 값으로 전달받은 객체에 변경을 가하더라도 원본 객체는 변하지 않아야 하는 경우에 불변객체가 필요하다.


얕은 복사와 깊은 복사

얕은 복사

  • 바로 아래 단계의 값만 복사하는 방법이다.
  • 중첩된 객체에서 참조형 데이터가 저장된 프로퍼티를 복사할 때, 그 주솟값만 복사한다는 의미

깊은 복사

  • 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사하는 방법이다.
  • 객체의 프로퍼티 중에서 그 값이 기본형 데이터일 경우는 그대로 복사되지만,
    참조형 데이터는 다시 그 내부의 프로퍼티를 복사
    해야한다.


undefined와 null

undefined - 어떤 변수에 값이 존재하지 않을 경우를 의미한다.

null - 사용자가 명시적으로 '없음'을 표현하기 위해 대입한 값이다.

profile
매일매일 성장하는 개발자 🚀

0개의 댓글