try{}
内の処理は必ず実行され、そこで例外が投げられたらcatch{}
が実行される。finally{}
は任意だが、記述がある場合は最後に「必ず」実行される。
これは、一般に例外処理と呼ばれる構文である。
比喩で理解する例外処理
JavaScriptに限らず、プログラミングにおける例外は、そのコードが想定する条件が破られた状態を指す。そのコードで認められないもの=例外のようなイメージである。
try
例えば、私が伊勢エビのようなものを顔面にくくり付けて深夜に徘徊しているとする。一般常識に鑑みて、少し危険な匂いがするはずだ。地域の安全のためにも、第三者に危害を及ぼす可能性があるかどうかを判断する必要がある。
つまり、警察組織による職務質問が行われるべきだ。
このように、有害・無害を見極める処理がtry{}
である。
catch
さて、警察組織によるトライ(職務質問)の結果、とんでもない事実が発覚する。よく見ると私が顔面にくくり付けているのは伊勢エビではなく、フェイスハガー(エイリアンの生殖器)だったのだ。これは明らかにヤバい。例外中の例外である。絶対に取り逃がさないよう、然るべき組織に対応をぶん投げる必要がある。
このぶん投げられた対応を受け止めるのがcatch{}
である。
また、try{}
からcatch{}
へ処理を移行するための、応援要請にあたる処理にはthrow
文を使う。一般には、文字通り「例外を投げる」などと表現される。
finally
警察組織が動く以上、結果に関わらず記録が求められる。この結果如何によらず最後に必ず実行される処理がfinally{}
にあたる。
変な例えのせいで逆にわかりにくくなったかもしれないが、finally
は必要がなければ別に書かなくても良い。
サンプルコード
以下、上記の比喩をコードで表現したものである。
try{}
もcatch{}
もfinally{}
も、特別難しいことはない。単純に、それぞれのブロックで実行したい処理を{}
の中に書けばいい。
ただ、catch{}
の中で例外の内容を知りたいケースが少なくない。上の例ではthrow
文で空文字を投げているが、必要に応じて例外に関連する情報をcatch
に送ることができる。
throw文
throw
文は、関数のどこにでも書ける。
throw文
が実行されると、その時点で関数の処理は停止し、一番近くの(コールスタック内の最初の)catch{}
に処理が移動する。
catch{}
が存在しない場合、コンソールにUncaught xxx
(xxxは投げられた例外の内容)と表示して、プログラムを終了する。try{}
に含めずにトップレベルにthrow
文を書いても、同様の挙動となる。
throw文の書き方
throw
文は、以下のように書く。なお、throw
で投げた式は、catch{}
の引数として受け取る。引数名は任意だが、err
やerror
とするのが一般的である。
JavaScriptで有効な式であれば、どのような値でも例外として投げることができる。
ただ、実際には、Errorオブジェクトを投げる慣習がある。
Error
オブジェクトは、Error('メッセージ')
あるいはnew Error('メッセージ')
のようにして生成する。
キャッチしたエラーオブジェクトをさらに上位のcatch{}
に投げたい時がある。そういった場合は、cause
プロパティを持つオブジェクトを第二引数に渡す。このcause
プロパティは、大元のエラーオブジェクトを保持することが期待される。
Errorオブジェクトの種類
Error()
は汎用的なエラーオブジェクトを生成するが、JavaScriptには特定のエラーに応じたエラーオブオブジェクトも用意されており、必要に合わせて使い分けることもできる。
種類 | 概要 |
---|---|
EvalError | グローバル関数eval() に関連して発生するエラーを表すインスタンスを作成。 |
RangeError | 数値変数またはパラメーターが有効な範囲を外れたときに発生するエラーを表すインスタンスを作成。 |
ReferenceError | 無効な参照を解除したときに発生するエラーを表すインスタンスを作成。 |
SyntaxError | 構文エラーを表すインスタンスを作成。 |
TypeError | 変数またはパラメーターが有効な型ではないときに発生するエラーを表すインスタンスを作成。 |
URIError | encodeURI() またはdecodeURI() に無効なパラメーターが渡されたときに発生するエラーを表すインスタンスを作成。 |
AggregateError | 複数のエラーを報告する必要がある場合(例: Promise.any() によって複数のエラーが報告される場合)に、複数のエラーを1つのエラーとしてまとめたインスタンスを作成。 |
例外処理の注意点
try...catch...finally
を使う際に注意したいポイントをまとめる。
tryはcatch、あるいはfinallyとセットで書く
try{}
には、catch{}
あるいはfinally{}
とセットで使う必要がある。try{}
単体で使うと構文エラーとなる。
また、catch
、finally
も単体では使えず、いずれも構文エラーとなるので注意したい。
ちなみにtry{}finally{}
のようにすると、try
とfinally
が処理された後に上位のcatchに処理が移動する。
try/catch/finallyのどれでも値を返せる
try{}
もcatch{}
もfinally
も、値を返すことができる。ただし、各ブロックのreturn
文の有無によって返される値が違ってくるため、注意が必要である。
まず、finally{}
が値を返す場合はその値が優先される。
finally{}
が値を返さない場合、例外が発生しなければtry{}
、発生すればcatch{}
から値が返される。
return
をfinally{}
に書くと混乱の元になりかねないので注意したい。