I want to throw some things in my JS code and I want them to be instanceof Error, but I also want to have them be something else.
In Python, typically, one would subclass Exception.
What's the appropriate thing to do in JS?
I want to throw some things in my JS code and I want them to be instanceof Error, but I also want to have them be something else.
In Python, typically, one would subclass Exception.
What's the appropriate thing to do in JS?
Try:
function MyError() {
Error.apply(this, arguments);
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';
try {
throw new MyError('foo!')
} catch(e) {
alert(e instanceof MyError)
}
Caveats: Type-specific catch
blocks are not part of the ECMA spec. So you only get one catch
within which you can put a bunch of if (error instanceof MyError) else ...
tests. Subclassing Error
may seem sexy in theory, but for said reason quickly falls down in practice.
See also: http://stackoverflow.com/questions/783818/how-do-i-create-a-custom-error-in-javascript: it appears the message
property of the subclass does not get set. Yet another reason to avoid subclassing a built-in.
Crescent Fresh's answer highly-voted answer is misleading. Though his warnings are invalid, there are other limitations that he doesn't address.
First, the reasoning in Crescent's "Caveats:" paragraph doesn't make sense. The explanation implies that coding "a bunch of if (error instanceof MyError) else ..." is somehow burdensome or verbose compared to multiple catch statements. Multiple instanceof statements in a single catch block are just as concise as multiple catch statements-- clean and concise code without any tricks. This is a great way to emulate Java's great throwable-subtype-specific error handling.
WRT "appears the message property of the subclass does not get set", that is not the case if you use a properly constructed Error subclass. To make your own ErrorX Error subclass, just copy the code block beginning with "var MyError =", changing the one word "MyError" to "ErrorX". (If you want to add custom methods to your subclass, follow the sample text).
The real and significant limitation of JavaScript error subclassing is that for JavaScript implementations or debuggers that track and report on stack trace and location-of-instantiation, like FireFox, a location in your own Error subclass implementation will be recorded as the instantiation point of the class, whereas if you used a direct Error, it would be the location where you ran "new Error(...)"). IE users would probably never notice, but users of Fire Bug on FF will see useless file name and line number values reported alongside these Errors, and will have to drill down on the stack trace to element #1 to find the real instantiation location.
In the above example Error.apply
(also Error.call
) doesn't do anything for me (Firefox 3.6/Chrome 5). A workaround I use is:
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';