특이한 typeof
typeof 연산자는 피연산자의 타입을 문자열 형태로 리턴하는 연산자이며 여러가지 특이한 부분이 있다.
typeof null; // object
typeof undefined; // undefined
typeof function(){} // function
typeof [] // object
제일 특이한 부분이 null 값의 타입이 object 라는 것이며 이는 falsy 한 값이기 때문에 다음과 같이 확인하는 것이 정확하다.
var a = null;
(!a && typeof a === 'object'); // true
선언되지 않은 것 vs 정의되지 않은 것
Undeclared(선언되지 않은 것)과 undefined(정의되지 않은 것)는 완전히 다른 개념이다. Undeclared의 경우는 아예 변수 자체가 선언되지 않음을 뜻하며 undefined는 변수에 값이 할당되지 않은 것을 말한다.
var a;
a; // undefined
b; // ReferenceError: b가 정의되지 않았습니다.
따라서 위와 같이 사용할 경우 에러가 발생한다.
typeof 안전가드(Safety Guard)
방금 위에서 본 차이점을 통해서 undeclared 변수를 사용하려고 할 경우에 에러가 발생한다는 것을 알 수 있다. 하지만 typeof 연산자를 사용한다면 모두 undefined 값이 나온다.
var a;
typeof a; // undefined
typeof b; // undefined
따라서 이 특성을 적극 활용하면 다음과 같은 경우에 유용하다.
- 전역 네임스페이스를 공유하고 있고 특정한 전역변수가 존재하는지 확인할 때
- 사용하는 유틸리티 파일에 특정 변수가 존재하는지 확인할 때
function doSomething() {
var helper = (typeof FeatureXYZ !== 'undefined') ? FeatureXYZ : function() {}
.....
}
위와 같이 안전가드를 사용할 수 있다.
유사배열을 배열로 바꾸자!
Array.prototype.slice사용 (ES6 이전)
function test() {
var arr = Array.prototype.slice.call(arguments);
console.log(arr);
}
test(1,2,3); // [1, 2, 3]
Array.from사용 (ES6)
function test() {
var arr = Array.from(arguments);
console.log(arr);
}
test(1,2,3); // [1, 2, 3]
문자열과 배열은 다르다.
문자열은 유사배열이며 불변 값이지만 배열은 가변값이다. 따라서 배열에서 유용한 가변배열 메서드는 불변 값인 문자열에서 사용할 수 없다. 하지만 배열에서도 불변배열 메서드가 있기 때문에 그걸 문자열에 빌려쓸 수 있는 형태이다.
var a = 'foo';
var b = Array.prototype.join.call(a, '-'); // 'f-o-o'
var c = Array.prototype.map.call(a, function(aa) {
return aa.toUpperCase() + '.';
}).join(''); // 'F.O.O.'
불변배열 메서드인 join 과 map 은 문자열에 쓸 수 있는 걸 볼 수 있다.
배열에는 가변배열 메서드인 reverse 가 있는데 이는 역시 가변배열 메서드이기 때문에 문자열에 사용할 수 없다. 따라서 야매스러운 방법을 사용한다.
var a = '123';
var c = a.split('').reverse().join(''); // '321';
문자열을 배열르 분할한 후에 역으로 나열하고 그걸 합치는 방법이다. 이는 단순 문자열에 굉장히 효과적이지만 유니코드 문자가 섞여 있는 경우는 불가하니 유니코드의 경우를 사용하고 싶다면 Esrever 를 참고하자.
숫자 소수점 이하 조정하기
var a = 77.89;
a.toFixed(0); // 77
a.toPrecision(2); // 77
기능은 비슷하지만 toFixed 의 경우 소수점 이하의 개수를 지정하고 toPrecision 의 경우는 유효숫자의 개수를 지정한다.
undefined와 null
undefined와 null 모두가 primitive type인데 특징이 다르다.
- undefined
- 식별자(identifier)로 사용될 수 있다.
- 값이 비어있는 상태를 표현한다. 즉, 선언은 되었지만 할당되지 않은 상태이다.
- null
- 식별자로 사용될 수 없다.
- “값 아닌 값”을 표현한다. 즉, 값이 아닌것을 표현하는 값이다.
NaN, 무한대, 0
NaN(Not a Number)
NaN은 “숫자 아님”이라는 뜻의 값으로 경계값(Sentinal Value)의 일종이다. 숫자 집합에서 특정한 종류의 에러 상황을 나타내기 때문에
typeof연산자를 적용하면number를 리턴한다.전역객체인
window가isNaN()이라는 판단함수를 가지고 있지만 이는 “숫자 아님”을 판단하고 NaN에 대해선 엄밀히 판단하지 못한다. 따라서 ES6에 도입된Number.isNaN()을 사용해야 한다.NaN은 자기 자신과도 동등하지 않은 유일한 값 으로 반사성(Reflexivity)이 없다.
var a = 'NaN' / 3; // NaN a === a; // false무한대
var a = 1 / 0; // Infinity == Number.POSITIVE_INFINITY var b = 1 / -0; // Infinity == Number.NEGATIVE_INFINITY var c = a / b; // NaN
0
-0 도 있다는 것을 알아두자.
var a = 0 / 3; // 0
var b = 0 / -3; // -0
여기서도 이상한 현상이 있는데 문자열 '-0' 을 -0 으로 변환시킬 때는 잘 되지만 그 역은 0 으로만 나온다.
var a = '-0';
var b = -0;
Number(a); // -0
b.toString(); // '0'
비교를 할 때도 0 과 -0 은 == 를 쓰든지 === 를 쓰든지 같다고 도출되기 때문에 ES6에서 도입된 Object.is() 를 사용하도록 하자. 이 부분은 NaN의 비교에도 마찬가지이다.