6.4 例外処理、残余引数

(1/1)
倒れるプログラムのキャラクター
JavaScriptでは、プログラムがエラーなど想定外の動作をしたときに例外を発生させる機能を備えている。この例外をキャッチし、適切にエラー処理することで、プログラムを停止させずに運用することができる。
ここでは、「6.3 consoleオブジェクト」で作った1ヵ月カレンダーにデバッグ機能を追加してみる。

目次

サンプル・プログラムを実行する

サンプル・プログラム

圧縮ファイルの内容
monthlyCalendar5.html1ヵ月カレンダー(例外処理)
Date3.jsDate3クラス
monthlyCalendar5.html 更新履歴
バージョン 更新日 内容
1.3.0 2023/08/15 制御構造の見直し
1.2.0 2023/08/15 変数名,メソッド名の見直し
1.0 2021/08/22 初版
Date3.js 更新履歴
バージョン 更新日 内容
1.1.0 2023/08/15 メソッド名の見直し
1.0 2021/08/22 初版

throw文

  12: class Date3 extends Date {
  13: 
  14: /**
  15:  * コンストラクタ(オーバーライド)
  16:  * @param   String text テキスト
  17:  * @return  なし
  18: */
  19: constructor(...args) {
  20:     let dt = super(...args);        //残余引数
  21:     //例外を発生させる
  22:     if (isNaN(dt)) {
  23:         throw 'Date3: parameter invalid';
  24:     }

Dateオブジェクトは、ありえない年月日を指定すると、NaN が戻ってくるだけで例外は発生しない。
そこで、「6.3 consoleオブジェクト」で Dateオブジェクトを継承して作った Date2クラスを改良し、ありえない年月日を指定すると例外を発生させる Date3クラス を新たに作る。

constructor をオーバーライドし、super の戻り値が NaN のときに throw文を使って例外を発生させる。

ここで、Dateオブジェクト の引数は様々な形をとり、数も一定していないことを思い出してほしい。各々の場合に対してオーバーライドするのは手間なので、残余引数という仕組みを使って super に引数を渡している。
残余引数の使い方だが、最後の引数に ... という接頭辞を付けると、その接頭辞が付いた変数が配列となり、引数を受け取ることができる。
ここでは ...argsDateオブジェクトに渡された全ての引数を配列として格納し、super の引数として渡している。

try~catch文

 136:     try {
 137:         //Date3オブジェクト
 138:         dt3 = new Date3(year.toString() + '-' + month.toString() + '-01 00:00:00');
 139:         console.log('dt3 = %o', dt3);
 140:     //例外処理
 141:     } catch(error) {
 142:         //ログ出力
 143:         console.warn(error);
 144:         //本日の年月に代入し直す
 145:         dt3 = new Date3();
 146:         dt3.setDate(1);
 147:         year  = dt3.getFullYear();
 148:         month = dt3.getMonth() + 1;
 149:         document.getElementById('year').value  = year;
 150:         document.getElementById('month').value = month;
 151:         //エラーを表示
 152:         document.getElementById('error').innerHTML = '警告:本日の年月を代入しました.';
 153:     }

try~catch文で例外処理を行う。
try文には、例外を発生させる可能性のある式を入れておく。
try文で例外が発生したら、catch文を実行する。errorにはエラー・オブジェクト(throw文のメッセージ)が格納されている。
まず、errorをデバッグコンソールに表示する。
次に、本日の年月を代入し直すことでプログラムを継続するようにする。

月に13を代入したときの動作は下図のようになる。
例外処理

コラム:システムの対障害設計

エラーの警告が出たスマホ・タブレットのイラスト
ちょっとしたツール・プログラムであれば、エラーが発生したらexitするなりabortするなりで終わらせてもいいが、大規模システムではそうも行かない。例外が発生したとき、それをどう料理するかが問われる。

例外などの何らかの障害が発生したとき、システムの機能を縮小せずに稼動継続させる設計がフォールトレラント(Fault Tolerant)である。try~catch文で言えば、どんな例外もcatchして、適切に処理しなければいけない。
障害が発生したとき、機能を縮小してでも稼動継続させる設計がフェールソフト(Fail Soft)だ。これはこれで、catchの処理が難しい。
自動的に予備システムに切り替えるフェールオーバー(Fail Over)、安全にシステムを停止するフェールセーフ(Fail Safe)という設計もある。

また、ユーザーが誤って操作して例外が発生しても、安全にシステム稼働を続けるフールプルーフ(Fool Proof)という設計もある。バリデーションと例外をうまく組み合わせて実装する必要がある。

ただし、例外を想定できるのは設定工程である。そして、例外処理すべきかどうかは、要件定義(要求仕様)と見比べて判断する。
近年、早く製品を世に出すためにアジャイルスパイラルといった開発手法が流行っているが、例外処理が十分でない設計の状態でコーディングを始めてしまうと、あとで例外処理を加えるというのは、なかなか手間がかかる。
エラー処理や例外処理の設計まではウォーターフォール方式で開発してはどうだろうか。
(この項おわり)
header