Kokudoriing

技術系与太話ブログ

undefined リテラルと NaN リテラル

undefined は変数宣言(初期化なし)時の規定値です。
NaN は 0 除算時の結果等、常用数学として不適切な値を意味します。
それぞれ undefined、NaN というリテラル表記が     ありません。

console.log(undefined); // undefined
console.log(NaN); // NaN

あれ、でもリテラルっぽく使えますね。
結論から言うとこれはグローバルオブジェクトのプロパティでしかありません。

つまり、以下のコードと先述のコードは等価。

console.log(window.undefined); // undefined
console.log(window.NaN); // NaN

つまり

undefined = 'non undefined';
NaN = 'non NaN';

console.log(undefined); // 'non undefined'
console.log(NaN); // 'non NaN'

これはひどい。
これは誰得仕様なので最新の ECMAScript5th では、 strictモード だと undefined、NaN を不変値として扱います。
ただ、最近のブラウザはお利口ですので、strictモードでなくとも不変値扱いしてくれます。
(だからと言って strictモード をしなくて良いという話ではない。)
なので腐った牛乳こと IE6 はもちろん、死ぬことを望まれている IE7 でもこの変数汚染が出来てしまいます。
更に、CSS3 が使えないでお馴染み IE8 もこの変数汚染が出来てしまいます。
糞ばっかですね。


どうするか。

JavaScriptでは undefined を吐くためだけに存在する void 演算子という子がいます。

console.log(void(0)); // undefined

ただあまり使われません。
理由としては後述する方法のほうがスマートな事、でしょうか。
因みに、void 演算子はよくブックマークレットで使われます。(最後に undefined 返す時)

つぎー。

関数の引数は仮引数より実引数の数が少ないと、余った仮引数に undefined が入ります。
これは ECMAScript の仕様で決まっており、安心して使えます。

(function(hoge) {
  console.log(hoge); // undefined
})();

この時仮引数の名前を undeifned にしてやると、
(undefined はグローバルオブジェクトのプロパティなのでキーワードじゃない)
凄く自然に記述できます。

(function(undefined) {
  console.log(undefined); // undefined
})();

もちろんこの時スコープ内で undefined を上書いてはいけません。
undefined、NaN を変数汚染から守るのは基本的に外部の不特定なソースが、
変数汚染をしているかもしれないという考えによるものです。

ちなみにちなみに、(function() {}) を Function.prototype.apply(this) で呼んでやるほうがベターです。

(function(undefined) {
  console.log(undefined); // undefined
}).apply(this);

はい、これいつもこのブログで書いている定形ですね。
これは何かというと、strictモード では関数呼び出しの場合の this は undefined をさします。
これは非常に嬉しい事で、今までは this が グローバルオブジェクトだったがために、
new 呼び出しを期待して this.property = 1 とかしてグローバル変数作ったりとかしていたり。
なので普通の関数の場合はこのルールは嬉しいのですが、
今回はスコープとして関数を利用しているのでこのルールが足かせになっちゃってます。
なので、apply(this) でコンテキストを無理やり変更してます。
(strictモード ではトップレベルでの this 参照はグローバルオブジェクトを指すことが約束されています。)

ちなみにちなみにちなみに、NaN は?
そもそも NaN を右辺値として使用することもなければ、
num == NaN とかも書いたりしません。と言うか書いてはいけません。
NaN は(NaNを含め)全ての値と ==、=== で false が返ります。
なので、NaN == NaN も NaN === NaN も false。
(0除算は不定なので、定まらないモノと定まらないモノが等しくなることはあり得ない。
もし等しくなると言えるのなら、それは値が定まっているとも言える。)
なので、NaN かどうかの判定は専用の window.isNaN(num) メソッドを使いましょう。


結論
これを定形だと思って使いましょう。

"strict mode";
(function(undefined) {
  
}).apply(this);

それか、IE6〜8 が入っている PC を見つけ次第窓から投げ捨てましょう。
ちなみに IE9 は大丈夫です。
Internet Explorer はバージョン9 からが Internet Explorerです。
そして IE10 からがモダンブラウザ。