JavaScriptのエラー処理と例外

概要

プログラミングにおいてエラー処理は非常に重要です。この章では、JavaScriptでのエラーの捕捉と処理の方法、カスタムエラーの作成について学びます。

目次

  1. try...catch ステートメント
  2. エラーオブジェクト
  3. finallyブロック
  4. カスタムエラーの作成
  5. エラーの伝播
  6. ベストプラクティス

1. try...catch ステートメント

try...catchステートメントを使用して、エラーが発生する可能性のあるコードをテストし、エラーを捕捉します。

try {
  // エラーが発生する可能性のあるコード
  throw new Error("何か問題が発生しました");
} catch (error) {
  // エラー処理
  console.error(error.message); // "何か問題が発生しました"
}

2. エラーオブジェクト

JavaScriptのエラーオブジェクトには、エラーに関する情報が含まれます。最も一般的なプロパティはmessagenameです。

try {
  throw new Error("カスタムエラー");
} catch (error) {
  console.log(error.name); // "Error"
  console.log(error.message); // "カスタムエラー"
}

3. finallyブロック

finallyブロックは、エラーの有無にかかわらず、try...catchの後に必ず実行されます。

try {
  // エラーが発生する可能性のあるコード
} catch (error) {
  // エラー処理
} finally {
  // 最終的な処理
  console.log("終了処理");
}

4. カスタムエラーの作成

Errorオブジェクトを拡張してカスタムエラーを作成することができます。

class CustomError extends Error {
  constructor(message) {
    super(message);
    this.name = "CustomError";
  }
}

try {
  throw new CustomError("カスタムエラー発生");
} catch (error) {
  console.log(error.name); // "CustomError"
  console.log(error.message); // "カスタムエラー発生"
}

5. エラーの伝播

エラーは捕捉されない限り、呼び出しスタックを通じて伝播します。これは時にエラーの原因を特定するのに役立ちます。

エラー伝播の基本的な考え方は、関数から発生したエラーが、その関数を呼び出した場所へと伝わっていくというものです。これを捕捉(catch)しなければ、エラーはさらに上のレベルへと伝わり、最終的にはグローバルスコープに達し、プログラムが停止する可能性があります。

以下のコード例では、functionAfunctionB を呼び出し、functionBfunctionC を呼び出します。functionC でエラーが発生し、それが捕捉されない場合の伝播の様子を示しています。

function functionC() {
  // ここでエラーを発生させます
  throw new Error('エラーがfunctionCで発生しました');
}

function functionB() {
  // functionCを呼び出します
  functionC();
}

function functionA() {
  // functionBを呼び出します
  functionB();
}

try {
  // functionAを呼び出します。これが最初のエントリーポイントです。
  functionA();
} catch (error) {
  // エラーがここで捕捉されます。
  console.error('捕捉されたエラー: ', error.message);
}

このコードでは、functionC で発生したエラーが functionB を通じて functionA へと伝わり、最終的にトップレベルの try-catch ブロックによって捕捉されます。これにより、エラーがどの関数で発生したかを追跡しやすくなり、デバッグが容易になります。エラーを捕捉しない場合、プログラムは予期せず終了する可能性があります。そのため、特に外部リソースへのアクセスやユーザー入力の処理など、エラーが発生しやすい操作を行う際には、適切にエラーを捕捉し、処理することが重要です。

次にfunctionB でエラーを捕捉し、それを処理する方法を示すコード例を以下に示します。この方法では、エラーが functionC で発生したときに、それを functionB 内で捕捉し、適切に処理することができます。これにより、エラーがさらに上位のレベルへと伝播するのを防ぎます。

function functionC() {
  // ここでエラーを発生させます
  throw new Error('エラーがfunctionCで発生しました');
}

function functionB() {
  try {
    // functionCを呼び出します
    functionC();
  } catch (error) {
    // functionB内でエラーを捕捉します
    console.error('functionB内でエラーが捕捉されました: ', error.message);
    // 必要に応じて、エラーを再投げるか、特定の処理を行うことができます
    // throw error; // エラーを再投げる場合
  }
}

function functionA() {
  // functionBを呼び出しますが、functionB内でエラーが処理されるため、ここでは特にエラー処理を行いません
  functionB();
}

try {
  // functionAを呼び出します。これが最初のエントリーポイントです。
  functionA();
} catch (error) {
  // functionBでエラーが再投げられた場合、ここで捕捉します
  console.error('トップレベルでエラーが捕捉されました: ', error.message);
}

このコードでは、functionC で発生したエラーが functionB 内の try-catch ブロックによって捕捉されます。これにより、functionB はエラーをログに記録し、その後の処理を決定することができます。例えば、エラーに応じて異なる処理を行ったり、エラーを再投げてさらに上位のレベルで処理を行ったりすることが可能です。この方法により、エラーの処理をより柔軟に行うことができ、アプリケーションの安定性とメンテナンス性を向上させることができます。エラー処理の適切な場所を選択することで、プログラムの挙動をより正確に制御することが可能になります。

6. ベストプラクティス

  • エラーを適切に捕捉し、処理する。
  • 予期しないエラーに対処するためのデフォルトのエラーハンドリング戦略を持つ。
  • 不必要にエラーを抑制しない。