throw
try
文Error
およびそのサブクラスError
Error
の組み込みサブクラスError
のサブクラス化error.cause
によるエラーのチェイン [ES2022].cause
の代替: カスタムエラークラスこの章では、JavaScript が例外をどのように処理するかを説明します。
なぜ JavaScript はもっと頻繁に例外をスローしないのですか?
JavaScript は ES3 まで例外をサポートしていませんでした。そのため、言語とその標準ライブラリでは控えめに使用されています。
次のコードを考えてみましょう。ファイルに保存されたプロファイルを、クラス Profile
のインスタンスを持つ配列に読み込みます。
function readProfiles(filePaths) {
const profiles = [];
for (const filePath of filePaths) {
try {
const profile = readOneProfile(filePath);
.push(profile);
profilescatch (err) { // (A)
} console.log('Error in: '+filePath, err);
}
}
}function readOneProfile(filePath) {
const profile = new Profile();
const file = openFile(filePath);
// ··· (Read the data in `file` into `profile`)
return profile;
}function openFile(filePath) {
if (!fs.existsSync(filePath)) {
throw new Error('Could not find file '+filePath); // (B)
}// ··· (Open the file whose path is `filePath`)
}
B 行で何が起こるかを見てみましょう。エラーが発生しましたが、問題を処理するのに最適な場所は現在の場所ではなく、A 行です。そこで、現在のファイルをスキップして次のファイルに進むことができます。
したがって
throw
文を使用して問題が発生したことを示します。try-catch
文を使用して問題を処理します。スローすると、次の構文がアクティブになります。
readProfiles(···)
for (const filePath of filePaths)
try
readOneProfile(···)
openFile(···)
if (!fs.existsSync(filePath))
throw
throw
は、try
文に遭遇するまで、ネストされた構文を 1 つずつ終了します。実行は、その try
文の catch
句で続行されます。
throw
これは throw
文の構文です。
throw «value»;
JavaScript では任意の値をスローできます。ただし、スタックトレースやエラーチェインなどの追加機能をサポートしているため、Error
またはそのサブクラスのインスタンスを使用するのが最適です(§24.4 “Error
およびそのサブクラス”を参照)。
これにより、次のオプションが残ります。
クラス Error
を直接使用します。JavaScript では、インスタンスに独自のプロパティを追加できるため、より静的な言語よりも制約が少なくなります。
const err = new Error('Could not find the file');
.filePath = filePath;
errthrow err;
Error
のサブクラス のいずれかを使用します。
Error
をサブクラス化します(詳細は 後で説明します)。
class MyError extends Error {
}function func() {
throw new MyError('Problem!');
}.throws(
assert=> func(),
() ; MyError)
try
文try
文の最大バージョンは次のようになります。
try {
«try_statements»catch (error) {
}
«catch_statements»finally {
}
«finally_statements» }
これらの句は、次のように組み合わせることができます。
try-catch
try-finally
try-catch-finally
try
ブロックtry
ブロックは、文の本体と見なすことができます。ここで、通常のコードを実行します。
catch
句例外が try
ブロックに到達した場合、その例外は catch
句のパラメータに割り当てられ、その句内のコードが実行されます。次に、実行は通常、try
文の後で続行されます。次の場合は、変更される可能性があります。
catch
ブロック内に return
、break
、または throw
がある場合。finally
句がある場合(try
文が終了する前に常に実行されます)。次のコードは、A 行でスローされた値が実際に B 行でキャッチされることを示しています。
const errorObject = new Error();
function func() {
throw errorObject; // (A)
}
try {
func();
catch (err) { // (B)
} .equal(err, errorObject);
assert }
catch
バインディングの省略 [ES2019]スローされた値に関心がない場合は、catch
パラメータを省略できます。
try {
// ···
catch {
} // ···
}
これは時々役立つことがあります。たとえば、Node.js には、func
内でエラーがスローされるかどうかを確認する API 関数 assert.throws(func)
があります。これは次のように実装できます。
function throws(func) {
try {
func();
catch {
} return; // everything OK
}throw new Error('Function didn’t throw an exception!');
}
ただし、この関数のより完全な実装には、catch
パラメータがあり、たとえば、その型が期待どおりであるかどうかを確認します。
finally
句finally
句内のコードは、try
ブロックまたは catch
句で何が起こっても、try
文の最後に常に実行されます。
finally
の一般的なユースケースを見てみましょう。リソースを作成し、そのリソースの使用が完了したら、そのリソースを常に破棄したいとします。その使用中に何が起こっても構いません。これは次のように実装します。
const resource = createResource();
try {
// Work with `resource`. Errors may be thrown.
finally {
} .destroy();
resource }
finally
は常に実行されるfinally
句は、エラーがスローされた場合でも(A 行)常に実行されます。
let finallyWasExecuted = false;
.throws(
assert=> {
() try {
throw new Error(); // (A)
finally {
} = true;
finallyWasExecuted
},
}Error
;
).equal(finallyWasExecuted, true); assert
そして、return
文がある場合でも(A 行)
let finallyWasExecuted = false;
function func() {
try {
return; // (A)
finally {
} = true;
finallyWasExecuted
}
}func();
.equal(finallyWasExecuted, true); assert
Error
およびそのサブクラスError
は、すべての組み込みエラークラスの共通のスーパー クラスです。
Error
これは、Error
のインスタンスプロパティとコンストラクターがどのように見えるかです。
class Error {
// Instance properties
: string;
message?: any; // ES2022
cause: string; // non-standard but widely supported
stack
constructor(
: string = '',
message?: ErrorOptions // ES2022
options;
)
}interface ErrorOptions {
?: any; // ES2022
cause }
コンストラクターには 2 つのパラメータがあります。
message
はエラーメッセージを指定します。options
は ECMAScript 2022 で導入されました。これには、現在 1 つのプロパティがサポートされているオブジェクトが含まれています。.cause
は、現在のエラーの原因となった例外(もしあれば)を指定します。次のサブセクションでは、インスタンスプロパティ .message
、.cause
、および .stack
について詳しく説明します。
Error.prototype.name
各組み込みエラークラス E
には、プロパティ E.prototype.name
があります。
> Error.prototype.name'Error'
> RangeError.prototype.name'RangeError'
したがって、組み込みエラーオブジェクトのクラス名を取得する方法は 2 つあります。
> new RangeError().name'RangeError'
> new RangeError().constructor.name'RangeError'
.message
.message
にはエラーメッセージのみが含まれます。
const err = new Error('Hello!');
.equal(String(err), 'Error: Hello!');
assert.equal(err.message, 'Hello!'); assert
メッセージを省略すると、空の文字列がデフォルト値として使用されます(Error.prototype.message
から継承されます)。
メッセージを省略すると、空の文字列になります。
.equal(new Error().message, ''); assert
.stack
インスタンスプロパティ .stack
は ECMAScript の機能ではありませんが、JavaScript エンジンで広くサポートされています。通常は文字列ですが、その正確な構造は標準化されておらず、エンジンによって異なります。
これは JavaScript エンジン V8 での表示例です。
const err = new Error('Hello!');
.equal(
assert.stack,
err`
Error: Hello!
at file://ch_exception-handling.mjs:1:13
`.trim());
.cause
[ES2022]インスタンスプロパティ .cause
は、new Error()
の 2 番目のパラメータの options オブジェクトを介して作成されます。これにより、現在のエラーの原因となった他のエラーを指定できます。
const err = new Error('msg', {cause: 'the cause'});
.equal(err.cause, 'the cause'); assert
このプロパティの使用方法については、§24.5 “エラーのチェイン”を参照してください。
Error
の組み込みサブクラスError
には、次のサブクラスがあります – ECMAScript 仕様から引用します。
AggregateError
[ES2021] は、複数のエラーを一度に表します。標準ライブラリでは、Promise.any()
のみが使用します。RangeError
は、値が許可される値のセットまたは範囲にないことを示します。ReferenceError
は、無効な参照値が検出されたことを示します。SyntaxError
は、解析エラーが発生したことを示します。TypeError
は、他の NativeError オブジェクトのいずれも失敗の原因を適切に示すものではない場合に、操作が失敗したことを示すために使用されます。URIError
は、グローバル URI 処理関数のいずれかが、その定義と互換性のない方法で使用されたことを示します。Error
のサブクラス化ECMAScript 2022 以降、Error
コンストラクターは 2 つのパラメータを受け入れます(前のサブセクションを参照)。したがって、それをサブクラス化する際には、2 つの選択肢があります。サブクラスでコンストラクターを省略するか、次のように super()
を呼び出すかです。
class MyCustomError extends Error {
constructor(message, options) {
super(message, options);
// ···
} }
場合によっては、より深くネストされた関数呼び出し中にスローされたエラーをキャッチし、それに追加情報を添付したい場合があります。
function readFiles(filePaths) {
return filePaths.map(
=> {
(filePath) try {
const text = readText(filePath);
const json = JSON.parse(text);
return processJson(json);
catch (error) {
} // (A)
};
}) }
try
句内のステートメントは、あらゆる種類のエラーをスローする可能性があります。ほとんどの場合、エラーはエラーの原因となったファイルのパスを認識しません。そのため、A 行でその情報を添付したいのです。
error.cause
によるエラーのチェイン [ES2022]ECMAScript 2022 以降、new Error()
では、その原因を指定できます。
function readFiles(filePaths) {
return filePaths.map(
=> {
(filePath) try {
// ···
catch (error) {
} throw new Error(
`While processing ${filePath}`,
cause: error}
{;
)
};
}) }
.cause
の代替: カスタムエラークラス次のカスタムエラークラスは、チェインをサポートしています。.cause
と前方互換性があります。
/**
* An error class that supports error chaining.
* If there is built-in support for .cause, it uses it.
* Otherwise, it creates this property itself.
*
* @see https://github.com/tc39/proposal-error-cause
*/
class CausedError extends Error {
constructor(message, options) {
super(message, options);
if (
isObject(options) && 'cause' in options)
(&& !('cause' in this)
) {// .cause was specified but the superconstructor
// did not create an instance property.
const cause = options.cause;
this.cause = cause;
if ('stack' in cause) {
this.stack = this.stack + '\nCAUSE: ' + cause.stack;
}
}
}
}
function isObject(value) {
return value !== null && typeof value === 'object';
}
演習: 例外処理
exercises/exception-handling/call_function_test.mjs
クイズ
クイズアプリを参照してください。