YOU DON'T KNOW JS : Chapter1. Types
자바스크립트 스터디를 진행, 번역이라 좀 어색할 수 있음 (원본 : https://github.com/getify/You-Dont-Know-JS)
Built-in Types
자바스크립트에서는 7가지 내장형 타입이 존재한다.
- null
- undefined
- boolean
- number
- string
- object
- symbol (ES6에서 추가, Chapter3에서 다룰 예정)
object를 제외하고 모두 원시타입(primitives)로 불림
typeof 연산자는 주어진 값의 타입을 검사하고 7개의 type중 하나를 항상 반환하지만 1:1로 정확하게 매칭되지 않는다.
null을 제외한 아래 6개는 정확하게 매칭된다.
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은 버그처럼 보일 수 있지만 아래와 같이 object를 반환한다.
typeof null === "object"; // true
null로 반환되면 좋겠지만, 자바스크립트에서 이 버그는 20년 가까이 지속되고 있고 아마 고치지 않을 것이다.
이미 너무 많은 웹 컨텐츠가 이 buggy한 동작에 의존하고 있고, 이 버그를 고치면 더 많은 버그를 만들어내어 웹 사이트가 멈출 것이기 때문이다.
만약 null값을 type을 이용하여 검증하고 싶다면 복합적인 조건을 사용해야 한다.
var a = null;
(!a && typeof a === "object"); // true
null은 false 값을 가지고 typeof 체크시 object를 반환하는 유일한 원시적인 값이다.
typeof가 반환하는 문자열이 하나 더 있다.
typeof function a(){ /* .. */ } === "function"; // true
위의 결과를 보면 function이 자바스크립트에 내장된 타입이라고 생각할 수 있지만, Spec을 읽어보면 object의 subtype임을 알 수 있다.
특이하게 함수는 호출가능한 객체로 취급되고 이 객체는 내부에 [[call]]이라는 불러올 수 있는 내부 속성을 갖고있다.
함수는 꽤 유용한 객체이며, 중요한 점은 속성을 가질 수 있다.
이 함수 객체는 length라는 속성을 갖는데, 매개변수의 개수를 의미한다. (a.length = 2)
function a(b,c) {
/* .. */
}
typeof [1,2,3] === "object"; // true
Values of Types
자바스크립트에서는 변수들은 타입을 가지지 않고 값이 타입을 가진다.
자바스크립트는 type enforcement(형 강제화)가 없다. 선언되었을 당시에 string 값을 가질수도 있고 number 값을 가질수도 있다.
따라서 typeof 연산자를 이용하는 것은 '변수의 타입이 무엇인가?'를 묻는게 아니라 '변수의 값이 가지는 타입은 무엇인가?'이다.
var a = 42;
typeof a; // "number"
a = true;
typeof a; // "boolean"
typeof 연산자는 항상 문자열을 반환한다.
typeof typeof 42; // "string"
처음에 typeof 42에서 "number"를 반환하고 "number"는 "string"으로 반환된다.
undefined vs undeclared
값이 없는 변수는 undefined 타입을 가진다. typeof 연산자를 적용했을때 undefined를 반환한다.
var a;
typeof a; // "undefined"
var b = 42;
var c;
// later
b = c;
typeof b; // "undefined"
typeof c; // "undefined"
이는 많은 개발자들에게 undefined와 undeclared가 동의어라는 생각을 유도하지만, 자바스크립트에서 두 컨셉은 완전히 다르다.
undefined 변수는 접근가능한 스코프에서 선언되었으나 당시에 값을 가지고 있지 않은 변수를 의미하고, 반대로 undeclared 변수는 접근 가능한 스코프에서 선언된적이 없는 변수를 의미한다.
var a;
a; // undefined
b; // Uncaughed ReferenceError: b is not defined
typeof 연산자는 이 부분을 더 혼란스럽게 만들 수 있다.
주의할 점은 typeof b;를 실행해도 오류가 발생되지 않는다는 점이다.
이것은 typeof 연산자의 특별한 안전 가드다.
위처럼 만약 선언되지 않은 변수에 typeof 연산자를 사용했을 때, undeclared를 반환했다면 좀 더 나이스했을 것이다.
var a;
typeof a; // "undefined"
typeof b; // "undefined"
typeof Undeclared
여러 스크립트 파일의 변수들이 전역 네임스페이스를 공유할 때, typeof 안전 가드는 유용하다.
프로그램에 DEBUG라는 전역 변수(플래그)로 제어되는 "디버그 모드"가 있다고 가정해보자.
콘솔에 메시지를 로깅하는 것과 같은 디버그 작업을 수행하기 전에 해당 변수가 선언되었는지 확인하고 싶을 수 있다.
최상위 전역 var DEBUG = true
선언은 "debug.js"파일에만 포함되고 개발/테스트 중일 때만 브라우저에 로드되어야 한다.
그러나 ReferenceError를 발생시키지 않도록 나머지 응용 프로그램 코드에서 전역 DEBUG 변수를 확인하는 방법에 주의해야한다.
이 경우 typeof가 유용한 안전 가드가 되어준다.
// oops, this would throw an error!
if (DEBUG) {
console.log( "Debugging is starting" );
}
// this is a safe existence check
if (typeof DEBUG !== "undefined") {
console.log( "Debugging is starting" );
}
typeof의 안전가드 없이 전역 변수를 검사하는 다른 방법은 전역 변수들이 기본적으로 window 객체의 속성이라는것을 이용하는 것이다.
if (window.DEBUG) {
// ..
}
if (!window.atob) {
// ..
}
선언되지 않은 변수를 참조하는 것과 달리 존재하지 않는 객체 속성 (전역 window 객체에 있더라도)에 접근해도 ReferenceError가 발생하지 않는다.
그러나 window 객체를 통한 전역변수 참조는 사용하지 않는 것이 좋다.
doSomethingCool ()은 FeatureXYZ라는 변수를 테스트하고, 발견되면 해당 변수를 사용하지만 그렇지 않은 경우 자체 변수를 사용한다.
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
이제 누군가 이 유틸리티를 그들의 모듈/프로그램에 포함하여 FeatureXYZ를 정의했는지 여부를 안전하게 확인한다고 가정해보자.
// an IIFE (see "Immediately Invoked Function Expressions"
// discussion in the *Scope & Closures* title of this series)
(function(){
function FeatureXYZ() { /*.. my XYZ feature ..*/ }
// include `doSomethingCool(..)`
function doSomethingCool() {
var helper =
(typeof FeatureXYZ !== "undefined") ?
FeatureXYZ :
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
doSomethingCool();
})();
여기서 FeatureXYZ는 전역 변수가 아니지만 확인을 위해 typeof의 안전 가드를 계속 사용하고 있다.
그리고 중요한 것은, 여기에 우리가 확인을 위해 사용할 수있는 객체(window.__ )가 없다는 것이다.
그러므로 typeof는 매우 유용하다.
몇몇 개발자들은 "종속성 주입 (dependency injection)"이라는 디자인 패턴을 선호한다.
function doSomethingCool(FeatureXYZ) {
var helper = FeatureXYZ ||
function() { /*.. default feature ..*/ };
var val = helper();
// ..
}
이러한 기능을 설계할 때 많은 옵션이 있다. 여기서 '올바른'패턴이나 '올바르지 않은' 패턴은 없다.
각 접근 방식마다 다양한 상충 관계가 있다. 그러나 전반적으로 선언되지 않은 것에 대한 typeof 안전가드는 우리에게 더 많은 옵션을 제공해줄 수 있다.
Review
- 자바스크립트는 7가지 내장 타입들이 존재한다.(null. undefined, boolean, number, string, object, symbol). 이들은 typeof 연산자에 의해 구별된다.
- 변수는 타입을 가지지 않고 값이 타입을 가진다. 이러한 타입들은 값들의 고유한 행동을 정의한다.
- 많은 개발자들이 undefined와 undeclared를 대략 같은 것이라고 생각하고 있으나, 자바스크립트에서는 완전히 다르다.
undefined는 변수가 값을 가지지 않는 것이고 undeclared는 선언된적이 없는 것이다. - 불행히도 JavaScript는 오류 메시지( "ReferenceError : a is not defined")뿐만 아니라 typeof의 반환 값 (두 경우 모두 "정의되지 않음")에서 이 두 용어를 혼동시킨다.
- typeof 연산자의 안전장치(오류방지) 특정 케이스에서 선언되지 않는 변수들을 사용되는 것에 대해 도움을 줄 수 있다.
'Programming > Javascript' 카테고리의 다른 글
[Javascript] You Don't Know JS (문법) (0) | 2020.04.05 |
---|---|
[Javascript] You Don't Know JS (강제변환) (0) | 2020.03.08 |
[Javascript] You Don't Know JS (Native) (0) | 2020.03.08 |
[Javascript] You Don't Know JS (Values-2) (0) | 2020.03.08 |
[Javascript] You Don't Know JS (Values) (0) | 2020.02.22 |