何かを開発するとき、タスクで間違っている可能性のある特定のものを反映するために、独自のエラークラスが必要になることが ネットワーク操作のエラーについては、HttpError
、データベース操作の場合はDbError
、検索操作の場合はNotFoundError
などが必要になる場合があります。
私たちのエラーは、message
、name
、できればstack
のような基本的なエラープロパティをサポートする必要があります。 もしその他の特性、例えば, HttpError
オブジェクトは、statusCode
404
または403
または500
のような値を持つstatusCode
プロパティを持つことができます。
JavaScriptではthrow
を任意の引数で使用できるため、技術的にはカスタムエラークラスはError
から継承する必要はありません。 しかし、継承すると、obj instanceof Error
を使用してエラーオブジェクトを識別できるようになります。 だから、それから継承する方が良いです。
アプリケーションが成長するにつれて、私たち自身のエラーは自然に階層を形成します。, たとえば、HttpTimeoutError
はHttpError
から継承することができます。
拡張エラー
例として、JSONをユーザーデータで読み取る関数readUser(json)
を考えてみましょう。
有効なjson
がどのように見えるかの例を次に示します。
let json = `{ "name": "John", "age": 30 }`;
内部的には、JSON.parse
を使用します。 不正な形式のjson
を受け取った場合、SyntaxError
をスローします。, しかし、たとえjson
構文的に正しい場合でも、それはそれが有効なユーザーであることを意味するものではありませんよね? 必要なデータを見逃すことがあります。 たとえば、ユーザーにとって不可欠なname
およびage
プロパティがない場合があります。
私たちの関数readUser(json)
JSONを読み取るだけでなく、データをチェック(”検証”)します。 必須フィールドがない場合、または形式が間違っている場合、それはエラーです。 そして、データは構文的に正しいので、それはSyntaxError
ではなく、別の種類のエラーです。, これをValidationError
と呼び、そのためのクラスを作成します。 その種のエラーは、問題のあるフィールドに関する情報も運ぶ必要があります。
私たちのValidationError
クラスは、組み込みのError
クラスから継承する必要があります。
そのクラスは組み込まれていますが、拡張しているものを理解できるように、おおよそのコードがあります。
次に、ValidationError
を継承して、実際に試してみましょう。
注意してください:(1)
行では、親コンストラクタを呼び出します。, JavaScriptでは、子コンストラクタでsuper
を呼び出す必要があるため、これは必須です。 親コンストラクターは、message
プロパティを設定します。
親コンストラクタは、name
プロパティを"Error"
に設定するため、(2)
行で正しい値にリセットします。,
readUser(json)
で使用してみましょう:
上記のコードのtry..catch
ブロックは、ValidationError
と組み込みのSyntaxError
JSON.parse
の両方を処理します。
instanceof
行の特定のエラータイプを確認するために(*)
を使用する方法を見てください。,
次のように、err.name
を見ることもできます。
// ...// instead of (err instanceof SyntaxError)} else if (err.name == "SyntaxError") { // (*)// ...
instanceof
バージョンははるかに優れています。2a9eadcca5″>
、PropertyRequiredError
ように、それのサブタイプを作成します。 そして、instanceof
チェックは、新しい継承クラスに対して引き続き機能します。 だから、それは将来の証拠です。また、catch
が不明なエラーを満たしている場合、(**)
行で再スローすることも重要です。, Div id=”c2dfd39931″>
ブロックは、検証と構文エラーの処理方法のみを知っており、他の種類(コード内のタイプミスまたは他の未知のものによる)が落ちる
さらなる継承
ValidationError
クラスは非常に一般的です。 多くのことが間違っています。 プロパティが存在しないか、間違った形式である可能性があります(age
の文字列値のように)。 不在のプロパティのために、より具体的なクラスPropertyRequiredError
を作成しましょう。 それは欠落しているプロパティに関する追加情報を運ぶでしょう。,
新しいクラスPropertyRequiredError
は使いやすいです:プロパティ名を渡す必要があります:new PropertyRequiredError(property)
。 人間が読めるmessage
は、コンストラクタによって生成されます。
this.name
PropertyRequiredError
コンストラクタは再び手動で割り当てられます。 それは少し面倒になるかもしれません–すべてのカスタムエラークラスでthis.name = <class name>
を割り当てます。 割り当てる独自の”基本エラー”クラスを作成することで回避できますthis.name = this.constructor.name
。 そして継承すべての当社のカスタムエラーは後からです。,
それをMyError
と呼びましょう。
MyError
およびその他のカスタムエラークラスを簡略化したコードは次のとおりです。
カスタムエラーは、特にValidationError
、"this.name = ..."
コンストラクタの行。
例外のラッピング
上記のコードの関数readUser
の目的は、”ユーザーデータを読み取る”ことです。 プロセスに異なる種類のエラーが発生する可能性があります。, 現在、SyntaxError
とValidationError
がありますが、将来的にはreadUser
関数が成長し、おそらく他の種類のエラーを生成する可能性があります。
呼び出すコードreadUser
これらのエラーを処理する必要があります。 現在、if
catch
ブロックで複数のif
を使用して、クラスをチェックして既知のエラーを処理し、未知のエラーを再スローします。
スキームは次のようなものです。
上記のコードでは、二つのタイプのエラーを見ることができますが、より多くのエラーがある可能性があります。,
もしreadUser
関数がいくつかの種類のエラーを生成するなら、私たちは自分自身に尋ねるべきです:私たちは本当にすべてのエラータイプを毎回一つずつチェックしたいのでしょうか?
多くの場合、答えは”いいえ”です:私たちは”すべてのことの上に一つのレベル”になりたいと思います。 しか知りたい場合がありました”データの読み取りエラー”–なぜで起こったく無関係のエラーメッセージを記述します。 または、さらに良いことに、エラーの詳細を取得する方法が必要な場合にのみ必要です。
ここで説明するテクニックは、”例外のラッピング”と呼ばれます。,
- 一般的な”データ読み取り”エラーを表すために、新しいクラス
ReadError
を作成します。 - 関数
readUser
は、ValidationError
およびSyntaxError
のように、その内部で発生するデータ読み取りエラーをキャッチし、代わりにReadError
を生成します。li> ReadError
オブジェクトは、元のエラーへの参照をcause
プロパティに保持します。,次に、readUser
を呼び出すコードは、ReadError
をチェックするだけで、あらゆる種類のデータ読み取りエラーではありません。 また、エラーの詳細が必要な場合は、cause
プロパティをチェックできます。,ReadError
を定義し、readUser
およびtry..catch
での使用を示すコードは次のとおりです。上記のコードでは、
readUser
a5f9b1a45a”>
代わりにエラー(未知のエラーはいつものように再スローされます)。したがって、外側のコードはinstanceof ReadError
をチェックし、それだけです。 必要な全ての可能なエラーです。,
このアプローチは、”低レベル”の例外を取り込み、それらをReadError
より抽象的なものに”ラップ”するため、”例外のラップ”と呼ばれます。 で幅広く使用されているオブジェクト指向プログラミング.
Summary
Error
およびその他の組み込みのエラークラスから通常は継承できます。 私たちはちょうど世話をする必要がありますname
プロパティと呼び出すことを忘れないでくださいsuper
。li>- 特定のエラーをチェックするには、
instanceof
を使用できます。 また、継承でも機能します。, しかし、時には3rdパーティライブラリからのエラーオブジェクトがあり、そのクラスを取得する簡単な方法はありません。 その後、name
プロパティは、このようなチェックに使用することができます。関数は低レベルの例外を処理し、さまざまな低レベルの例外の代わりに高レベルのエラーを作成します。 - 例外をラップすることは一般的な手法です。 低レベルの例外は、上記の例では
err.cause
ようにそのオブジェクトのプロパティになることがありますが、厳密には必要ありません。