我想在我的JS代码中扔一些东西,我希望它们是Error的instanceof,但我也想让它们成为其他东西。
通常,在Python中,可以将Exception子类化。
在JS中适合做些什么?
我想在我的JS代码中扔一些东西,我希望它们是Error的instanceof,但我也想让它们成为其他东西。
通常,在Python中,可以将Exception子类化。
在JS中适合做些什么?
Answers:
message
属性唯一的标准字段Error对象是。(请参阅MDN或EcmaScript语言规范,第15.11节)其他所有内容都是特定于平台的。
Mosts环境设置stack
属性,但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
您可以嗅探堆栈,从堆栈中移走不需要的元素,并提取诸如fileName和lineNumber之类的信息,但是这样做需要有关当前正在运行JavaScript的平台的信息。大多数情况下都是不必要的-如果您确实需要,可以在事后检查中进行。
Safari是一个明显的例外。没有stack
属性,但是有throw
关键字集sourceURL
和line
要抛出的对象的属性。这些事情肯定是正确的。
我使用的测试用例可以在这里找到:JavaScript自制的Error对象比较。
function MyError(message) { this.message = message; this.stack = Error().stack; } MyError.prototype = Object.create(Error.prototype); MyError.prototype.name = "MyError";
MyError.prototype.constructor = MyError
。
this
吧?
在ES6中:
class MyError extends Error {
constructor(message) {
super(message);
this.name = 'MyError';
}
}
var supportsClasses = false; try {eval('class X{}'); supportsClasses = true;} catch (e) {}
this.name = this.constructor.name;
改用。
简而言之:
如果您使用的是不带转译器的ES6 :
class CustomError extends Error { /* ... */}
如果您使用的是Babel Transpiler:
选项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);
如果您使用的是纯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;
}
替代方案:使用Classtrophobic框架
说明:
为什么使用ES6和Babel扩展Error类是一个问题?
因为CustomError实例不再被这样识别。
class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false
事实上,从巴贝尔的官方文档,你不能扩展任何内置的JavaScript类如Date
,Array
,DOM
或Error
。
问题描述如下:
那么其他答案呢?
所有给出的答案都解决了该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
问题,还可以保留常规错误console.log
:
console.log(new CustomError('test'));
// output:
// Error: test
// at CustomError (<anonymous>:2:32)
// at <anonymous>:1:5
class CustomError extends Error { /* ... */}
无法正确处理供应商特定的参数(lineNumber
,等),“使用ES6语法扩展Javascript中的错误”是Babel特定的,您的ES5解决方案使用了const
它,并且不处理自定义参数。
编辑:请阅读评论。事实证明,这仅在V8(Chrome / Node.JS)中有效。我的意图是提供一个跨浏览器解决方案,该解决方案可在所有浏览器中使用,并在支持的地方提供堆栈跟踪。
编辑:我做了这个社区Wiki,以便进行更多编辑。
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
}
我保留this.constructor.prototype.__proto__ = Error.prototype
在函数内部,以将所有代码保持在一起。但是,您也可以this.constructor
使用UserError
和进行替换,它允许您将代码移至函数外部,因此仅被调用一次。
如果您沿那条路线行驶,请确保在第一次掷球之前致电该线路UserError
。
注意事项不适用该功能,因为无论顺序如何,都首先创建功能。因此,您可以毫无问题地将函数移至文件末尾。
浏览器兼容性
可在Firefox和Chrome(和Node.JS)中使用,并兑现了所有承诺。
Internet Explorer在以下方面失败
错误不必从头err.stack
开始,因此“这不是我的错”。
Error.captureStackTrace(this, this.constructor)
不存在,所以您需要做其他类似的事情
if(Error.captureStackTrace) // AKA if not IE
Error.captureStackTrace(this, this.constructor)
toString
当你继承子类时,不再存在Error
。因此,您还需要添加。
else
this.toString = function () { return this.name + ': ' + this.message }
IE不会考虑UserError
到是instanceof Error
,除非你运行下面你前一段时间throw UserError
UserError.prototype = Error.prototype
Error.call(this)
确实没有做任何事情,因为它返回错误而不是修改this
。
UserError.prototype = Error.prototype
有误导性。这不做继承,这使它们成为同一个类。
Object.setPrototypeOf(this.constructor.prototype, Error.prototype)
是首选this.constructor.prototype.__proto__ = Error.prototype
。
为了避免出现每种不同类型的错误,我将一些解决方案的精髓结合到一个 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';
});
this.name = name;
吗?
name
已经在原型上设置了,所以不再需要了。我删除了 谢谢!
在2018年,我认为这是最好的方法; 支持IE9 +和现代浏览器。
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 }
});
}
setPrototypeOf()
?至少根据MDN而言,通常不建议您使用它,只要您可以通过.prototype
在构造函数上设置属性来完成同一件事(就像您在else
没有的浏览器中所做的那样setPrototypeOf
)。
setPrototypeOf
。但是,如果仍然需要它(按照OP的要求),则应使用内置方法。正如MDN所指出的那样,这被认为是设置对象原型的正确方法。换句话说,MDN表示不要更改原型(因为它会影响性能和优化),但如果需要,请使用setPrototypeOf
。
CustomError.prototype = Object.create(Error.prototype)
)处使用一行即可。此外,Object.setPrototypeOf(CustomError, Error.prototype)
是设置构造函数本身的原型,而不是为的新实例指定原型CustomError
。无论如何,在2016年我觉得其实有更好的方法来扩展的错误,但我仍然搞清楚如何与巴贝尔一起使用它:github.com/loganfsmyth/babel-plugin-transform-builtin-extend/...
CustomError.prototype = Object.create(Error.prototype)
也正在改变原型。由于ES5中没有内置的扩展/继承逻辑,因此您必须对其进行更改。我敢肯定,您提到的babel插件会做类似的事情。
Object.setPrototypeOf
在这里使用无意义,至少在您使用时没有用:gist.github.com/mbrowne/4af54767dcb3d529648f5a8aa11d6348。也许您打算写Object.setPrototypeOf(CustomError.prototype, Error.prototype)
-这会更有意义(尽管与简单设置相比仍然没有任何好处CustomError.prototype
)。
出于完整性的考虑(仅因为以前的答案中没有提到此方法),如果您使用的是Node.js,而不必关心浏览器的兼容性,则内置的功能很容易实现所需的效果inherits
的util
模块(此处为官方文档)。
例如,假设您要创建一个自定义错误类,该类将错误代码作为第一个参数,将错误消息作为第二个参数:
文件custom-error.js:
'use strict';
var util = require('util');
function CustomError(code, message) {
Error.captureStackTrace(this, CustomError);
this.name = CustomError.name;
this.code = code;
this.message = message;
}
util.inherits(CustomError, Error);
module.exports = CustomError;
现在您可以实例化和传递/抛出您的CustomError
:
var CustomError = require('./path/to/custom-error');
// pass as the first argument to your callback
callback(new CustomError(404, 'Not found!'));
// or, if you are working with try/catch, throw it
throw new CustomError(500, 'Server Error!');
请注意,使用此代码段,堆栈跟踪将具有正确的文件名和行,并且错误实例将具有正确的名称!
发生这种情况是由于captureStackTrace
方法的使用,该方法stack
在目标对象上创建了一个属性(在这种情况下,CustomError
实例化了该属性)。有关其工作原理的更多详细信息,请参见此处的文档。
this.message = this.message;
这是错误的还是关于JS我还不了解的疯狂事情?
Crescent Fresh的答案极富争议,令人误解。尽管他的警告无效,但他没有解决其他限制。
首先,Crescent的“注意事项”(Caveats :)段落中的推理没有任何意义。这种解释意味着,与多个catch语句相比,编码“一堆if(错误(MyError的MyError实例)else ...”)在某种程度上是繁重的或冗长的。单个catch块中的多个instanceof语句与多个catch语句一样简洁-简洁简洁的代码,没有任何技巧。这是模拟Java出色的特定于可抛出子类型的错误处理的好方法。
WRT“似乎未设置子类的message属性”,如果您使用正确构造的Error子类,则情况并非如此。要创建自己的ErrorX Error子类,只需复制以“ var MyError =”开头的代码块,将一个单词“ MyError”更改为“ ErrorX”。(如果要向子类添加自定义方法,请遵循示例文本)。
JavaScript错误子类的真正且显着的局限性是,对于跟踪并报告堆栈跟踪和实例化位置的JavaScript实现或调试器(如FireFox),您自己的Error子类实现中的位置将被记录为该实例的实例化点。类,而如果您使用直接错误,它将是您运行“新错误(...)”的位置。IE用户可能永远不会注意到,但是FF上的Fire Bug用户将在这些错误旁边看到无用的文件名和行号值报告,并且必须深入到元素1的堆栈跟踪中才能找到真正的实例化位置。
Crescent Fresh's
已被删除!
这个解决方案怎么样?
而不是使用以下方法抛出自定义错误:
throw new MyError("Oops!");
您将包装Error对象(有点像Decorator):
throw new MyError(Error("Oops!"));
这样可以确保所有属性都是正确的,例如堆栈,fileName lineNumber等。
然后,您要做的就是复制属性或为它们定义getter。这是使用吸气剂(IE9)的示例:
function MyError(wrapped)
{
this.wrapped = wrapped;
this.wrapped.name = 'MyError';
}
function wrap(attr)
{
Object.defineProperty(MyError.prototype, attr, {
get: function()
{
return this.wrapped[attr];
}
});
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
wrap('name');
wrap('message');
wrap('stack');
wrap('fileName');
wrap('lineNumber');
wrap('columnNumber');
MyError.prototype.toString = function()
{
return this.wrapped.toString();
};
new MyErr (arg1, arg2, new Error())
在MyErr构造函数中,我们用于Object.assign
将最后一个arg的属性分配给this
正如某些人所说,使用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');
}
}
在节点中或直接在浏览器中,它将显示: Custom error
尝试在Typescript操场上的项目中使用Typescript运行它,它将显示Basic error
...
解决方案是执行以下操作:
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;
}
}
我的解决方案比提供的其他答案更简单,并且没有缺点。
它保留了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;
};
throw CustomError('err')
而不是throw new CustomError('err')
在上面的示例中Error.apply
(也Error.call
)对我没有任何帮助(Firefox 3.6 / Chrome 5)。我使用的解决方法是:
function MyError(message, fileName, lineNumber) {
var err = new Error();
if (err.stack) {
// remove one stack level:
if (typeof(Components) != 'undefined') {
// Mozilla:
this.stack = err.stack.substring(err.stack.indexOf('\n')+1);
}
else if (typeof(chrome) != 'undefined' || typeof(process) != 'undefined') {
// Google Chrome/Node.js:
this.stack = err.stack.replace(/\n[^\n]*/,'');
}
else {
this.stack = err.stack;
}
}
this.message = message === undefined ? err.message : message;
this.fileName = fileName === undefined ? err.fileName : fileName;
this.lineNumber = lineNumber === undefined ? err.lineNumber : lineNumber;
}
MyError.prototype = new Error();
MyError.prototype.constructor = MyError;
MyError.prototype.name = 'MyError';
正如其他人所说,在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);
}
我只想补充别人已经说过的话:
为确保自定义错误类在堆栈跟踪中正确显示,您需要将自定义错误类的原型的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 dev工具中偷懒地尝试过):
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)
我的2美分:
a)因为访问Error.stack
属性(如在某些答案中)会带来很大的性能损失。
b)因为只有一行。
c)因为https://developer.mozilla.org/zh-CN/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 的FOR ALL INSTANCES 设置为特定的新创建的Error。它保留MyError类的属性和方法,还将新的Error属性(包括.stack)放入__proto__
链中。
具有有用的堆栈信息的MyError实例不能超过一个。
如果您不完全了解this.__proto__.__proto__=
它,请不要使用此解决方案。
由于很难对JavaScript异常进行子类化,因此我不对它进行子类化。我只是创建一个新的Exception类,并在其中使用Error。我更改了Error.name属性,使其看起来像我在控制台上的自定义异常:
var InvalidInputError = function(message) {
var error = new Error(message);
error.name = 'InvalidInputError';
return error;
};
可以像常规错误一样抛出上述新异常,并且该异常将按预期运行,例如:
throw new InvalidInputError("Input must be a string");
// Output: Uncaught InvalidInputError: Input must be a string
注意:堆栈跟踪不是完美的,因为它将使您到达创建新错误的位置,而不是引发错误的位置。在Chrome上这不是什么大问题,因为它可以直接在控制台中提供完整的堆栈跟踪。但这在Firefox上更成问题。
m = new InvalidInputError(); dontThrowMeYet(m);
m = new ...
then Promise.reject(m)
。没必要,但是代码更易于阅读。
正如Mohsen的答案所指出的那样,在ES6中可以使用类来扩展错误。这要容易得多,并且它们的行为与本机错误更加一致...但是不幸的是,如果需要支持ES6之前的浏览器,在浏览器中使用它并不是一件简单的事情。有关如何实现的一些说明,请参见下文,但与此同时,我建议一种相对简单的方法,该方法结合了其他答案中的一些最佳建议:
function CustomError(message) {
//This is for future compatibility with the ES6 version, which
//would display a similar message if invoked without the
//`new` operator.
if (!(this instanceof CustomError)) {
throw new TypeError("Constructor 'CustomError' cannot be invoked without 'new'");
}
this.message = message;
//Stack trace in V8
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
else this.stack = (new Error).stack;
}
CustomError.prototype = Object.create(Error.prototype);
CustomError.prototype.name = 'CustomError';
在ES6中,它很简单:
class CustomError extends Error {}
...并且您可以使用来检测对ES6类的支持try {eval('class X{}')
,但是如果尝试在旧版浏览器加载的脚本中包含ES6版本,则会出现语法错误。因此,支持所有浏览器的唯一方法是为eval()
支持ES6的浏览器动态加载单独的脚本(例如,通过AJAX或)。更为复杂的是,eval()
并非所有环境都支持(由于内容安全策略),这可能会或可能不会成为您项目的考虑因素。
因此,就目前而言,无论是上面的第一种方法,还是直接使用Error
而不尝试扩展它,对于需要支持非ES6浏览器的代码,实际上似乎是最好的方法。
有些人可能要考虑另一种方法,即使用Object.setPrototypeOf()
可用的位置创建一个错误对象,该对象是您的自定义错误类型的实例,但其外观和行为更像是控制台中的本机错误(感谢Ben的回答)的建议)。这是我对这种方法的看法:https : //gist.github.com/mbrowne/fe45db61cea7858d11be933a998926a8。但是考虑到有一天我们将只能使用ES6,就我个人而言,我不确定这种方法的复杂性是否值得。
做到这一点的方法是从构造函数返回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
和的其他属性第一个问题可以通过使用此答案中的技巧遍历错误的所有不可枚举的属性来解决:是否可以获取对象的不可枚举的继承属性名称?,但是ie <9不支持此功能。第二个问题可以通过在堆栈跟踪中删除该行来解决,但是我不确定如何安全地执行此操作(也许只是删除e.stack.toString()的第二行)。
该代码段显示了所有内容。
function add(x, y) {
if (x && y) {
return x + y;
} else {
/**
*
* the error thrown will be instanceof Error class and InvalidArgsError also
*/
throw new InvalidArgsError();
// throw new Invalid_Args_Error();
}
}
// Declare custom error using using Class
class Invalid_Args_Error extends Error {
constructor() {
super("Invalid arguments");
Error.captureStackTrace(this);
}
}
// Declare custom error using Function
function InvalidArgsError(message) {
this.message = `Invalid arguments`;
Error.captureStackTrace(this);
}
// does the same magic as extends keyword
Object.setPrototypeOf(InvalidArgsError.prototype, Error.prototype);
try{
add(2)
}catch(e){
// true
if(e instanceof Error){
console.log(e)
}
// true
if(e instanceof InvalidArgsError){
console.log(e)
}
}
我会退后一步,考虑为什么要这么做?我认为关键是要以不同的方式处理不同的错误。
例如,在Python中,您可以将catch语句限制为仅catch MyValidationError
,也许您希望能够在javascript中执行类似的操作。
catch (MyValidationError e) {
....
}
您无法使用javascript执行此操作。只会有一个捕获块。您应该对错误使用if语句来确定其类型。
catch(e) {
if(isMyValidationError(e)) {
...
} else {
// maybe rethrow?
throw e;
}
}
我想我会抛出一个带有类型,消息和您认为合适的其他属性的原始对象。
throw { type: "validation", message: "Invalid timestamp" }
当您发现错误时:
catch(e) {
if(e.type === "validation") {
// handle error
}
// re-throw, or whatever else
}
error.stack
,标准工具将无法使用,等等,等等。一种更好的方法是将属性添加到错误实例,例如var e = new Error(); e.type = "validation"; ...
这是基于乔治·贝利的回答,但扩展并简化了最初的想法。它是用CoffeeScript编写的,但是很容易转换为JavaScript。这个想法是通过包装它的装饰器扩展Bailey的自定义错误,使您可以轻松地创建新的自定义错误。
注意:这仅在V8中有效。Error.captureStackTrace
在其他环境中不支持。
装饰器采用错误类型的名称,然后返回采用错误消息的函数并将其括起来。
CoreError = (@message) ->
@constructor.prototype.__proto__ = Error.prototype
Error.captureStackTrace @, @constructor
@name = @constructor.name
BaseError = (type) ->
(message) -> new CoreError "#{ type }Error: #{ message }"
现在很容易创建新的错误类型。
StorageError = BaseError "Storage"
SignatureError = BaseError "Signature"
为了好玩,您现在可以定义一个函数,SignatureError
如果调用了过多的args,则该函数将抛出a 。
f = -> throw SignatureError "too many args" if arguments.length
这已经过很好的测试,并且似乎可以在V8上完美运行,保持回溯,位置等。
注意:new
构造自定义错误时,使用是可选的。
Mohsen在ES6上面有一个很好的答案,它设置了名称,但是如果您使用的是TypeScript,或者您生活在将来,希望有关公共和私有类字段的提案已超过第3阶段的提案,并提出了此建议,进入第4阶段(作为ECMAScript / JavaScript的一部分),那么您可能想知道它会短一些。第3阶段是浏览器开始实现功能的位置,因此,如果您的浏览器支持,则下面的代码可能会起作用。(在新的Edge浏览器v81中进行了测试,似乎工作正常)。请注意,尽管此功能目前尚不稳定,应谨慎使用,并且应始终检查浏览器对不稳定功能的支持。这篇文章主要针对浏览器可能支持的未来居民。要检查支持,请检查MDN并我可以使用。它目前有跨浏览器的市场这是越来越有,但不是很大,所以如果你真的想现在使用它,不想等待或者使用像transpiler 66%的支持巴别塔之类的东西打字稿。
class EOFError extends Error {
name="EOFError"
}
throw new EOFError("Oops errored");
将此错误与无名错误进行比较,该错误在引发时将不会记录其名称。
class NamelessEOFError extends Error {}
throw new NamelessEOFError("Oops errored");
this.name = 'MyError'
函数的外部移动并将其更改为MyError.prototype.name = 'MyError'
。