JSコードの中でいくつかのものを投げたいのですが、それらを instanceof Error にしたいのですが、それ以外のものにもしたいのです。
Pythonでは通常、Exceptionをサブクラス化します。
JSではどのようにするのが適切でしょうか?
Errorオブジェクトが持つ唯一の標準的なフィールドは、message
プロパティです。(MDN]1、または EcmaScript Language Specification, section 15.11 を参照してください) ***その他はすべてプラットフォーム固有のものです。
ほとんどの環境では、stack
プロパティが設定されていますが、fileName
やlineNumber
は継承に使うには実質的に無意味です。
ということで、ミニマムなアプローチとしては
function MyError(message) {
this.name = 'MyError';
this.message = message;
this.stack = (new Error()).stack;
}
MyError.prototype = new Error; // <-- remove this if you do not
// want MyError to be instanceof Error
スタックをスニッフィングして、そこから不要な要素を取り除き、fileName や lineNumber のような情報を抽出することもできますが、そうすると JavaScript が現在実行されているプラットフォームに関する情報が必要になります。ほとんどの場合、そのようなことは必要ありません。本当に必要であれば、ポストモーテムで行うことができます。
Safari は注目すべき例外です。stackプロパティはありませんが、
throwキーワードは、スローされるオブジェクトの
sourceURLと
line` プロパティを設定します。これらは正しいことが保証されています。
使用したテストケースはこちらにあります。JavaScript自作エラーオブジェクト比較をご覧ください。
Crescent Freshの回答は、高い評価を得ていますが、誤解を招く恐れがあります。 彼の警告は無効ですが、彼が言及していない他の制限があります。
まず、Crescent's "Caveats:"の段落にある理由は意味をなしません。 この説明では、複数のcatch文と比較して、"たくさんのif (error instanceof MyError) else ..."をコーディングすることは、何らかの負担や冗長性があるとしています。 1つのcatchブロック内の複数のinstanceof文は、複数のcatch文と同じように簡潔で、何のトリックもないすっきりとしたコードになります。 これは、Java'の素晴らしいthrowable-subtype-specificエラー処理を模倣する素晴らしい方法です。
WRT " appear the message property of the subclass doesn't get set", that is not the case if you used a properly constructed Error subclass. 独自のErrorX Errorサブクラスを作るには、"var MyError ="で始まるコードブロックをコピーして、1ワードの"MyError"を"ErrorX"に変更するだけです。 (サブクラスにカスタムメソッドを追加したい場合は、サンプルテキストに従ってください)。
JavaScriptのエラーサブクラス化の本当の意味での大きな制限は、FireFoxのようにスタックトレースやインスタンスの位置を追跡して報告するJavaScriptの実装やデバッガでは、自分のErrorサブクラスの実装の位置がクラスのインスタンス化ポイントとして記録されてしまうことですが、直接Errorを使用した場合は、"new Error(...)")を実行した位置となります。 IEのユーザーはおそらく気づかないでしょうが、FFのFire Bugのユーザーは、これらのエラーと一緒に無駄なファイル名と行番号の値が報告され、本当のインスタンス化の場所を見つけるために、スタックトレースで要素1まで掘り下げなければなりません。
上記の例では、Error.apply
(Error.call
も)は私にとって何もしてくれません(Firefox 3.6/Chrome 5)。私が使っている回避策は
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != 'undefined') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf('\n')+1);
}
else if (typeof(chrome) != 'undefined' || typeof(process) != 'undefined') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\n[^\n]*/,'');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';