私たちが普段書いているプログラムでは、何らかの原因によって処理が妨げられることがあります。エラーを起こした際に、プログラムが強制終了されてしまうと、セキュリティやUX(ユーザーエクスペリエンス)などに悪影響を与えてしまうことが考えられます。

そのため、こうした事象をあらかじめ対処するためのプログラムを書くことも大切です。
そこで今回は、JavaScriptの例外処理とエラーオブジェクトについて解説していきます。

例外処理

例外処理とは、プログラムが処理されている最中にエラーを起こした際に、意図的に用意していた処理を実行する手法のことです。エラーハンドリングやエラー処理とも呼ばれています。
事前に例外処理を用意しておくと、不具合が生じた場合にも瞬時に対応ができるようになります。

以下は、JavaScriptで例外処理を行うための構文です。

  • try…catch文
  • throw文

try…catch文

try…catch文は、ある処理に対して、例外が起こった時の処理を行うための構文です。

tryブロック内で例外が発生すると、tryブロック内にあるそれ以降の処理は実行されなくなり、代わりに、catchブロック内で例外が発生した場合の処理を実行します。
また、finallyブロックは、例外の発生の有無に関わらず、必ず最後に処理を実行します。

try {
  実行する処理
} catch(error) {
  例外発生時の処理 
} finally {
  例外の発生に関わらず必ず最後に呼び出される処理
}

catch、またはfinallyのどちらかのブロックがあれば、もう片方のブロックは省略することが可能です。

throw文

throw文は、エラーが起こった際に、自ら定義したオブジェクトを例外として投げるための構文です。
エラーだと認識されたオブジェクトを、エラー処理専門の場所へ届けるイメージです。

投げられるオブジェクトには、文字列、数値、ファンクションなど、プリミティブ型やオブジェクト型が該当します。

throw '文字列';
throw 123;
throw new Error('Errorオブジェクトのインスタンス');

例外として投げられたオブジェクトは、try…catch文のcatchブロックで受け取ることができるようになります。

try {
  // 例外を意図的に投げる
  throw new Error('例外が発生しました');
} catch(error) {
  console.log(error.message);
}
// '例外が発生しました'

エラーオブジェクト

エラーオブジェクトの概念を知っておくことも重要です。
throw文を使ってあらゆるオブジェクトを投げることができますが、通常はエラーオブジェクトを使って例外処理を行うことが一般的だからです。

エラーオブジェクトには以下のような種類があります。

  • Error
  • ReferenceError
  • SyntaxError
  • TypeError など

また、使用できるプロパティも用意されています。

  • nameプロパティ:エラーの種類を参照
  • messageプロパティ:エラーのメッセージを参照

ここでは、最も重要なErrorオブジェクトを中心に解説していきます。

Error

new ErrorでErrorオブジェクトを生成します。

throw文では、あらゆるオブジェクトを例外として投げることができますが、実際にはこのErrorオブジェクトのインスタンスを投げる方法が推奨されています。
理由は、Errorオブジェクトのインスタンスはデバックに役立つ情報を持っており、スタックトレースが取得できるためです。

このように、エラーの種類やメッセージを読み取ることができます。

try {
  throw new Error('文字列');
} catch(error) {
  console.log(error); // Error: 文字列
  console.log(error.name); // 'Error'
  console.log(error.message); // '文字列'
}

一方、throw '文字列'のようにErrorオブジェクトではないオブジェクトを投げる場合は、スタックトレースを行うことができません。

try {
  throw '文字列';
} catch(error) {
  console.log(error); // '文字列'
  console.log(error.name); // undefined
  console.log(error.message); // undefined
}

上記のことから、厳密で正確なエラー処理を行う場合には、Errorオブジェクトを使う方がベターだということが分かります。

ここで補足ですが、「エラーオブジェクト」はエラーの種類全体のことを指し、「Errorオブジェクト」はErrorという名前のエラーオブジェクトのことを指しています。

ビルドインエラー

以下は、先ほど取り上げたErrorオブジェクト以外の代表的なエラーオブジェクトです。

  • ReferenceError:存在しない関数などが参照された際に起こる
  • SyntaxError:プログラムの構文が誤っている際に起こる
  • TypeError:値が期待される型でない際に起こる

普段プログラムを書いていく中で、このようなエラーに遭遇したことがあるかもしれません。
これらはビルドインエラーと呼ばれており、上記で紹介したErrorオブジェクトを継承します。
そのため、これらのエラーが発生した際には、Errorオブジェクトと同じようにプロパティを使うことができます。

try…catch文の中でErrorオブジェクトを使う

例外処理とエラーオブジェクトについて学んだところで、実際にtry…catch文の中でErrorオブジェクトを使ってみましょう。

以下は、郵便番号を示す変数numが数値でなければ例外処理を行う例です。

function myPostalcode(num) {
  if (typeof num !== 'number') {
    throw new Error('郵便番号のフォーマットが異なります');
  } else {
    return num;
  }
}

let num = 'abcdefg';  // 文字列

try {
  console.log(myPostalcode(num));
} catch(error) {
  console.log(error.message);
} finally {
  console.log('処理が完了しました');
}
// '郵便番号のフォーマットが異なります'
// '処理が完了しました'

let num = 'abcdefg'は文字列なので(数値のフォーマットとは異なる)、if文のthrow new ErrorによりErrorオブジェクトが投げられます。
投げられたErrorオブジェクトはcatchブロックで受け取るため、'郵便番号のフォーマットが異なります'と出力されます。
その後finallyブロックに進むと、'処理が完了しました'という出力結果を得られます。

反対に、let num = 1234567のように郵便番号が数値だった場合には、tryブロックからfinallyブロックの処理が行われます。

function myPostalcode(num) {
  if (typeof num !== 'number') {
    throw new Error('郵便番号のフォーマットが異なります');
  } else {
    return num;
  }
}

let num = 1234567; // 数値

try {
  console.log(myPostalcode(num));
} catch(error) {
  console.log(error.message);
} finally {
  console.log('処理が完了しました');
}
// 1234567
// '処理が完了しました'

このように例外処理を用意しておくことで、あらゆるエラーに対応できるようになります。
例えば、通信が途絶えてしまった場合や、誤った情報を入力した場合などの理由から処理が完了しなかった場合に対して、そのことを画面に表示するなどです。

まとめ

今回は、例外処理とエラーオブジェクトについて解説しました。

JavaScriptはシングルスレッドで動いているため、一度エラーが起きてしまうとアプリケーション自体が止まってしまう恐れがあります。
そのため、エラーが起こった際にも適切に対処をし、プログラムが動き続けるようにする必要があります。

安心して利用できるプログラムを作るために、例外処理の理解も深めていきましょう。

エラーオブジェクトの関連記事

JavaScriptで発生するエラー
Console API