JavaScript の NaN について
この記事は#kosen10s Advent Calendar 2017の 15 日目の記事です。
昨日は寒い日は紅茶に砂糖を入れて飲むとおいしい - 死後裁きにあうでした。 美味しい紅茶が飲みたくなりました。
2 つとった枠のうち 1 つは技術系の記事を書こうと思ってたのですが、準備不足もあり小ネタです。
JavaScript でコードを書いていると、まれにNaN(Not a Number)
に遭遇することがあります。
別に知ってれば大したことないのですが、若干ややこしくて厄介なので NaN について解説したいと思います。
どういうときに遭遇するか
NaN はMath
object の関数に引数として不適な値を渡したり、parseInt()
などで文字列を数値に変換させようとすると返ってくることがあります。
また、let x = NaN
のように代入可能です。
例:
Math.sqrt(-1); // => NaN 虚数は返ってこない
parseInt("hello", 10); // => NaN
https://example.com?page=18
という URL からpage
パラメータを取得し、その値に応じて表示する内容を書き換える
といったコードを書いた時、https://example.com?page=hello
に対しては例外処理が必要です。
ちなみに、数値x(!==0)
を0
で割ったときにはInfinity
もしくは-Infinity
となり、0 / 0
はNaN
となります
Truthy, Falsy
NaN
を単体で評価すると Falsy になります。直感的ですね。
NaN ? "foo" : "hoge"; // => 'hoge'
比較
NaN
は比較演算子で評価した場合、どんな値とも等価にはなりません。
ここで気をつけなければいけないのが、NaN === NaN
がfalse
になることです。
NaN === false; // => false
NaN === 0; // => false
NaN > 0; // => false
NaN < 0; // => false
NaN === NaN; // => false
NaN !== false; // => true
NaN !== true; // => true
NaN !== NaN; // => true
NaN の検出
JavaScript にはisNaN()
というトップレベル関数が用意されています。引数を一つとり、boolean(true | false)を返します。
ただ、このisNaN()
にも一癖あって、渡された引数がNaN
以外にも、文字列、undefined、Object、 Function だった場合もtrue
を返します。
そのため、isNaN(x)
によりtrue
が返却されても、x
がNaN
である保証はありません。
isNaN(NaN); // => true
isNaN(undefined); // => true
isNaN("hello"); // => true
isNaN({}); // => true
isNaN(new Function()); // => true
isNaN(0); // => false
isNaN(true); // => false
isNaN(null); // => false
引数が Array の場合は length が 0 か、要素 1 つだけで値が数値または null の場合のみfalse
が返ります
isNaN([1, 2, 3]); // => true
isNaN(["hello"]); // => true
isNaN([true]); // => true
isNaN([]); // => false
isNaN([1]); // => false
isNaN([null]); // => false
非常にややこしいですね。覚えなくて大丈夫です。
というのも、ECMAScript2015 でNumber.isNaN()
が導入され、これを用いることによりNaN
かどうかを正しく評価することができるようになりました。
Number.isNaN(NaN); // => true
Number.isNaN(undefined); // => false
Number.isNaN("hello"); // => false
Number.isNaN({}); // => false
Number.isNaN(new Function()); // => false
Number.isNaN(0); // => false
Number.isNaN(true); // => false
Number.isNaN(null); // => false
すばらしいですね。非常にわかりやすくなりました。とはいえ、前時代の JavaScript を書かなければいけないこともあるかもしれません。
そのときは先に述べた、NaNは比較演算子で評価した場合、どんな値とも等価にはならない
という性質を利用します。
Number.isNaN = function (val) {
return val !== val;
};
Number.isNaN(NaN); // => true;
Number.isNaN(0); // => false;
まとめ
トップレベル関数のisNaN()
は使ってはいけません。Number.isNaN()
を使いましょう。
明日は ruryusham さんの記事です。