例外処理のブラウザ挙動/実装演習

例外処理を含む関数では、どこで処理が止まり、どの結果を持って外側へ出るかが重要です。入れ子、return、可変オブジェクト、ループ制御を組み合わせ、処理順を追跡します。

この単元で学ぶこと

  • finally前後の戻り値を値と参照で区別する
  • 入れ子の例外と再throwの伝播順を求める
  • break・continueを含むfinallyの実行を判定する

本文解説

処理済みの変更は残る let x=0;try{x=2;JSON.parse("bad");x=4;}catch(e){x+=3;}では最後は5です。解析失敗でx=4は飛ばしますが、先に行ったx=2は残ります。tryを失敗したトランザクションのように一括で巻き戻す規則はありません。どの行まで実行済みかを明示してからcatchの更新を加えます。

return値は先に評価する function f(){let x=1;try{return x;}finally{x=9;}}は1を返します。returnの式xを評価した時点で数値1が決まっているためです。finally後にreturn xの式へ戻って9を読み直しません。finallyが値を変えているように見える場合も、返す値そのものを変更する操作かを見分けます。

オブジェクトの戻り値は参照 const x={n:1};をreturn xで返し、finallyでx.n=9にすると呼出し元から見えるnは9です。返す参照は同じままでも、その参照先の内容を変更しています。数値変数への再代入とは異なります。finallyで新しいオブジェクトをローカル変数へ代入した場合と、元のオブジェクトを編集する場合も区別します。

finallyがthrowした場合 try{return "A";}finally{throw new Error("B");}なら元のreturnは実行結果として外へ出ず、Bの例外が伝播します。console.log(f())ではfの評価が失敗するのでAの表示もありません。finally自身の異常が元の問題を隠す可能性があるため、後片付けの失敗をどう扱うかも設計上の判断になります。

内側から外側へ抜ける 内側tryがAをthrowし、内側finallyでFを表示し、外側catchでmessageを表示するならF、Aです。内側catchが新たにBをthrowすればF、Bになります。各段階で「保留中の結果はreturnかthrowか、値は何か」を一つ保持し、finallyが正常ならそれを外側へ運びます。

ループを抜ける前のfinally forのtry内でcontinueやbreakを実行しても、そのtryに対応するfinallyを先に通ります。i=0,1,2のループでi=1だけcount+=10をcontinueで飛ばし、finallyで毎回count++するなら合計23です。10を加える回数2と、finallyの回数3を別に数えると検算できます。

失敗した操作を正確に特定する JSON.parse("null")はJSONの値nullへ正常に変換されます。その結果へ.xとアクセスしたときにTypeErrorです。JSON.parse("bad")なら解析自体がSyntaxErrorです。両方にJSON.parseという語があっても、どの式まで成功したかで種類が違います。catchする型を選ぶときも操作単位で追跡します。

捕捉後の責任を明確にする catchでreturnした場合もfinallyの後にその値を返します。一方catchで別のRangeErrorをthrowすれば元の例外は置き換わり、外側に捕捉がなければそこで終了します。catchの仮引数は局所的な束縛で、同名の外側変数を自動で書き換えません。例外の種類、保持する情報、続行可能な状態を意識してcatchの処理を選びます。

図解

finallyと戻り値の二つの例
返す値の決定と、参照先の内容変更を区別する。

重要ポイント

  • return式の評価と関数の終了の間にfinallyが入る。
  • 参照先の編集は呼出し元からも見える。
  • 内側finallyは外側catchより先に通る。
  • continue/breakでもfinallyを通る。

間違えやすい点

  • すべてのJSON関連エラーをSyntaxErrorにしない。
  • 例外の元の型が再throw後も変わらないと思わない。
  • finallyでの変数代入と参照先の編集を混同しない。

用語解説

保留中の結果
finallyに入る前に決まっているreturnやthrowなど、外側へ伝える予定の処理結果。
再throw
catchした値又は別の例外を、throwでさらに外側へ伝えること。
局所的な束縛
catchの仮引数など、限られたスコープ内で使える変数名と値の対応。

関連教材

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。