我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
当前回答
我会退一步考虑你为什么要这么做?我认为关键是要以不同的方式处理不同的错误。
例如,在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
}
其他回答
我想再补充一下大家已经说过的话:
为了确保自定义错误类在堆栈跟踪中正确显示,您需要将自定义错误类的原型的name属性设置为自定义错误类的name属性。 我的意思是:
CustomError.prototype = Error.prototype;
CustomError.prototype.name = 'CustomError';
完整的例子是:
var CustomError = function(message) {
var err = new Error(message);
err.name = 'CustomError';
this.name = err.name;
this.message = err.message;
//check if there is a stack property supported in browser
if (err.stack) {
this.stack = err.stack;
}
//we should define how our toString function works as this will be used internally
//by the browser's stack trace generation function
this.toString = function() {
return this.name + ': ' + this.message;
};
};
CustomError.prototype = new Error();
CustomError.prototype.name = 'CustomError';
当所有的都说了,做了,你抛出你的新异常,它看起来像这样(我懒惰地尝试在chrome开发工具):
CustomError: Stuff Happened. GASP!
at Error.CustomError (<anonymous>:3:19)
at <anonymous>:2:7
at Object.InjectedScript._evaluateOn (<anonymous>:603:39)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:562:52)
at Object.InjectedScript.evaluate (<anonymous>:481:21)
正如其他人所说,在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);
}
在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__属性已弃用,该属性在其他答案中广泛使用。
编辑:请阅读评论。我的目的是提供一个跨浏览器的解决方案,它可以在所有浏览器中工作,并在支持的地方提供堆栈跟踪。
编辑:我创建这个社区维基是为了允许更多的编辑。
V8 (Chrome / Node.JS)的解决方案,在Firefox中工作,并可以修改为在IE中正常工作。(见文末)
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype // Make this an instanceof Error.
Error.call(this) // Does not seem necessary. Perhaps remove this line?
Error.captureStackTrace(this, this.constructor) // Creates the this.stack getter
this.name = this.constructor.name; // Used to cause messages like "UserError: message" instead of the default "Error: message"
this.message = message; // Used to set the message
}
“让我看看代码!”
短版:
function UserError(message) {
this.constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace(this, this.constructor)
this.name = this.constructor.name
this.message = message
}
我保留这个。构造器。原型。__proto__ =错误。函数中的原型将所有代码保存在一起。但是你也可以替换这个。使用UserError构造函数,这允许你将代码移到函数之外,所以它只被调用一次。
如果您走那条路,请确保在第一次抛出UserError之前调用该行。
这个警告并不适用于函数,因为函数是先创建的,不管顺序如何。因此,您可以将函数移动到文件的末尾,没有任何问题。
浏览器兼容性
工作在Firefox和Chrome(和Node.JS),并满足所有承诺。
ie浏览器出现如下问题
Errors do not have err.stack to begin with, so "it's not my fault". Error.captureStackTrace(this, this.constructor) does not exist so you need to do something else like if(Error.captureStackTrace) // AKA if not IE Error.captureStackTrace(this, this.constructor) toString ceases to exist when you subclass Error. So you also need to add. else this.toString = function () { return this.name + ': ' + this.message } IE will not consider UserError to be an instanceof Error unless you run the following some time before you throw UserError UserError.prototype = Error.prototype
我的解决方案比其他提供的答案更简单,也没有缺点。
它保留了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;
};