JavaScript/例外処理

出典: フリー教科書『ウィキブックス(Wikibooks)』
ナビゲーションに移動 検索に移動

例外処理(れいがいしょり、exception handling)とは、プログラムに異常が発生した場合に現在の処理を中断し、エラーメッセージを表示するなどの処理を行うことをいいます。

throw[編集]

throw文は例外を発生させます。

function reduce(array, callback, initialValue) {
    if (typeof callback != 'function') {
        throw new Error(callback + " is not a function");
    }
    // ...
}

reduce([], null); // "null is not a function" とエラー

throw文にはどんな値でも渡すことができますが、一般的にはErrorなどの例外オブジェクトを渡します。例外オブジェクトは生成されるときに例外発生時の状況を記録するため、デバッグが容易になるからです。特にReferenceErrorオブジェクトやSyntaxErrorオブジェクト、TypeErrorオブジェクトなどの例外オブジェクトは、エラーの種類(参照エラーや構文エラー、型エラーなど)を明示するのに用いられます。

function reduce( array, callback, initialValue ) {
    if ( typeof callback != 'function' ) {
        throw new TypeError( callback + " is not a function" );
    }
    // ...
}

reduce( [], null ); // "TypeError: null is not a function" とエラー

throw文で例外が投げられると、以降のプログラムの実行は中断され、処理系のエラーコンソールにエラーが表示されます。

try-catch[編集]

try文のブロックの中で例外が発生すると、catch文のブロックが実行され、例外が捕捉されます。try文のブロックで例外が発生しなかった場合は、catch文のブロックは実行されません。catch文のブロックが実行された後も、catch文のブロックの中で例外が発生しなければ、プログラムは中断せずに以降の処理を継続します。

try {
    throw "エラー!";
}
catch (e) {
    alert(e); // "エラー!" と警告
}

alert("しかし処理は続行…");

catch文は複数置くことができます。また、catch文は必ずエラーメッセージeを受け取らなければなりません。eの変数名はご自由に。

finally[編集]

finally文は事後処理を行います。try-catch文の後にfinally文を書くと、例外が発生してもしなくてもfinally文が実行されます。

try {
    alert("try");     // 0. "try" と警告
}
catch (e) {
    alert("catch");
}
finally {
    alert("finally"); // 1. "finally" と警告
}

alert("outside");     // 2. "outside" と警告

例外が発生した場合は、catch文が実行された後にfinally文が実行されます。finally文が実行された後は以降の処理を継続します。

try {
    alert("try");     // 0. "try" と警告
    throw null;
}
catch (e) {
    alert("catch");   // 1. "catch" と警告
}
finally {
    alert("finally"); // 2. "finally" と警告
}

alert("outside");     // 3. "outside" と警告

try文の後にはcatch文またはfinally文のいずれか、もしくは両方を置かなければなりません。catch文を除いたtry-finally文では、例外が発生してもしなくてもfinally文は実行されますが、catch文によって例外が捕捉されないので、例外が発生した場合は以降の処理を中断します。

大域脱出[編集]

例外は大域脱出に使うこともできます。大域脱出とは、入れ子になった制御構造の内側から外側に制御を戻すことです。breakreturnは最内側の制御構造(for/while/switchと関数)を抜け出すだけですが、例外をthrowすると文や関数を超えて制御が移ります。この性質を利用すると二重以上のループや関数を脱出することができるのです。

JavaScript 1.6で追加されたforEachメソッドを使用すると、次のようにして配列の各要素について処理を行うことができます。

var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
array.forEach(function(n){
    if ( n == 5 ) {
        alert(n); // "5" と表示
        return;   // でも抜けられない
    }
});

この例では配列の中から 5 という数字を見つけて表示し、ループを抜けることを期待していますが、returnをしてもforEachメソッドによって呼ばれた無名関数から脱出するだけで、ループそのものは最後の 9 まで回ってしまいます。その分の処理に掛かる時間は無駄になってしまいます。

このような場合、try-catch文による例外処理を応用すると反復処理から抜け出すことができます。

var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
try {
    array.forEach(function(n){
        if ( n == 5 ) {
            alert(n);    // "5" と表示
            throw false; // 例外を投げる
        }
    });
}
catch (e) {
    if (e) throw e; // もしfalseでない例外が発生していたら中断
}

// 以降の処理

こうすると、配列の中から 5 という値が見つかった時点で例外を発生し、forEachメソッドの反復を抜けるため、処理に掛かる時間を短縮することができます。

catch節は単に見せかけの例外を捕捉するだけで、そのまま以降の処理を続けますが、もし本当に意図しない例外がtry節の中で発生していたときのために、throw false;で投げた例外efalseになっていない場合(trueの場合)は同じ例外を再度発生させるようにしています。

注意[編集]

someindexOfなど、配列の要素を舐める関数をうまく使うと、例外に頼らずとも効率よく動くコードが書けることがほとんどです。例外をエラー通知以外のことに使うのは裏技的な最後の手段と捉え、極力避けましょう。

このページ「JavaScript/例外処理」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。