我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
当前回答
正如其他人所说,在Node中,这很简单:
class DumbError extends Error {
constructor(foo = 'bar', ...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DumbError);
}
this.name = 'DumbError';
this.foo = foo;
this.date = new Date();
}
}
try {
let x = 3;
if (x < 10) {
throw new DumbError();
}
} catch (error) {
console.log(error);
}
其他回答
我会退一步考虑你为什么要这么做?我认为关键是要以不同的方式处理不同的错误。
例如,在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
}
在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__属性已弃用,该属性在其他答案中广泛使用。
Error对象拥有的唯一标准字段是message属性。(参见MDN或EcmaScript语言规范,第15.11节)其他一切都是特定于平台的。
大多数环境都设置了堆栈属性,但是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
您可以嗅探堆栈,从堆栈中移除不需要的元素,并提取文件名和lineNumber等信息,但这样做需要有关JavaScript当前运行的平台的信息。大多数情况下,这是不必要的——如果你真的想,你可以在事后进行分析。
Safari是个明显的例外。没有堆栈属性,但是throw关键字设置了被抛出对象的sourceURL和line属性。这些东西肯定是正确的。
我使用的测试用例可以在这里找到:JavaScript自制错误对象比较。
因为JavaScript异常很难子类化,所以我不子类化。我只是创建了一个新的Exception类,并在其中使用一个Error。我修改了Error.name属性,使它看起来像我在控制台上的自定义异常:
var InvalidInputError = function(message) {
var error = new Error(message);
error.name = 'InvalidInputError';
return error;
};
上面的new异常可以像普通的Error一样被抛出,它会像预期的那样工作,例如:
throw new InvalidInputError("Input must be a string");
// Output: Uncaught InvalidInputError: Input must be a string
注意:堆栈跟踪并不是完美的,因为它只会把你带到创建新错误的地方,而不是你抛出错误的地方。这在Chrome上不是什么大问题,因为它直接在控制台中为您提供了完整的堆栈跟踪。但在Firefox上问题就更多了。
正如其他人所说,在Node中,这很简单:
class DumbError extends Error {
constructor(foo = 'bar', ...params) {
super(...params);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DumbError);
}
this.name = 'DumbError';
this.foo = foo;
this.date = new Date();
}
}
try {
let x = 3;
if (x < 10) {
throw new DumbError();
}
} catch (error) {
console.log(error);
}