비록 현재 왕성한 액션 히어로의 역할로 웹의 커다란 한 부분을 담당하고 있는 JavaScript라도 그 결점은 있기 마련이고, 언젠가는 이러한 언어 설계상의 오류가 자기의 뒤통수를 때릴 때가 있을 것이다. 결국, 미리 알아서 조심해야지.

JavaScript에서 NaN 값은 not a number라는 뜻으로, 즉 숫자가 아니라는 의미이다. 하지만,

typeof NaN === 'number' // true 

이렇듯, typeof로는 NaN와 숫자를 구분할 수가 없거니와, 자신과의 비교도 불허한다.

NaN === NaN    // false 
NaN !== NaN    // true 

결국, JavaScript에서는 숫자와 NaN를 구분하는 isNaN라는 함수를 제공하고 있다:

isNaN(NaN)       // true 
isNaN(0)         // false 
isNaN('oops')    // true 
isNaN('0')       // false 

결국, 숫자를 구별하는 가장 확실한 방법으로 다음과 같은 함수가 쓰일 수 있겠다:

function isNumber(value) {
  return typeof value === 'number' && isFinite(value);
}

typeof 얘기가 나와서 그러는데,

typeof null     // object 

null 대신에 object를 돌려받는다. 그래서, null 값을 알아보기 위한 가장 좋은 방법은 아래와 같다:

my_value === null

또한, JavaScript의 Reserved Words는 보통 변수 이름으로 사용될 수 없는데, 굳이 reserved words를 object literals의 키 값으로 사용하려 할 경우에는, 항상 따옴표도 함께 써줘야 하고 dot notation 대신에 bracket notation을 사용해야 한다:

var method;                // ok 
var class;                 // illegal 
object = {box: value};     // ok 
object = {case: value};    // illegal 
object = {'case': value};  // ok 
object.box = value;        // ok 
object.case = value;       // illegal 
object['case'] = value;    // ok 

JavaScript는 프로그램 상 오류를 자동 수정하려는 성질이 있어서 문단 마지막에 항상 semicolons을 삽입하는데, 이것이 오히려 아래처럼 뜻하지 않는 문제를 일으킬 수도 있다.

return
{
  status: true
};

return 뒤에 바로 semicolon이 붙어버리면서 결국, undefined 값을 돌려주게 된다. 그래서 { 는 항상 아래처럼 앞 줄의 맨 마지막에 붙여주는 스타일을 손에 익혀야 한다.

return {
  status: true
};

그리고 string을 integer로 바꾸어주는 parseInt 함수를 사용할 때는 항상 radix 매개 변수를 사용하는 버릇을 들여서, 아래와 같이 뜻하지 않는 결과를 초래하는 일을 미연에 방지한다.

parseInt("08");      // 0  
parseInt("09");      // 0 
parseInt("08", 10);  // 8 

또 하나, JavaScript의 소수점 계산은 형편없는 것으로 악명높다:

alert(0.1 + 0.2); // 0.30000000000000004 

이것은 JavaScript만의 문제가 아니라, Binary Floating-Point Arithmetic(IEEE 754)을 채용한 언어들에서 공통적으로 나타나는 문제점으로, ECMAScript 4에서는 Real Decimals의 채용하면서 이를 극복할 수 있는 문제지만, 당분간은 미리 scaling 해서 이 문제를 피할 수 밖에.

다음은 JavaScript에서 사용되는 여러가지 “falsy” 값들이다:
0(Number), NaN(Number), ”(String), false(Boolean), null(Object), undefined(Undefined).

모두 “falsy” 값을 가지지만 번갈아 서로 혼용되서 사용될 수는 없어서, 예를 들어 null 값을 구하는데, undefined를 대신 사용하면 잘 못된 결과를 얻게 된다. 이 얘기는 자동 타입 변환(type coercion)을 일으키는 == 연산자 대신에 더 염격한 === 연산자를 사용하라는 얘기와 맞닿아 있다.

이 외에도, 실수든 혹은 필요에 의해서든 상호 운용성을 떨어뜨리는 global variables의 남용 등, JavaScript 문법 검사기인 JSLint를 한번 돌려 본 사람이라면 많은 골칫거리를 떠안게 된다. 하지만, 대부분의 골 때리는 일들은 잘못된 습관에서 비롯되는 경우가 많으므로 평소에 많은 코드를 접하면서 좋은 습관을 들이도록 노력하는 것이 중요할 것이다.

관련된 주제의 글

“JavaScript의 이런 점이 뒤통수를 때리더라.”에 달린 5개의 댓글

NaN의 정의에 따르면 NaN은 어떠한 객체와도 같지 않으니
number != number // number가 NaN이면 true.
이런 식으로 검증할 수도 있을 것 같습니다.

어차피 isNaN 함수가 제공되지 그걸 쓰면 되지만요. ㅋㅋ

덧붙이면, 두 개의 값이 같은 것인지 혹은 같은 object인지 알아볼 때 확실한 방법으로 ECMAScript 2015에선 Object.is() 매소드를 제공하고 있습니다.

Object.is(NaN, 0/0); // true
Object.is([], []); // false

coercion 걱정 없이 비교할 수 있어서, 앞으로 브라우저 지원 상황이 좋아지면 유용하게 쓰일 수 있을 겁니다.

댓글을 남겨 주세요