コンテンツにスキップ

JavaScript/例外処理

出典: フリー教科書『ウィキブックス(Wikibooks)』

例外処理(れいがいしょり、exception handling)とは、プログラム実行中に予期せぬ異常が発生した場合に、通常の実行フローを中断し、エラーメッセージの表示や適切な処理を行うプログラムの手法です。

throw

[編集]

throw文は、プログラムの実行中に発生したエラーや問題を示し、その場で例外を引き起こします。例えば、条件に合致しない場合や予期せぬ状況であれば、throw文を使って例外を発生させることができます。

functionreduce(array,callback,initialValue){if(typeofcallback!='function'){thrownewError(callback+" is not a function");}// ...}reduce([],null);// "null is not a function" とエラー

後述のtry/catch ブロックなしで throw を実行すると、エラーが現在のコンテキストから伝播し、エラーが発生したポイントからコードの実行が停止されます。これにより、通常の実行フローが中断され、エラーがコンソールに表示されたり、上位の呼び出し元でエラーがキャッチされるまで、エラーが伝播します。

throw文では、あらゆる種類の値を渡すことができますが、通常は例外オブジェクト(Errorなど)を渡します。例外オブジェクトは例外が発生した際の状況を記録し、デバッグを容易にします。特に、ReferenceErrorSyntaxErrorTypeErrorなどの例外オブジェクトは、エラーのタイプ(参照エラー、構文エラー、型エラーなど)を明確に示すために利用されます。

functionreduce(array,callback,initialValue){if(typeofcallback!='function'){thrownewTypeError(callback+" is not a function");}// ...}reduce([],null);// "TypeError: null is not a function" とエラー

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

try-catch

[編集]

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

try{thrownewError("エラー!");}catch(e){console.log(e.message);// "エラー!" と表示}console.log("しかし処理は続行…");

catch節は複数置くことができます。また、catch節は必ずthrow文のパラメータeを受け取らなければなりません。eの変数名は任意の識別子。

finally

[編集]

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

try{console.log("try");// 0. "try" と表示}catch(e){console.log("catch");}finally{console.log("finally");// 1. "finally" と表示}console.log("outside");// 2. "outside" と表示

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

try{console.log("try");// 0. "try" と表示thrownewError();}catch(e){console.log("catch");// 1. "catch" と表示}finally{console.log("finally");// 2. "finally" と表示}console.log("outside");// 3. "outside" と表示

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

return と finally

[編集]
return と finally
functiondiv(n,d){try{returnn/d}catch(e){console.log(e)}finally{console.log(`div(${n}, ${d}) -- finally`)}}console.log(`div(1, 2) = ${div(1,2)}`)console.log(`div(1, 0) = ${div(1,0)}`)console.log(`div(0, 0) = ${div(0,0)}`)
実行結果
div(1, 2) -- finally div(1, 2) = 0.5 div(1, 0) -- finally div(1, 0) = Infinity div(0, 0) -- finally div(0, 0) = NaN 
try文にfinally節を持つ言語では「tryブロックで例外を出さずのreturn文に達したとき、finally節を実行するか?」が問題になります。
ES/JSでは、return文に達してもfinally節が実行されます。

大域脱出

[編集]

例外は大域脱出に使うこともできます。大域脱出とは、入れ子になった制御構造の内側から外側に制御を戻すことです。ラベルを伴わないbreakreturnは最内側の制御構造(for/while/switchと関数)を抜け出すだけですが、例外をthrowすると文や関数を超えて制御が移ります。 この性質を利用すると二重以上のループや関数を脱出することができるのです。 しかし、大域脱出目的の例外の使用には慎重になってください。breakやreturnをラベルと共に使用することで、ほとんどの場合は例外を使うことなく大域脱出を達成できます。

イテレーションメソッドからの脱出
Array.prototype.forEach メソッドの様にcallbackの反復処理を行うイテレーションはbreakやreturnでは脱出ができないので、例外による大域脱出が適用なケースです。
この場合も、for文に置換えるほうが可読性は向上するでしょう。
関数外のラベルにはbreakできません(動かない例)
constary=newArray(10).fill(0).map((_,i)=>i)LABEL:ary.forEach(function(x){if(x>5)breakLABEL;// SyntaxError: Undefined label 'LABEL'console.log(x)})
例外を使ったイテレーションメソッドからの脱出
constary=newArray(10).fill(0).map((_,i)=>i);try{ary.forEach(function(x){if(x>5){thrownewError(`x = ${x}`);}console.log(x)});}catch{}
実行結果
0 1 2 3 4 5 
Array.prototype.every() を使ったイテレーションの中断
constary=newArray(10).fill(0).map((_,i)=>i);ary.every(function(x){if(x>5){returnfalse}console.log(x)returntrue});
実行結果
0 1 2 3 4 5 
このページ「JavaScript/例外処理」は、まだ書きかけです。加筆・訂正など、協力いただける皆様の編集を心からお待ちしております。また、ご意見などがありましたら、お気軽にトークページへどうぞ。
close