[JavaScript] 데이터 타입의 종류

빵호·2021년 10월 7일
0

JavaScript

목록 보기
14/28
post-thumbnail

데이터 타입의 종류

자바스크립트의 데이터 타입에는 크게 두 가지가 있다.

1. 원시형(primitive type)

1. 숫자(number)
2. 문자열(string)
3. 불리언(boolean)
4. null
5. undefined
6. 심볼(symbol)
  • 할당이나 연산시 복제됨
  • 값이 담긴 주소값을 복제함
  • 불변성(immutability)을 띰

2. 참조형(reference type)

1. 객체(Object)
2. 배열(Array)
3. 함수(Funtion)
4. 날짜(Date)
5. 정규표현식(RegExp)
6. Map, WeakMap, Set, WeakSet...
  • 할당이나 연산지 참조됨
  • 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제함

배경지식

메모리와 데이터

컴퓨터는 모든 데이터를 0 또는 1로 바꿔 기억하고 0 또는 1만 표현할 수있는 하나의 메모리 조각을 비트(bit)라고 한다. 메모리는 매우 많은 비트들로 구성돼 있고 각 비트는 고유한 식별자(unique identifer)를 통해 위치를 확인할 수 있다. 하지만 비트 단위로 위치를 확인하는 것은 매우 비효율적이다. 그래서 표현할 수 있는 데이터 개수도 늘고 검색 시간이 줄어든 바이트(8개의 비트로 구성됨)가 탄생했고 모든 데이터는 바이트 단위의 메모리 주소값(memory address)을 통해 서로 구분하고 연결할 수 있다.

식별자와 변수

  • 변수(variable)는 '변할 수 있는 데이터'이다.
  • 식별자(idntifier)는 데이터를 식별하는 데 사용하는 이름, 즉 변수명이다.

변수 선언과 데이터 할당

변수 선언

var a;
// 메모리에 식별자 a를 검색 후 없으면 메모리의 빈 공간을 확보하여 그 공간의 식별자를 a로 지정

변수란 변경 가능한 데이터가 담길 수 있는 공간 또는 그릇이다. 위의 명령어가 실행되면 메모리에 비어있는 공간을 찾아 식별자를 a라고 지정하는 데 이것을 변수 선언이라고 한다. 이후에 a에 사용자가 접근하려고 하면 a라는 이름을 가진 주소를 검색해 해당 공간에 담긴 데이터를 반환한다.

데이터 할당

var a = 'abc';
// 메모리에 'abc' 저장 후 그 주소값을 식별자 a의 데이터에 연결

할당의 경우 a라는 이름을 가진 주소를 검색해서 그곳에 문자열 'abc'를 할당할것 같지만 그렇지 않다. 데이터를 할당할 때는 별도의 메모리 공간을 확보해 문자열 'abc'를 저장하고, 그 주소를 변수 영역에 저장한다. 이렇게 한 단계를 더 거치는 이유는 데이터 변환을 자유롭게 하고 메모리를 효율적으로 관리하기 위해서이다. 미리 확보한 공간 내에서만 데이터 변환이 가능하면 더 큰 데이터가 들어왔을때 해당 데이터 크기에 맞춰 공간을 늘려야 하고 이때 데이터가 메모리 중간에 있으면 뒤에 저장된 데이터를 전부 옮기고 옮겨진 주소를 식별자에 다시 연결해야 해서 매우 비효율 적이기 때문이다.

a = 'abcdef'; 
// 메모리에 'adcdef' 저장 후 그 주소값을 식별자 a의 데이터에 연결
var b = 1;
// 메모리에 1 저장 후 그 주소값을 식별자 b의 데이터에 연결
var c = 1;
// b에서 사용된 1의 주소값을 식별자 c에 연결

변수에 새로운 데이터를 할당할 때도 기존 데이터가 저장된 공간에 새로운 데이터를 할당하는 게 아닌 새로운 데이터 저장 공간에 새로운 데이터를 저장해 그 주소를 식별자에 연결한다. 하지만 하나의 데이터를 여러 변수에 할당할 때는 하나의 공간에 데이터를 한 번만 할당하고 해당 주소값을 재활용한다.

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

  • 변수(variable)와 상수(constant)를 구분하는 성질은 '변수 영역 메모리의 변경 가능성'이다.
  • 불변성 여부를 구분하는 성질은 '데이터 영역 메모리의 변경 가능성'이다.

불변값

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

기본형 데이터는 모두 불변값이다. 위와 같은 명령어가 실행되었을 때 'abc'에 'def'를 추가했다고 기존 'abc'가 'abcdef'로 바뀌는 게 아니라 새로운 문자열 데이터를 만들고 그 주소를 변수 a에 저장한다. 이처럼 한번 만든 값은 바꿀 수 없고 가비지 컬렉팅을 당하지 않는 한 영원히 변하지 않는다.

가변값

var obj = {
  a: 1,
  b: 'b'
};

obj.a = 2; // 객체의 주소값이 바뀌는게 아니라 변수 a의 주소값이 바뀜

참조형 데이터는 기본적인 성질은 가변 값인 경우가 많지만 설정에 따라 불변값으로 활용하는 방안도 있다. 참조형은 객체의 변수 영역이 별도로 존재하고 데이터 영역은 기존의 메모리 공간을 활용한다. 데이터 영역에 저장된 값은 불변값이지만 변수에 다른 값을 대입할 수 있어 가변값이라고 하는 것이다.

변수 복사 비교

//기본형
var a = 10;
var b = a;

//참조형
var obj = { c: 10, d: 'ddd' };
var obj2 = obj;

기본형 데이터

변수 영역의 빈 공간을 확보 후 식별자를 a로 지정한다. 이후 숫자 10을 데이터 영역에서 검색 후 없으면 빈 공간에 데이터 10을 저장 후 데이터의 주소값을 변수의 데이터에 넣는다. 그리고 복사를 위해 변수 영역의 빈 공간을 찾아 식별자를 b로 지정 후 식별자 a를 검색해 10이 들어있는 데이터 주소를 b의 변수영역 데이터에 넣는다.

참조형 데이터

변수 영역의 빈 공간들을 확보 후 식별자를 obj, c, d로 지정한다. 이후 데이터 영역에서 객체의 데이터와 객체안의 변수의 데이터가 저장될 공간을 확보 후 객체에는 변수의 주소값을 변수에는 데이터의 주소값을 대입한다. c에 대입할 10은 데이터의 영역에 존재하므로 해당 주소값을 대입한다. 이후 복사하는 과정은 기본형 데이터와 똑같이 변수 영역에 빈 공간을 확보 후 식별자를 obj2로 지정하고 식별자 obj를 검색해 그 안의 값을 대입한다.

변수 복사 이후 값 변경

//기본형
var a = 10;
var b = a;

b = 15;

//참조형
var obj = { c: 10, d: 'ddd' };
var obj2 = obj;

obj.c = 20;

기본형

데이터 영역에 15가 없으므로 새로운 공간을 확보 후 저장하고 변수 영역에서 식별자가 b인 주소를 찾아 값을 15의 주소값으로 바꾼다.

참조형

데이터 영역에 20이 없으므로 새로운 공간을 확보 후 저장한다. 이후 변수의 영역에서 obj2를 찾고 값이 담긴 주소를 찾고 값에 담긴 변수의 영역에서 식별자 c를 찾아 그곳에 20이 담긴 주소값을 대입한다.

결론

기본형 데이터는 변수를 복사 후 복사한 변수의 값을 바꾸면 둘은 서로 다른 주소를 바라보기 떄문에 복사한 변수의 값만 바뀌고 원본의 값은 바뀌지 않는다 하지만 참조형 데이터는 계속 같은 객체를 바로보기 때문에 복사한 변수의 값을 바꾸면 원본의 값도 바뀌게 된다.

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

obj2 = { c: 20, d: 'ddd'};

하지만 위와 같이 obj2에 새로운 객체를 할당하게 되면 값을 직접 변경하게 되어 데이터 영역의 새로운 공간에 객체가 저장되고 그 주소가 변수 obj2의 값에 저장되어 객체의 대한 변경임에도 ojb obj2의 값이 달라지게 된다. 참조형 데이터는 기본적으로는 가변값이지만 위처럼 불변값으로 바뀔수도 있다.

불변 객체

불변 객체(immutable object)는 최근의 React, Veu.js 등의 라이브러리나 프레임워크, 함수형 프로그래밍 등에서 매우 중요한 기초 개념이다. 참조형 데이터의 '가변성'은 프로퍼티를 변경할 떄만 성립하지만 데이터 자체를 바꾸면 기본형 데이터와 마찬가지로 '불변성'이 성립한다.

얕은 복사

const obj = { 1: 'a' }
const newObj = obj;

newObj.1 = 'b';

console.log(obj.1); // 'b'
console.log(obj === newObj); // true

얕은 복사(shallow copy)는 바로 아래 단계의 값만 복사하는 방법이다. 참조형 데이터가 저장된 프로퍼티를 복사할 때 주소값만 복사하기 떄문에 원본과 사본이 모두 동일한 참조형 데이터를 가르켜 사본을 바꾸면 원본도 바뀌고 원본을 바꾸면 사본도 바뀌게 됨

깊은 복사

깊은 복사(deep copy)는 내부의 모든 값들을 하나하나 찾아서 전부 복사하는 방법이다. 어떤 객체를 복사할 때 객체 내부의 모든 값을 복사해서 완전히 새로운 데이터를 만들기 떄문에 어느 쪽의 프로퍼티를 변경하더라도 다른 쪽에 영향을 주지 않는다.

undefined와 null

자바스크립트에는 '없음'을 나타내는 값이 두 가지 있다. undefined와 null이다. 의미는 같은 것 같지만 미세하게 다르고, 사용 목적 또한 다르다.

undefined

  1. 값을 대입하지 않은 변수
  2. 객체 내부의 존재하지 않는 프로퍼티에 접근하려고 할 떄
  3. return 문이 없거나 호출되지 않는 함수의 실행 결과

undefined는 사용자가 명시적으로 지정할 수도 있지만 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여하는 경우도 있다.

명시적으로 부여한 경우

그 자체로 값이다. 비어있음을 의미하지만 하나의 값으로 동작하고 프로퍼퍼티나 배열의 요소는 고유한 키값(프로퍼티 이름)이 실존하고 순화의 대상이 된다.

값이 존재하지 않는 경우

자바스크립트 엔진이 반환해주는 undefinde는 해당 프로퍼티나 배열의 키값(인덱스) 자체가 존재하지 않음을 의미한다.

arr = []
arr.length = 3
console.log(arr) // [empty x 3]

하지만 빈 배열의 경우 비어있는 요소가 들어있다. 비어있는 요소는 undefined와 출력 결과부터 다르고 순회 관련 배열 메서드(map, filter, forEach ...)에서 순회 대상에서 제외 된다. 배열도 객체이기 떄문에 존재하지 않는 프로퍼티에 순회할 없기 떄문이다. 배열은 length의 프로퍼티 개수만큼 빈 공간을 확보하는게 아닌 특정 인덱스에 값을 지정할 때 빈 공간을 확보하고 인덱스 이름, 데이터 주소값을 저장한다.

null

var n - null;
console.log(typeof n); // object

console.log(n == undefined) // true
console.log(n == null) // true
  
console.log(n === undefined) // false
console.log(n === null) // true

사용자가 명시적으로 비어있음을 나타내기 위해 undefined를 지정할 수 있지만 자바스크립트 엔진이 반환해주는 undefined와 혼란이 생길 수 있으므로 비어있음을 명시적으로 나타내고 싶을 때는 null을 쓰도록 하자. 주의할 점은 null의 타입이 object라는 점이다. 따라서 변수의 값이 null인지 확인할때는 typeof 대신 다른 방식으로 접근해야 한다.

profile
늘 한결같이 꾸준히

0개의 댓글