[JS] 06장 데이터 타입-모던 자바스크립트 Deep Dive

2024. 1. 9. 17:45개발/Deep Dive (JS) 정리

데이터 타입(data type)은 값의 종류를 말한다. 자바스크립트의 모든 값은 데이터 타입을 갖는데 자바스크립트 ES6는 7개의 데이터 타입을 제공한다.

구분 데이터 타입 설명
원시 타입 숫자(number) 타입 숫자. 정수와 실수 구분 없이 하나의 숫자 타입만 존재
문자열(string) 타입 문자열
불리언(boolean) 타입 논리적 참(true)과 거짓(false)
undefined 타입 var 키워드로 선언된 변수에 암묵적으로 할당되는 값
null 타입 값이 없다는 것을 의도적으로 명시할 때 사용하는 값
심벌(symbol)  타입 ES6에서 추가된 7번째 타입
객체 타입 객체, 함수, 배열 등

6.1 숫자 타입

자바스크립트는 다른 프로그래밍 언어(c, java, python 등)와는 다르게 하나의 숫자 타입만 존재한다. ECMAScript 사양에 따르면 숫자 타입의 값은 배정밀도 64비트 부동소수점 형식을 따른다. 즉, 모든 수를 실수로 처리하며, 정수만 표현하기 위한 데이터 타입이 별도로 존재하지 않는다. 정수, 실수, 2진수, 8진수, 16진수 모두 메모리에 배정밀도 64비트 부동소수점 형식의 2진수로 저장된다. 모두 출력 시 10진수로 해석된다.

//모두 숫자 타입이다.
var integer = 10; //정수
var double = 10.12; //실수
var negative = -20; //음의 정수

//2진수, 8진수, 16진수 모두 10진수로 해석
var binary = 0b01000001; //2진수
var octal = 0o101; //8진수
var hex = 0x41; //16진수

console.log(binary); // 65
console.log(octal); // 65
console.log(hex); // 65

그 외에 특별한 3가지 값도 존재하며 다음과 같이 표현된다.

  • Infinity : 양의 무한대
  • -Infinity : 음의 무한대
  • NaN : 산술 연산 불가(not-a-number)
//숫자 타입의 세 가지 특별한 값
console.log(10 / 0); //Infinity
console.log(10 / -0); //-Infinity
console.log(1 * 'String'); //NaN

6.2 문자열 타입

텍스트 데이터를 나타내는 데 사용하고 0개 이상의 16비트 유니코드 문자(UTF-16)의 집합으로 전 세계 대부분의 문자를 표현할 수 있다.

작은따옴표(''), 큰따옴표("") 또는 백틱(``)으로 텍스트를 감싸서 표현한다. 자바스크립트에서 가장 일반적인 표기법은 작은따옴표를 사용하는 것이다.

//문자열 타입
var string;
string = '문자열'; //작은따옴표
string = "문자열"; //큰따옴표
string = `문자열`; //백틱

//따옴표로 감싸지 않으면 식별자로 인식한다.
string = 문자열; //ReferenceError: 문자열 is not defined

6.3 템플릿 리터럴

템플릿 리터럴은 멀티라인 문자열, 표현식 삽입, 태그드 템플릿 등 편리한 문자열 처리 기능을 제공한다. 템플릿 리터럴은 백틱(``)을 사용해 표현한다.

6.3.1 멀티라인 문자열

일반 문자열 내에서는 줄바꿈(개행)이 허용되지 않는다. 따라서 일반 문자열 내에서 줄 바꿈 등의 공백을 표현하려면 백슬래시(\)로 시작하는 이스케이프 시퀀스를 사용해야 한다.

이스케이프 시퀀스 의미
\0 Null
\b 백스페이스
\f 폼 피드: 프린터로 출력할 경우 다음 페이지의 시작 지점으로 이동한다.
\n 개행: 다음 행으로 이동
\r 개행: 커서를 처음으로 이동
\t 탭(수평)
\v 탭(수직)
\uXXXX 유니코드 ex)'\u0041'은 'A', '\uD55C'는 '한'
\' 작은따옴표
\" 큰따옴표
\\ 백슬래시

위의 표에서 가장 많이 사용하는 \n은 꼭 기억하도록 하자.

이스케이프 시퀀스를 사용하지 않더라도 줄 바꿈이 허용되고 모든 공백도 있는 그대로 적용된다.

var template = `<div>
	<span>안녕하세요</span>!
</div>;
`
console.log(template);


//출력 결과
<div>
	<span>안녕하세요</span>!
</div>;

6.3.2 표현식 삽입

문자열은 문자열 연산자 + 를 사용해 연결할 수 있다.

var firstName = 'Min-joon';
var lastName = 'Choi';

//ES5: 문자열 연결
console.log('My name is' + firstName + ' ' + lastName + '.');
//My name is Min-joon Choi.

템플릿 리터럴 내에서는 표현식 삽입을 통해 간단히 문자열을 삽입할 수 있고, 이를 통해 문자열 연산자보다 가독성 좋고 간편하게 문자열을 조합할 수 있다.

var firstName = 'Min-joon';
var lastName = 'Choi';

//ES6: 표현식 삽입
console.log(`My name is ${firstName} ${lastName}.`);
//My name is Min-joon Choi.

표현식 삽입 시 ${ }로 표현식을 감싼다. 반드시 백틱(``)으로 감쌌는지 확인하고 사용해야 한다.


6.4 불리언 타입

불리언 타입의 값은 논리적 참과 거짓을 나타내는 true와 false 뿐이다.

var foo = true;
console.log(foo); // true

foo = false;
console.log(foo); // false

6.5 undefined 타입

undefined 타입의 값은 undefined가 유일하다. var 키워드로 선언한 변수는 암묵적으로 undefined로 초기화된다. 메모리 관점에서 이야기하면 변수 선언에 의해 확보된 메모리 공간을 처음 할당이 이뤄질 때까지 빈 상태(대부분 비어 있지 않고 쓰레기 값이 들어 있다)로 놔두지 않고 자바스크립트 엔진이 undefined로 초기화한다.

var foo;
console.log(foo); // undefined

undefined는 개발자의 의도적으로 할당하는 것이 아니라 자바스크립트 엔진이 변수를 초기화하는 데 사용하는 것이기 때문에 undefined를 할당하는 것은 혼란을 야기하기 때문에 권장하지 않는다.

변수에 "값이 없다" 또는 "비어있다"라는 것을 명시하고 싶을 때는 다음에 설명할 null을 할당한다.


6.6 null 타입

null 타입은 값은 null이 유일하다. 직전에 설명한 것처럼 null은 개발자가 의도적으로 변수에 값이 없다는 것을 명시할 때 사용한다. 변수에 null을 할당하는 것은 변수가 이전에 참조하던 값을 더 이상 참조하지 않겠다는 뜻이고, 자바스크립트 엔진은 이 참조하지 않는 메모리 공간에 대해 가비지 콜렉션을 수행한다.

사용하지 않는 변수는 변수의 스코프(범위)를 좁게 만들기 위해 변수 자체를 소멸시키는 편이 낫다.


6.7 심벌 타입

심벌(symbol)은 변경 불가능한 원시 타입의 값이다. 심벌 값은 다른 값과 중복되지 않는 유일무이한 값이다. 따라서 주로 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다.

//심벌 값 생성
var key = Symbol('key');
console.log(typeof key); // symbol

//객체 생성
var obj = {};

//이름이 충돌할 위험이 없는 유일무이한 값인 심벌을 프로퍼티 키로 사용한다.
obj[key] = 'value';
console.log(obj[key]); //value

자세한 내용은 추후에 작성할 33장 내용에 Symbol에 관하여 자세히 다룰 예정이다.


6.8 객체 타입

자바스크립트는 객체 기반 언어로 자바스크립트를 이루고 있는 거의 모든 것이 객체이다. 위에 설명한 6가지 데이터 타입 이외의 값은 모두 객체 타입이다.


6.9 데이터 타입의 필요성

6.9.1 데이터 타입에 의한 메모리 공간의 확보와 참조

값은 메모리에 저장하고 참조할 수 있어야 하기 때문에 값을 저장하려면 먼저 확보해야 할 메모리 공간의 크기를 결정해야 한다. 이를 통해 가장 효율적으로 메모리 공간을 활용할 수 있기 때문이다.

ECMAScript 사양은 문자열과 숫자 타입 외의 데이터 타입의 크기를 명시적으로 규정하고 있지는 않다. 따라서 문자열과 숫자 타입을 제외하고 데이터 타입에 따라 확보되는 메모리 공간의 크기는 자바스크립트 엔진 제조사의 구현에 따라 다를 수 있다. 단, ECMAScript 사양에 숫자 타입은 배정밀도 64비트 부동소수점 형식을 사용한다고 명시되어 있고, 배정밀도 64비트 부동소수점 형식은 8비트로 숫자를 표현하므로 숫자 값의 크기를 8바이트로 설명한다. 숫자는 2진수로 저장된다.

값을 참조할 때는 한 번에 읽어 들여야 할 메모리 공간의 크기, 즉 메모리 셀의 개수(바이트 수)를 알아야 한다. 숫자 타입의 경우 8바이트 단위로 읽어 들이지 않으면 값이 훼손된다. 

6.9.2 데이터 타입에 의한 값의 해석

숫자 타입은 2진수로 저장된다고 했다. 여기서 메모리에서 읽어 들인 2진수를 어떻게 해석하는지에 따라 다르게 해석될 수 있다는 문제점이 있다.

모든 값은 데이터 타입을 가지며, 메모리에 2진수, 즉 비트의 나열로 저장된다. 메모리에 저장된 값은 데이터 타입에 따라 다르게 해석되는데 0100 0001은 숫자로 해석하면 65지만 문자열로 해석하면 'A'다.

이러한 문제를 해결하기 위해 데이터 타입을 사용한다. 정리하면 아래와 같다.

  • 값을 저장할 때 확보해야 하는 메모리 공간의 크기를 결정하기 위해 사용
  • 값을 참조할 때 한 번에 읽어 들여야 할 메모리 공간의 크기를 결정하기 위해 사용
  • 메모리에서 읽어 들인 2진수를 어떻게 해석할지 결정하기 위해 사용

6.10 동적 타이핑

6.10.1 동적 타입 언어와 정적 타입 언어

정적 타입 언어(static/strong type)는 C나 Java 같은 언어로 변수를 선언할 때 변수에 할당할 수 있는 값의 종류, 즉 데이터 타입을 사전에 선언해야 한다. 즉, 변수의 타입을 변경할 수 없으며 변수에 선언한 타입에 맞는 값만 할당할 수 있다. 이를 명시적 타입 선언이라 한다.

정적 타입 언어는 컴파일 시점에 타입체크(선언한 데이터 타입에 맞는 값을 할당했는지 검사하는 처리)를 수행하는데 이를 통과하지 못하면 에러를 발생시키고 프로그램의 실행 자체를 막는다. 이를 통해 타입의 일관성을 강제함으로써 안정적인 코드 구현을 통해 에러를 줄인다.

동적 타입 언어(dynamic/weak type)는 javascript나 python 같은 언어로 변수는 선언이 아닌 할당에 의해 타입이 결정(타입 추론)되고 재할당에 의해 변수의 타입은 언제든지 동적으로 변할 수 있다. 이러한 특징을 동적 타이핑이라 한다. 자바스크립트는 var, let, const 키워드를 사용해 변수를 선언하고 어떠한 데이터 타입의 값이라도 자유롭게 할당할 수 있다.

6.10.2 동적 타입 언어와 변수

동적 타입 언어는 데이터 타입에 상관 없이 변수를 지정할 수 있기 때문에 편리하지만 구조적인 단점을 갖고 있다. 변수값이 언제든지 변경될 수 있기 때문에 변화하는 변수 값을 추적하기 어려울 수 있다. 또한 변수의 타입이 고정되어 있지 않고 동적으로 변하는 동적 타입 언어의 변수는 값의 변경에 의해 타입도 언제든지 변경될 수 있으므로 타입에 대한 신뢰도가 떨어진다.

심지어 자바스크립트는 개발자의 의도와는 상관없이 자바스크립트 엔진에 의해 암묵적으로 타입이 자동으로 변환되기도 한다. 이처럼 동적 타입 언더는 유연성은 높지만 신뢰성은 떨어진다.

이러한 이유로 안정적인 프로그램을 만들기 위해 변수를 사용할 때 주의 사항은 다음과 같다.

  • 변수는 꼭 필요한 경우에 한해 제한적으로 사용한다.
  • 변수의 유효 범위(스코프)는 최대한 좁게 만들어 변수의 부작용을 억제해야 한다.
  • 전역 변수는 최대한 사용하지 않도록 한다.
  • 변수보다는 상수를 사용해 값의 변경을 억제한다. (const)
  • 변수 이름은 변수의 목적이나 의미를 파악할 수 있도록 네이밍한다.