我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
当前回答
正确的方法是从构造函数返回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()的第二行??)
其他回答
除了标准的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(见浏览器兼容性版本)
正确的方法是从构造函数返回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()的第二行??)
为了避免针对每种不同类型的错误的样板文件,我将一些解决方案的智慧结合到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';
});
我的解决方案比其他提供的答案更简单,也没有缺点。
它保留了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;
};
就像有些人说的,ES6很简单:
class CustomError extends Error { }
所以我在我的应用程序(Angular, Typescript)中尝试了这个,但它不起作用。经过一段时间后,我发现问题来自Typescript:O
参见https://github.com/Microsoft/TypeScript/issues/13965
这很令人不安,因为如果你这样做:
class CustomError extends Error {}
try {
throw new CustomError()
} catch(e) {
if (e instanceof CustomError) {
console.log('Custom error');
} else {
console.log('Basic error');
}
}
在节点中或直接在浏览器中显示:自定义错误
尝试在你的项目中使用Typescript在Typescript游乐场上运行,它会显示基本错误…
解决方法如下:
class CustomError extends Error {
// we have to do the following because of: https://github.com/Microsoft/TypeScript/issues/13965
// otherwise we cannot use instanceof later to catch a given type
public __proto__: Error;
constructor(message?: string) {
const trueProto = new.target.prototype;
super(message);
this.__proto__ = trueProto;
}
}