至るところで使われる、nullチェックの書き方をJavaScript的に考えてみることにします。
nullチェックとは
プログラミングでは、よくnullという概念が用いられています。「何もない」という特殊な値ですが、実際には、これがしばしば悪さをすることになるのです。
Javaの例
以下のコードは実行時例外(NullPointerException)になります。
public class Main{
public static void main(String[] args){
boolean result = isExample(null);
System.out.println(result);
}
private static boolean isExample(String s){
return s.equals("example");
}
}
これは、String型宣言が行われているにも関わらず、nullという特別な値が入っているために、equals()メソッドへの参照を取得することができません。よって、アプリケーションは処理を継続する術を持たず、例外が出てしまうわけです。
しかし、これを回避する手段があります。それが俗に言う「nullチェック」です。以下のコードを実行してみましょう。
public class Main{
public static void main(String[] args){
boolean result = isExample(null);
System.out.println(result);
}
private static boolean isExample(String s){
if(s == null){
return false;
}else{
return s.equals("example");
}
}
}
これで、nullがあっても正しくresultが返るようになりました。
このif(s == null)
の部分が、nullかどうかをチェックする、「nullチェック」と呼ばれるコードです。
JavaScriptでのnull
JavaScriptには、nullに加えてundefinedという値があります。両者は似たようなものですが、undefinedはその名のとおり、「未定義」の値です。たとえば・・・。
var str;
console.log(str); // undefined
undefinedは値の内容が存在しないときに暗黙的に設定される値です。対して、nullはプログラマが明示的に設定しなければ存在しない値です。たとえば次のコードではnullが代入されます。
var str = null;
console.log(str); // null
nullは、undefinedを返す場合とで明示的に動作を変えたい場合などに使われますが、意識して使うケースは通常そう多くありません。
今回は、そんなJavaScriptで使えるnull(undefined)チェックの手段について、いくつか考えてみましょう。
JavaScriptでのnull(undefined)チェック
if文で分岐する
最も単純な例です。
var o;
if(o === undefined || o === null){
console.log("o is null or undefined");
}
特に理由がなければこれで問題ありません。実際には、これをこのまま使わず、ユーティリティ的なメソッドを定義して使うことになるかと思います。
function isNullOrUndefined(o){
return (o === undefined || o === null);
}
typeof演算子を使う
時に、ローカル変数のundefinedを上書きする悪いヤツがいるかもしれません。ES5では、グローバルのundefinedの書き換えは行うことができませんが、ローカル変数のundefinedにundefined以外を定義することができます。
しかし、通常、クロージャ内部のローカル変数まで弄られる心配をする必要はありません。これらは良くない例として覚えておきましょう。
たとえば以下のようなケースを考えてみます。
var result = isNullOrUndefined("example");
console.log(result); // falseを期待するがtrueが返る
function isNullOrUndefined(o){
var undefined = "example";
return (o === undefined || o === null);
}
こういったことが想定される場合、以下のようにtypeof演算子を使うことで確実性を保つことができます。
var result = isNullOrUndefined("example");
console.log(result); // false
function isNullOrUndefined(o){
var undefined = "example";
return (typeof o === "undefined" || o === null);
}
ちなみに、nullに対して値を代入しようとすると、SyntaxErrorとなりますので、こちらは心配する必要はありません。
グローバル変数を見る
先ほどの例だと、ローカル変数のundefinedを参照してしまって期待した結果が得られませんでした。
ES5では、グローバルのundefinedを書き換えることはできませんので、以下のようなコードでも確実性を担保できます。
var result = isNullOrUndefined("example");
console.log(result); // true
function isNullOrUndefined(o){
var undefined = "example";
return (o === function(){}.undefined || o === null);
}
なかなかトリッキーなコードです。可読性を損なうので、実際には使わないようにしましょう。
暗黙的キャストを利用する
JavaScriptは、どのようなオブジェクトであっても、評価時に暗黙的にbooleanにキャストするという特徴があります。以下のコードを見てください。
var a = "";
var b = 0;
var c = undefined;
var d = null;
var e = NaN;
これらは、全て暗黙的にfalseと評価されます。これを利用すれば、簡単にnullチェックが実現できます。しかしこれは、限られた用途にしか使えないことを覚えておいてください。入力がNumber型やString型の場合、空文字や0、NaNもfalseと評価されてしまうことに注意しましょう。
以下のように、入力値がいくつかのケースに限られている場合に有効でしょう。
var o = findById(1);
if(o){
console.log(o.name);
}
function findById(id){
if(id === 1){
return {
id: 1,
name: "example"
};
}
return null;
}
oがnullの場合は、consoleを表示しないのでo.name
が評価されません。仮にoがnullなのにo.nameを評価しようとした場合、TypeErrorが発生してしまいます。このコードは、これを未然に防いだものです。
配列などのケース
ところで、配列などに対してforEachメソッドを実行したい場合に、nullチェックを行うケースがあります。
var arrays = getArrayOrNull();
arrays.forEach(function(arr){
console.log(arr);
});
// ランダムでnullかArrayを返すメソッド
function getArrayOrNull(){
return Math.round(Math.random()) ? [1,2,3] : null;
}
これをこのまま実行すると、50%の確立でTypeErrorが発生しますが・・・。
以下のようにすれば、nullの場合は空配列を代入するため、問題なく動作します。
var arrays = getArrayOrNull() || [];
arrays.forEach(function(arr){
console.log(arr);
});
// ランダムでnullかArrayを返すメソッド
function getArrayOrNull(){
return Math.round(Math.random()) ? [1,2,3] : null;
}
これもよく使われるテクニックです。適切な場所で使えると簡潔ですね。
まとめ
いろいろ手段はありますが、通常のコーディングでは最も単純な厳密等価演算子を使うのがベターでしょう。
しかし、暗黙キャストを使う方法も、よく使われています。ケースによって適切な使い方をして、バグなく可読性に優れたプログラミングを行いたいものですね。