きっかけは JavaScript NaN type is crazy にコメントした事ですが
1. NaN === NaN
は false
typeof NaN // 'number'
typeof Inifity // 'number'
typeof -Infinity // 'number'
toString.call(NaN); // '[object Number]'
Infinity == Infinity // true
Infinity == -Infinity // false
Infinity == NaN // false
NaN == NaN // false
NaN === NaN // false (!!)
みんな知ってるね
2. global.isNaN("NaN")
は true, global.isFinite("0")
も true
で、このNaN
や Infinity
が厄介である為に isNaN()
と isFinite()
がグローバルオブジェクトに用意されているのですが、これもまた罠があります
isNaN(1); // false
isNaN(NaN); // true
isNaN("NaN"); // true (!?)
グローバルオブジェクトの isNaN()
や isFinite()
は引数が文字列でも数値型にパースできるもんだとみなして判定に入ります。これ、isFinite()
の方が厄介で、ここで無限大ではない(ちゃんと数値演算できる)変数だと判定してそのまま演算してしまうドジを踏みうる。
var test = function(x) {
if (isFinite(x)) {
return x + x;
}
};
test('10'); // "1010"
3. ちゃんと使おう Number.isNaN()
, Number.isFinite()
厳格な数値の NaN
判定、あるいは有限数判定にはグローバルメソッドではない Number.isNaN()
や Number.isFinite()
を使いましょう。
isNaN(NaN); // true
isNaN('NaN'); // true
Number.isNaN(NaN); // true
Number.isNaN('NaN'); // false
isFinite(10); // true
isFinite('10'); // true
Number.isFinite(10); // true
Number.isFinite('10'); // false
if (typeof x === 'number') { ... }
のようなバリデーションより手っ取り早く、かつ安心ですよ。
4. (追記)「それ IE とかじゃ Number.isNaN() とかないじゃないですかー」「それくらい Polyfill りなさいよ」
現状、IE 以外のブラウザは ECMAScript 6 の仕様にもかかわらず先行実装してくれているけど、 IE 9 以前のブラウザには用意されていません。でも、以下のようなコードで polyfill することはできます。
Number.isFinite = Number.isFinite || function(any) {
return typeof any === 'number' && isFinite(any);
};
Number.isNaN = Number.isNaN || function(any) {
return typeof any === 'number' && isNaN(any);
};