我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
当前回答
为了避免针对每种不同类型的错误的样板文件,我将一些解决方案的智慧结合到createErrorType函数中:
function createErrorType(name, init) {
function E(message) {
if (!Error.captureStackTrace)
this.stack = (new Error()).stack;
else
Error.captureStackTrace(this, this.constructor);
this.message = message;
init && init.apply(this, arguments);
}
E.prototype = new Error();
E.prototype.name = name;
E.prototype.constructor = E;
return E;
}
然后,您可以轻松地定义新的错误类型,如下所示:
var NameError = createErrorType('NameError', function (name, invalidChar) {
this.message = 'The name ' + name + ' may not contain ' + invalidChar;
});
var UnboundError = createErrorType('UnboundError', function (variableName) {
this.message = 'Variable ' + variableName + ' is not bound';
});
其他回答
正确的方法是从构造函数返回apply的结果,以及以通常复杂的javascript方式设置原型:
function MyError() {
var tmp = Error.apply(this, arguments);
tmp.name = this.name = 'MyError'
this.stack = tmp.stack
this.message = tmp.message
return this
}
var IntermediateInheritor = function() {}
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor()
var myError = new MyError("message");
console.log("The message is: '"+myError.message+"'") // The message is: 'message'
console.log(myError instanceof Error) // true
console.log(myError instanceof MyError) // true
console.log(myError.toString()) // MyError: message
console.log(myError.stack) // MyError: message \n
// <stack trace ...>
在这一点上,这种方法唯一的问题(我已经重复了一点)是
除了stack和message之外的属性不包含在MyError和 堆栈跟踪有一个额外的行,这并不是真正必要的。
第一个问题可以通过使用以下回答中的技巧遍历所有不可枚举的error属性来解决:是否可能获得对象的不可枚举继承属性名?,但ie<9不支持。第二个问题可以通过在堆栈跟踪中删除这一行来解决,但我不确定如何安全地做到这一点(可能只是删除e.stack.toString()的第二行??)
我会退一步考虑你为什么要这么做?我认为关键是要以不同的方式处理不同的错误。
例如,在Python中,您可以限制catch语句仅捕获MyValidationError,也许您希望能够在javascript中执行类似的操作。
catch (MyValidationError e) {
....
}
你不能在javascript中这样做。只有一个捕捉块。你应该对错误使用if语句来确定它的类型。
抓住(e) { 如果(isMyValidationError (e)) { ... }其他{ //可能重新抛出? 把e; } }
我想我会抛出一个原始对象,其中包含类型、消息和您认为合适的任何其他属性。
throw { type: "validation", message: "Invalid timestamp" }
当你捕捉到错误时:
catch(e) {
if(e.type === "validation") {
// handle error
}
// re-throw, or whatever else
}
我的解决方案比其他提供的答案更简单,也没有缺点。
它保留了Error原型链和Error上的所有属性,而不需要对它们有具体的了解。它已经在Chrome, Firefox, Node和IE11中进行了测试。
唯一的限制是在调用堆栈的顶部有一个额外的条目。但这很容易被忽视。
下面是一个带有两个自定义参数的例子:
function CustomError(message, param1, param2) {
var err = new Error(message);
Object.setPrototypeOf(err, CustomError.prototype);
err.param1 = param1;
err.param2 = param2;
return err;
}
CustomError.prototype = Object.create(
Error.prototype,
{name: {value: 'CustomError', enumerable: false}}
);
使用示例:
try {
throw new CustomError('Something Unexpected Happened!', 1234, 'neat');
} catch (ex) {
console.log(ex.name); //CustomError
console.log(ex.message); //Something Unexpected Happened!
console.log(ex.param1); //1234
console.log(ex.param2); //neat
console.log(ex.stack); //stacktrace
console.log(ex instanceof Error); //true
console.log(ex instanceof CustomError); //true
}
对于需要setPrototypeOf的polyfil的环境:
Object.setPrototypeOf = Object.setPrototypeOf || function (obj, proto) {
obj.__proto__ = proto;
return obj;
};
在2018年,我认为这是最好的方式;支持IE9+和现代浏览器。
更新:请参阅此测试和repo以了解不同实现的比较。
function CustomError(message) {
Object.defineProperty(this, 'name', {
enumerable: false,
writable: false,
value: 'CustomError'
});
Object.defineProperty(this, 'message', {
enumerable: false,
writable: true,
value: message
});
if (Error.hasOwnProperty('captureStackTrace')) { // V8
Error.captureStackTrace(this, CustomError);
} else {
Object.defineProperty(this, 'stack', {
enumerable: false,
writable: false,
value: (new Error(message)).stack
});
}
}
if (typeof Object.setPrototypeOf === 'function') {
Object.setPrototypeOf(CustomError.prototype, Error.prototype);
} else {
CustomError.prototype = Object.create(Error.prototype, {
constructor: { value: CustomError }
});
}
还要注意__proto__属性已弃用,该属性在其他答案中广泛使用。
除了标准的message属性,JavaScript现在支持将特定的错误原因作为可选参数添加到error构造函数中:
const error1 = new Error('Error one');
const error2 = new Error('Error two', { cause: error1 });
// error2.cause === error1
在节点v16.9.0中提供。 适用于Chrome, Firefox和Safari(见浏览器兼容性版本)