我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。
在Python中,通常会子类化Exception。
在JS中应该做什么?
当前回答
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自制错误对象比较。
其他回答
除了标准的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(见浏览器兼容性版本)
正如其他人所说,在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);
}
简而言之:
如果你使用的是不带转译器的ES6: 类CustomError扩展错误{/*…* /} 如果你正在使用Babel转译器:
选项1:使用babel-plugin-transform-builtin-extend
选项2:自己动手(灵感来自同一个库)
function CustomError(...args) {
const instance = Reflect.construct(Error, args);
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Reflect.setPrototypeOf(CustomError, Error);
If you are using pure ES5: function CustomError(message, fileName, lineNumber) { var instance = new Error(message, fileName, lineNumber); Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); return instance; } CustomError.prototype = Object.create(Error.prototype, { constructor: { value: Error, enumerable: false, writable: true, configurable: true } }); if (Object.setPrototypeOf){ Object.setPrototypeOf(CustomError, Error); } else { CustomError.__proto__ = Error; } Alternative: use Classtrophobic framework
解释:
为什么使用ES6和Babel扩展Error类是一个问题?
因为CustomError的实例不再被这样识别。
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
事实上,在Babel的官方文档中,你不能扩展任何内置的JavaScript类,如Date、Array、DOM或Error。
问题描述如下:
本机扩展破坏HTMLELement, Array和其他 类的一个对象,它扩展了基类型如数组,数字,对象,字符串或错误不是这个类的实例
那么其他的SO答案呢?
所有给出的答案都修复了instanceof问题,但你会失去常规的错误console.log:
console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error↵ at CustomError (<anonymous>:4:19)↵ at <anonymous>:1:5"}
而使用上面提到的方法,不仅可以修复instanceof问题,还可以保留常规的error console.log:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
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自制错误对象比较。
我的观点是:
为什么又是另一个答案?
a)因为访问错误。Stack属性(如某些答案)有很大的性能损失。
b)因为只有一行。
c)因为https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error的解决方案似乎没有保存堆栈信息。
//MyError class constructor
function MyError(msg){
this.__proto__.__proto__ = Error.apply(null, arguments);
};
使用的例子
http://jsfiddle.net/luciotato/xXyeB/
它能做什么?
this.__proto__。__proto__是MyError.prototype。__proto__,所以它为所有实例设置__proto__ MyError的一个特定的新创建的错误。它保留MyError类的属性和方法,并将新的Error属性(包括.stack)放在__proto__链中。
明显的问题:
你不能有一个以上的MyError实例和有用的堆栈信息。
如果你不完全理解this.__proto__。__proto__ =。