JavaScriptでは初期化されていない変数には全て「undefined」という値が入っています。
var a;
alert(a); //undefinedが入っている
これを利用して、変数が定義済みかどうかを判別することが可能です。…が、やり方がいろいろあるみたいなので、まとめてみることにします。
undefinedと比較する
if (a === undefined) {
alert("aは未定義");
}
グローバル変数として、そのまんまundefinedという名前の変数が用意されているので、それと比較するやり方。一番素直な方法ですが、JavaScriptにおいては良くない書き方とされています。
undefinedは予約語ではなく、単なる変数です。だから上書きすることができるし、関数スコープ内で同名のローカル変数を作ることもできます。(ただし最近の処理系ではconst扱いになって上書きできなくなっているようです)
undefined = 1;//古めの処理系なら代入できちゃう
(function(){
var undefined = 5; //変数作れちゃう
alert(undefined); // 5
})();
なので、文脈によらず、必ず確実にundefined判定をするためにはこの書き方は使えないことになります。もちろん普通は、undefinedに別の値を代入するなんて行儀の悪いことはしないでしょう。しかし、他の人にライブラリとして提供するようなプログラムを書く場合は気にする必要があります。
typeof a === "undefined"
そこでよく使われているのがtypeofを使うやり方です。undefined値にtypeof演算子を作用させると必ず"undefined"という文字列が返るため、それと比較することで判定を行います。
if (typeof a === "undefined") {
alert("aは未定義");
}
たぶん最もよく使われていますが、個人的にはちょっと長くて不格好だと思っています。
void 0と比較する
voidはあらゆる値に作用し、常にundefinedを返す演算子です。文脈によらずundefinedを受け取れるので、安全確実です。別にvoid 100でもvoid ""でも何でもいいのですが、慣習的に0が使われることが多いようです。
if (a === void 0) {
alert("aは未定義");
}
わかっていれば読めるんですが、void演算子がそもそもJavaScript独特のものなので、可読性が悪いような気もします。
!で代用する
undefined値に「!」を作用させるとtrueが返るため、これを利用するやり方もあります。しかしfalseや0もundefined扱いになってしまうので、注意が必要です。
if (!a) {
alert("aはfalseか0かundefinedかnull");
}
undefinedを厳密に判別する必要がある場合は使えませんが、厳密でなくていいのであれば短く書けますし、理解して使うならよいと思います。
==nullで代用する
[JavaScript] typeof arg == 'undefined' っていらないんじゃね? / LiosK-free Blogで紹介されていたやり方です。nullはundefinedと違って予約語です。どの文脈でも確実にnullが入っているので安心して使えます。
「===」を使わず「==」を使っているのがポイントですね。
if (a == null) {
alert("aはundefinedかnull");
}
これも「!」と同じく完全な判定には使えませんが、「!」よりずっと厳密になりました。気にする必要があるのは「nullとundefinedを区別する必要があるか?」という点だけです。通常は区別しなくていい気がするので、個人的にはよく使わせてもらっています。
自分でundefinedを定義してしまう
jQueryが採用している方式です。undefinedが予約語でないせいで問題なのだから、逆に自分で定義してしまおうという発想です。個人的には結構な衝撃を受けました。
(function(undefined){
//このブロック内では確実にundefinedはundefined値が入っている
if (a === undefined) {
alert("aは未定義");
}
})();
わかりにくいなら、こう書いても同じです。
(function(){
var undefined;
//このブロック内では確実にundefinedはundefined値が入っている
if (a === undefined) {
alert("aは未定義");
}
})();
自分で定義したのだから、キーワード"undefined"にundefined値が入っていることが保証されます。なので、安心してundefinedと比較できるようになります。
この書き方、結構面白くて、コード圧縮ツールと相性がいいといううれしい副作用があります。例えばYUI Compressorを使って、typeofを使う場合と比較するとこんなに差が出ます。(ちょっと極端な例かも知れませんが^^;)
if (typeof a === "undefined") {
alert(1);
}
if (typeof b === "undefined") {
alert(2);
}
if (typeof c === "undefined") {
alert(3);
}
//-----圧縮後↓ 109byte-------------
if(typeof a==="undefined"){alert(1)}if(typeof b==="undefined"){alert(2)}if(typeof c==="undefined"){alert(3)};
(function(undefined){
if (a === undefined) {
alert(1);
}
if (b === undefined) {
alert(2);
}
if (c === undefined) {
alert(3);
}
})();
//---- 圧縮後↓ 75byte------------
(function(d){if(a===d){alert(1)}if(b===d){alert(2)}if(c===d){alert(3)}})();
コード圧縮ツールはローカル変数を短い名前に再定義してくれるので、jQuery方式の書き方は圧縮効率を高めることにつながります。長いコードで、しかもundefined判定をよく使うような場合は効果が高くなるでしょう。
まとめ
教科書的にはいかなる文脈でも使えるtypeofを使いましょうということになりますが、適宜他の書き方も検討するとより読みやすいコードになるんじゃないでしょうか。(無難なコメントだな…)
![パーフェクトJavaScript (PERFECT SERIES 4) [大型本] / 井上 誠一郎, 土江 拓郎, 浜辺 将太 (著); 技術評論社 (刊) パーフェクトJavaScript (PERFECT SERIES 4) [大型本] / 井上 誠一郎, 土江 拓郎, 浜辺 将太 (著); 技術評論社 (刊)](https://images-fe.ssl-images-amazon.com/images/I/51yrjFsf-2L._SL160_.jpg)
追記:ReferenceError対策
おおう。それがあった。ご指摘ありがとうございます。
完全に宣言されてない変数の場合、いきなり使うとReferenceErrorが発生しますね。ということは上で書いている例も文脈依存か。。
// グローバル変数の存在確認には使えない
//if (a == null) { // ReferenceError!
//}
if (typeof a === "undefined") { //これなら例外が起きない
//...
}
// 引数の確認とかなら使ってOK
function hoge(a) {
if (a == null) {
//...
}
}
hoge();
いちおうグローバルオブジェクト(要はwindow)を使えば、==nullでグローバル変数の存在確認も書けます。が、環境依存になってしまう(node.jsとかにはwindowがありません)ので、教科書的にはアウトな表現ですね。。難しいなあ…
if (window.a == null) { //これならReferenceErrorは起きない
alert("aは未定義!");
}
keyword: javascript