Data-type | 데이터 타입

타입이란 자바스크립트 엔진, 개발자 모두에게 어떤 값을 다른 값과 분별할 수 있는 고유한 내부 특성의 집합이다.

내장 타입

자바스크립트에는 7가지 내장 타입이 있다.

null, undefined, boolean, number, string, object, symbol

값의 타입은 typeof 연산자로 알 수 있다.

하지만 7가지의 내장 타입과 1대1로 정확히 매치되지는 않는다.

typeof undefined === "undefined"; // true
typeof true = "boolean"; // true
typeof 42 === "number"; // true
typeof "42" === "string"; // true
typeof { life: 42 } === "object"; // true
typeof Symbol() === "symbol"; // true

하지만 null에 대한 typeof 연산 결과는 버그처럼 보이기도 한다.

typeof null === "object"; // true

그래서 타입으로 null 값을 정확히 확인하려면 조건이 하나 더 필요하다.

var a = null;
!a && typeof a === "object"; // true

null은 falsy한 유일한 원시 값이지만 타입은 object인 특별한 존재다

typeof가 반환하는 문자열은 하나 더 있다.

typeof function a() {} === "function"; // true

typeof 반환 값을 보면 마치 function이 최상위 레벨의 내장 타입처럼 보이지만 명세를 읽어보면 실제로는 object의 하위 타입이다.

구체적으로 설명하면 함수는 호출 가능한 객체라고 명시되어 있다.

사실 함수는 객체라서 유용하다. 무엇보다 함수에 프로퍼티를 둘 수 있따.

function a(b, c) {}

함수에 선언된 인자 개수는 함수 객체의 length 프로퍼티로 알 수 있다.

a.length; // 2

배열 또한 객체다

typeof [1, 2, 3] === "object"; // true

배열은 숫자 인덱스를 가지며 length 프로퍼티가 자동으로 관리되는 등의 추가 특성을 지닌 객체의 하위 타입이라 할 수 있다.

값은 타입을 가진다

값에는 타입이 있지만 변수에는 따로 타입이 존재하지 않는다.

자바스크립트는 타입 강제를 하지 않는다. 변수값은 처음에 할당된 값과 동일한 타입일 필요는 없다.

변수에 typeof 연산자를 하는 것은 변수의 타입이 무엇이냐 보다는 타입이란 개념에는 변수가 없으므로 이 변수에 들어있는 값의 타입이 무엇이니와 같다.

var a = 42;
typeof a; // number
a = true;
typeof a; // boolean

typeof 연산자의 반환 값은 언제나 문자열이다.

typeof typeof 42; // string

값이 없는 vs 선언되지 않는

값이 없는 변수의 값은 undefined이며 typeof의 결과 값은 "undefined"이다.

값이 없는 undefined 와 선언되지 않은 "undefined"를 동의어처럼 생각할 수 있으나 자바스크립트에서 둘은 완전히 다른 개념이다.

undefined는 접근 가능한 스코프에 변수가 선언되었으나 현재 아무런 값도 할당되지 않은 상태를 가리키는 반면

"undefined"는 접근 가능한 스코프에 변수 자체가 선언조차 되지 않은 상태를 의미한다.

선언되지 않은 변수의 typeof 연산 결과는 헷갈린다.

var a;
typeof a; // "undefined"
typeof b; // "undefined"

선언되지 않는 변수도 typeof하면 undefined로 나온다.

b는 선언조차 하지 않은 변수인데 typeof b를 해도 브라우저는 오류 처리를 하지 않는다.

바로 이것이 typeof만의 독특한 안전 가드이다.

선언되지 않은 변수

브라우저에서 자바스크립트 코드를 처리할 때 특히 여러 스크립트 파일의 변수들이 전역 네임스페이스를 공유할때 typeof 안전 가드가 쓸모가 있다.

예를 들어 DEBUG라는 전역 변수로 프로그램의 모드를 조정한다면 작업을 수행하기 전에 이 변수의 선언 여부를 체크해야 한다.

// 이렇게 하면 에러가 난다.
if (DEBUG) {
console.log("디버깅을 시작합니다.");
}
// 이렇게 해야 안전하게 존재 여부를 체크할 수 있다.
if (typeof DEBUG !== "undefined") {
console.log("디버깅을 시작합니다.");
}

임의로 정의한 변수를 쓰지 않더라고 이런 식을 체크하는 것이 편리하며 내장 API 기능을 체크할 때에도 에러가 나지 않게 도와준다.

if (typeof atob === "undefined") {
atob = function() {};
}

typeof 안전 가드 없이 전역 변수를 체크하는 다른 방법은 전역 변수가 모두 전역 객체의 프로퍼티라는 점을 이용하는 것이다.

if (window.DEBUG) {
}

선언되지 않은 변수 떄와는 달리 어떤 객체의 프로퍼티를 접근할 때 그 프로퍼티가 존재하지 않아도 ReferenceError가 발생하지 않는다.

하지만 window 객체를 통한 전역 변수 참조는 가급적 삼가하는 것이 좋다.

전역 변수를 꼭 window 객체로만 호출하지 않는 다중 자바스크립트 환경이라면 더욱 그렇다.

typeof 안전 가드는 전역 변수를 사용하지 않을 떄에도 유용하다.

다른 개발자가 작성한 유틸리티 함수를 자신의 모듈에 카피 앤 페이스트하여 사용하는데 가져다 쓰는 프로그렘에 유틸리티의 특정 변수값이 정의되어 있는지 체크해야 할때 사용한다.

function doSomethingCool() {
var helper = typeof FeatureXYZ !== "undefined" ? FeatureXYZ : function() {};
var val = helper();
}

doSomethingCool 함수는 FeatureXYZ 변수가 있으면 그대로 사용하고 없으면 바디 함수를 정의한단.

이렇게 해야 다른 사람이 카피앤 페이스트를 해도 안전하게 FeatureXYZ가 존재하는지를 체크할 수 있다.

아니면 의존성 주입 설계 패턴 처럼 FeatureXZY가 doSomethingCool의 바깥이나 언저리에 정의되었는디 암시적으로조사하는 대신 다음 코드처럼 명시적으로 의존 관계를 전달하는 것이다.

function doSomethingCool(FeatureXYZ) {
var helper = FeatureXYZ || function() {};
var val = helper();
}

다양한 설계 옵션이 가능하지만 접근 방식에 따라 장단점이 고루 있어서 어떤 것이 완전히 맞다라고 할 수 없다.

하지만 대체로 typeof 안전 가드가 선택할 수 있는 옵션이 많아서 좋다.

정리하기

자바스크립트는 7가지 내장 타입 null, undefined, boolean, number, string, object,symbol이 있으며 typeof 연산자로 타입명을 알아낸다.

변수는 타입이 없지만 값은 타입이 있고 타입은 값의 내재된 특성을 정의한다.

undefined는 선언된 변수에 할당할 수 있는 값이지만 undeclared는 변수 자체가 선언된 적이 없음을 나타낸다.

불행하게 자바스크립트는 이 두 용어를 섞어버려서 에러 메세지 뿐만 아니라 typeof 반환 값도 모두 undefined로 나타난다.

하지만 typeof 안전 가드 덕분에 선언되지 않은 변수에 사용하면 확인이 가능하다.