エラー処理メカニズム

エラーインスタンスオブジェクト

JavaScript の解析または実行時にエラーが発生すると、エンジンはエラー オブジェクトをスローします。 JavaScript はネイティブで「Error」コンストラクターを提供しており、スローされるすべてのエラーはこのコンストラクターのインスタンスです。

var err = new Error('エラーが発生しました');
err.message // 「エラーが発生しました」

上記のコードでは、Error() コンストラクターを呼び出して、インスタンス オブジェクト err を生成します。 Error() コンストラクターは、インスタンスの message 属性から読み取ることができるエラー メッセージを表すパラメーターを受け取ります。 Error インスタンス オブジェクトがスローされた後、プログラム全体はエラーが発生した場所で中断され、実行を続行できなくなります。

JavaScript 言語標準では、Error インスタンス オブジェクトには、エラー発生時のプロンプト メッセージを表す message 属性が必要であることのみが記載されており、他の属性については言及されていません。ほとんどの JavaScript エンジンは、「Error」インスタンスの「name」属性と「stack」属性も提供します。これらはそれぞれエラーの名前とエラー スタックの名前を表しますが、これらは非標準であり、すべての実装で利用できるわけではありません。

  • メッセージ: エラーメッセージ
  • 名前: 間違った名前 (非標準属性)
  • スタック: 間違ったスタック (非標準プロパティ)

name プロパティと message プロパティを使用すると、どのようなエラーが発生したかの大まかなアイデアを得ることができます。

if (エラー名) {
  console.log(error.name + ': ' + error.message);
}

stack 属性は、エラーが発生したときのスタックを表示するために使用されます。

関数 throwit() {
  新しいエラー('')をスローします;
}

関数 catchit() {
  試す {
    スローイット();
  } キャッチ(e) {
    console.log(e.stack); // スタックトレースを出力します。
  }
}

キャッチイット()
// エラー
// throwit で (~/examples/throwcatch.js:9:11)
// catchit で (~/examples/throwcatch.js:3:9)
// repl:1:5 で

上記のコードでは、エラー スタックの最も内側の層は throwit 関数、次に catchit 関数、そして最後に関数の実行環境です。

ネイティブエラータイプ

Error インスタンス オブジェクトは最も一般的なエラー タイプであり、これに基づいて JavaScript は他の 6 つのエラー オブジェクトも定義します。つまり、「Error」の派生オブジェクトは6つあります。

SyntaxError オブジェクト

SyntaxError オブジェクトは、コードを解析するときに発生する構文エラーです。

//変数名が間違っています
変数1a;
// キャッチされない SyntaxError: 無効なトークンまたは予期しないトークンです

// 括弧がありません
console.log 'こんにちは');
// キャッチされない SyntaxError: 予期しない文字列

上記のコードのエラーは構文解析段階で見つかる可能性があるため、SyntaxError がスローされます。最初のエラー メッセージは「トークンが不正です」で、2 番目のエラー メッセージは「文字列が要件を満たしていません」です。

ReferenceError オブジェクト

ReferenceError オブジェクトは、存在しない変数が参照されたときに発生するエラーです。

// 存在しない変数を使用します
未知の変数
// キャッチされない参照エラー: 不明な変数が定義されていません

別のトリガー シナリオは、関数の結果の割り当てなど、割り当てることができないオブジェクトに値を割り当てることです。

// 等号の左側は変数ではありません
console.log() = 1
// キャッチされない ReferenceError: 代入の左側が無効です

上記のコードは関数 console.log の実行結果に値を代入しており、その結果により ReferenceError エラーが発生します。

RangeError オブジェクト

RangeError オブジェクトは、値が有効範囲を超えたときに発生するエラーです。主な状況はいくつかあります。1 つは配列の長さが負の数である場合、もう 1 つは Number オブジェクトのメソッド パラメーターが範囲外であり、関数スタックが最大値を超えている場合です。

// 配列の長さを負にすることはできません
新しい配列(-1)
// キャッチされない RangeError: 配列の長さが無効です

TypeError オブジェクト

TypeError オブジェクトは、変数またはパラメータが予期された型ではない場合に発生するエラーです。たとえば、文字列、ブール値、数値などのプリミティブ型に対して new コマンドを使用すると、new コマンドのパラメータはコンストラクターである必要があるため、このエラーがスローされます。

新しい123
// キャッチされない TypeError: 123 はコンストラクターではありません

var obj = {};
obj.unknownMethod()
// キャッチされない TypeError: obj.unknownMethod は関数ではありません

上記のコードの 2 番目のケースでは、オブジェクトに存在しないメソッドを呼び出すと、「obj.unknownMethod」の値が関数ではなく「未定義」であるため、「TypeError」エラーもスローされます。

URIError オブジェクト

URIError オブジェクトは、主に encodeURI()decodeURI()encodeURIComponent()decodeURIComponent()escape() に関連する、URI 関連関数のパラメータが正しくないときにスローされるエラーです。 unescape() これら 6 つの関数。

decodeURI('%2')
// URIError: URI の形式が正しくありません

EvalError オブジェクト

eval関数が正しく実行されなかった場合、EvalErrorがスローされます。このエラー タイプは現在使用されておらず、以前のコードとの互換性を確保するためにのみ残されています。

要約

上記の 6 つの派生エラーは、元の Error オブジェクトとともに、すべてコンストラクターです。開発者はこれらを使用して、エラー オブジェクトのインスタンスを手動で生成できます。これらの各コンストラクターは、エラー メッセージを表すパラメーターを受け取ります。

var err1 = new Error('エラーが発生しました!');
var err2 = new RangeError('エラーが発生しました。変数が有効な範囲を超えています!');
var err3 = new TypeError('エラーが発生しました。変数の型が無効です!');

err1.message // 「エラーが発生しました!」
err2.message // 「エラーが発生しました。変数が有効な範囲を超えています!」
err3.message // "エラーが発生しました。変数の型が無効です。"

カスタムエラー

JavaScript によってネイティブに提供される 7 つのエラー オブジェクトに加えて、独自のエラー オブジェクトを定義することもできます。

関数 UserError(メッセージ) {
  this.message = メッセージ || 'デフォルトのメッセージ';
  this.name = 'ユーザーエラー';
}

UserError.prototype = 新しいエラー();
UserError.prototype.constructor = UserError;

上記のコードは、エラー オブジェクト UserError をカスタマイズし、Error オブジェクトを継承させます。その後、このカスタム タイプのエラーを生成できます。

new UserError('これはカスタム エラーです!');

ステートメントをスローします

throw ステートメントの目的は、プログラムの実行を手動で中断し、エラーをスローすることです。

var x = -1;

if (x <= 0) {
  throw new Error('x は正の数でなければなりません');
}
// キャッチされないエラー: x は正の値でなければなりません

上記のコードでは、変数 x0 以下の場合、手動でエラーをスローして x の値が正しくないことをユーザーに伝え、プログラム全体がここで実行を中断します。ご覧のとおり、throw によってスローされるエラーはそのパラメータであり、Error オブジェクトのインスタンスです。

「throw」はカスタム エラーをスローすることもできます。

関数 UserError(メッセージ) {
  this.message = メッセージ || 'デフォルトのメッセージ';
  this.name = 'ユーザーエラー';
}

throw new UserError('何か問題が発生しました!');
// 捕捉されない UserError {メッセージ: "エラーが発生しました!"、名前: "UserError"}

上記のコードでは、throwUserError インスタンスをスローします。

実際、「throw」はあらゆるタイプの値をスローできます。つまり、パラメータには任意の値を指定できます。

// 文字列を投げる
「エラー!」をスローします。 ';
// キャッチされないエラー!

// 値をスローする
42をスローします。
//捕まらない 42

// ブール値をスローします
true をスローします。
// 捕捉されていない真

// オブジェクトを投げる
投げる {
  toString: function () {
    「エラー!」を返します。
  }
};
// 捕捉されない {toString: ƒ}

JavaScript エンジンの場合、プログラムは「throw」ステートメントに遭遇すると終了します。エンジンは、「throw」によってスローされた情報を受け取ります。これは、エラー インスタンスまたは他のタイプの値である可能性があります。

試してみて...構造体をキャッチ

エラーが発生すると、プログラムは実行を終了します。 JavaScript は「try...catch」構造を提供しており、これによりエラーを処理したり、実行を継続するかどうかを決定したりできます。

試す {
  throw new Error('エラーが発生しました!');
} キャッチ (e) {
  console.log(e.name + ": " + e.message);
  console.log(e.stack);
}
// エラー: 何か問題が発生しました!
// <匿名>:3:9 で
// ...

上記のコードでは、「try」コード ブロックがエラーをスローし(上の例では「throw」ステートメントを使用しています)、JavaScript エンジンがコードの実行をすぐに「catch」コード ブロックに切り替えます。そうでない場合、エラーはブロックされます。 「catch」コードブロックによってキャプチャされます。 catch は、try コード ブロックによってスローされた値を表すパラメータを受け取ります。

特定のコードがエラーを報告するかどうかわからない場合は、そのコードを「try...catch」コード ブロックに配置して、さらなるエラー処理を容易にすることができます。

試す {
  f();
} キャッチ(e) {
  // エラーを処理します
}

上記のコードでは、関数 f が実行中にエラーを報告すると、catch コード ブロックが実行され、その後エラーが処理されます。

「catch」コード ブロックがエラーをキャッチした後、プログラムは中断されず、通常のフローに従って実行を続けます。

試す {
  throw "エラーが発生しました";
} キャッチ (e) {
  コンソール.ログ(111);
}
コンソール.ログ(222);
// 111
// 222

上記のコードでは、「try」コード ブロックによってスローされたエラーは「catch」コード ブロックによってキャッチされ、プログラムは下方向に実行を続けます。

catch コード ブロック内でエラーをスローしたり、ネストされた try...catch 構造を使用したりすることもできます。

var n = 100;

試す {
  nを投げます。
} キャッチ (e) {
  if (e <= 50) {
    // ...
  } それ以外 {
    eを投げます。
  }
}
//未捕獲 100

上記のコードでは、「catch」コードで別のエラーがスローされます。

さまざまな種類のエラーをキャッチするために、「catch」コード ブロックに判定ステートメントを追加できます。

試す {
  foo.bar();
} キャッチ (e) {
  if (e インスタンスの EvalError) {
    console.log(e.name + ": " + e.message);
  else if (e インスタンスof RangeError) {
    console.log(e.name + ": " + e.message);
  }
  // ...
}

上記のコードでは、catch がエラーをキャプチャした後、エラーの種類 (EvalError または RangeError) を判断し、別の処理を実行します。

最後にコードブロック

try...catch 構造では、最後に finally コード ブロックを追加でき、エラーが発生するかどうかに関係なく、最後にステートメントを実行する必要があることを示します。

関数 cleansUp() {
  試す {
    throw new Error('何か問題が発生しました...');
    console.log('この行は実行されません');
  } ついに {
    console.log('クリーニング作業を完了しました');
  }
}

クリーンアップ()
// クリーンアップ作業を完了する
// キャッチされないエラー: 何か問題が発生しました...
// cleansUp で (<匿名>:3:11)
// <匿名>:10:1 に

上記のコードには「catch」ステートメント ブロックがないため、エラーが発生するとコードは実行を中断します。実行を中断する前に、「finally」コード ブロックが最初に実行され、その後、ユーザーにエラー メッセージが表示されます。

関数アイドル(x) {
  試す {
    コンソール.ログ(x);
    「結果」を返します。
  } ついに {
    console.log('FINALLY');
  }
}

アイドル('こんにちは')
// こんにちは
// ついに

上記のコードでは、「try」コード ブロックではエラーは発生せず、「return」ステートメントも含まれていますが、「finally」コード ブロックは引き続き実行されます。また、この関数の戻り値は result のままです。

次の例は、「return」ステートメントの実行が「finally」コードの前にランク付けされ、「finally」コードの実行が完了した後にのみ戻ることを示しています。

変数カウント = 0;
関数 countUp() {
  試す {
    戻り数;
  } ついに {
    カウント++;
  }
}

countUp()
// 0
カウント
// 1

上記のコードは、「finally」コード ブロックが実行される前に、「return」ステートメントの「count」の値が取得されることを示しています。

以下は、「finally」コード ブロックを使用する一般的なシナリオです。

openFile();

試す {
  writeFile(データ);
} キャッチ(e) {
  ハンドルエラー(e);
} ついに {
  closeFile();
}

上記のコードは、まずファイルを開き、次に「try」コード ブロックでファイルに書き込みます。エラーが発生しない場合は、「finally」コード ブロックが実行されてファイルが閉じられます。ブロックは最初にエラーを処理するために使用され、次に finally ブロックを使用してファイルを閉じます。

次の例は、3 つの try...catch...finally 間の実行シーケンスを完全に反映しています。

関数 f() {
  試す {
    コンソール.ログ(0);
    「バグ」をスローします。
  } キャッチ(e) {
    コンソール.ログ(1);
    return true; // この文は本来、実行前にfinallyコードブロックの終わりまで遅延されます。
    console.log(2); // 実行されません
  } ついに {
    コンソール.ログ(3);
    return false; // この文は前の文を上書きします。
    console.log(4); // 実行されません
  }

  console.log(5); // 実行されません
}

var 結果 = f();
// 0
// 1
// 3

結果
// 間違い

上記のコードでは、「catch」コード ブロックが実行を終了する前に、「finally」コード ブロックが最初に実行されます。

catch コード ブロックでは、finally コード ブロックへの転送をトリガーするフラグには、return ステートメントだけでなく、throw ステートメントも含まれます。

関数 f() {
  試す {
    「何か問題が発生しました!」を投げます。 ';
  } キャッチ(e) {
    console.log('内部エラーをキャッチしました');
    throw e; // この文は本来、最終的に終了するまで待ってから実行します。
  } ついに {
    return false; // 直接返す
  }
}

試す {
  f();
} キャッチ(e) {
  // ここでは実行されません
  console.log('外側の「偽物」をキャッチ');
}

//内部エラーをキャッチ

上記のコードでは、「catch」コードブロックに入った後、「throw」ステートメントに遭遇するとすぐに「finally」コードブロックが実行され、その中に「return false」ステートメントがあるので戻ります。直接実行され、コード ブロックの残りの `catch を実行する必要はなくなります。

「try」コード ブロック内で、「try」コード ブロックを再度使用することもできます。

試す {
  試す {
    consle.log('Hello world!'); // エラーレポート
  }
  ついに {
    console.log('ついに');
  }
  console.log('実行しますか?');
キャッチ(エラー) {
  console.error(error.message);
}
// ついに
// コンソールが定義されていません

上記のコードでは、「try」の中に別の「try」があります。内側の try はエラーを報告します (console のスペルが間違っています)。このとき、内側の finally コード ブロックが実行され、エラーがスローされ、外側の catch によって捕捉されます。

リファレンス接続


作者: wangdoc

アドレス: https://wangdoc.com/

ライセンス: クリエイティブ・コモンズ 3.0