使用 ES6 语法和 Babel 扩展 Javascript 中的错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31089801/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Extending Error in Javascript with ES6 syntax & Babel
提问by Karel Bílek
I am trying to extend Error with ES6 and Babel. It isn't working out.
我正在尝试使用 ES6 和 Babel 扩展 Error。它行不通。
class MyError extends Error {
constructor(m) {
super(m);
}
}
var error = new Error("ll");
var myerror = new MyError("ll");
console.log(error.message) //shows up correctly
console.log(myerror.message) //shows empty string
The Error object never get the right message set.
Error 对象永远不会得到正确的消息集。
Now I have seen a few solutions on SO (for example here), but they all seem very un-ES6-y. How to do it in a nice, ES6 way? (That is working in Babel)
现在我已经在 SO 上看到了一些解决方案(例如这里),但它们看起来都非常不符合 ES6 标准。如何以一种不错的 ES6 方式做到这一点?(这是在 Babel 中工作的)
回答by Lee Benson
Based on Karel Bílek's answer, I'd make a small change to the constructor
:
根据 Karel Bílek 的回答,我会对以下内容进行一些小改动constructor
:
class ExtendableError extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack;
}
}
}
// now I can extend
class MyError extends ExtendableError {}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
This will print MyError
in the stack, and not the generic Error
.
这将打印MyError
在堆栈中,而不是通用Error
.
It will also add the error message to the stack trace - which was missing from Karel's example.
它还会将错误消息添加到堆栈跟踪中——这是 Karel 的示例中缺少的。
It will also use captureStackTrace
if it's available.
captureStackTrace
如果可用,它也会使用。
With Babel 6, you need transform-builtin-extend(npm) for this to work.
使用 Babel 6,你需要transform-builtin-extend( npm) 才能工作。
回答by Karel Bílek
Combining this answer, this answerand this code, I have made this small "helper" class, that seems to work fine.
结合这个答案,这个答案和这个代码,我制作了这个小“助手”类,它似乎工作正常。
class ExtendableError extends Error {
constructor(message) {
super();
this.message = message;
this.stack = (new Error()).stack;
this.name = this.constructor.name;
}
}
// now I can extend
class MyError extends ExtendableError {
constructor(m) {
super(m);
}
}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
回答by Sukima
To finally put this to rest. In Babel 6 it is explicit that the developers do not supportextending from built in. Although this trick will nothelp with things like Map
, Set
, etc. it does work for Error
. This is important as one of the core ideas of a language that can throw an exception is to allow custom Errors. This is doubly important as Promises become more useful since they to are designed to reject an Error.
终于把这件事平息了。在通天六是明确的,开发商不支持从内置的扩展。虽然这一招不会的东西帮助像Map
,Set
等它确实工作Error
。这很重要,因为可以抛出异常的语言的核心思想之一是允许自定义错误。这一点很重要,因为 Promise 变得越来越有用,因为它们旨在拒绝 Error。
The sad truth is you still need to perform this the old way in ES2015.
可悲的事实是您仍然需要在 ES2015 中以旧方式执行此操作。
Custom Error pattern
自定义错误模式
class MyError {
constructor(message) {
this.name = 'MyError';
this.message = message;
this.stack = new Error().stack; // Optional
}
}
MyError.prototype = Object.create(Error.prototype);
On the other hand there is a plugin for Babel 6 to allow this.
另一方面,Babel 6 有一个插件可以实现这一点。
https://www.npmjs.com/package/babel-plugin-transform-builtin-extend
https://www.npmjs.com/package/babel-plugin-transform-builtin-extend
Update:(as of 2016-09-29) After some testing it appears that babel.io does not properly account for all the asserts (extending from a custom extended Error). But in Ember.JS extending Error works as expected: https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce
更新:(截至 2016-09-29)经过一些测试,babel.io 似乎没有正确解释所有断言(从自定义扩展错误扩展)。但在 Ember.JS 中,扩展错误按预期工作:https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce
回答by Artur Aleksanyan
Edit: Breaking changes in Typescript 2.1
编辑:Typescript 2.1中的重大更改
Extending built-ins like Error, Array, and Map may no longer work.
As a recommendation, you can manually adjust the prototype immediately after any super(...) calls.
扩展 Error、Array 和 Map 等内置函数可能不再有效。
作为建议,您可以在任何 super(...) 调用后立即手动调整原型。
Editing Lee Benson original answer a little bit works for me. This also adds stack
and additional methods of ExtendableError
class to the instance.
稍微编辑 Lee Benson 的原始答案对我有用。这还会向实例添加类的stack
其他方法ExtendableError
。
class ExtendableError extends Error {
constructor(message) {
super(message);
Object.setPrototypeOf(this, ExtendableError.prototype);
this.name = this.constructor.name;
}
dump() {
return { message: this.message, stack: this.stack }
}
}
class MyError extends ExtendableError {
constructor(message) {
super(message);
Object.setPrototypeOf(this, MyError.prototype);
}
}
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror.dump());
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
回答by Diego Ferri
With the latest changes in babel 6, I find transform-builtin-extendno longer working. I ended up using this mixed approach:
随着 babel 6 的最新变化,我发现transform-builtin-extend不再有效。我最终使用了这种混合方法:
export default class MyError {
constructor (message) {
this.name = this.constructor.name;
this.message = message;
this.stack = (new Error(message)).stack;
}
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;
and
和
import MyError from './MyError';
export default class MyChildError extends MyError {
constructor (message) {
super(message);
}
}
As a result all these tests pass:
结果,所有这些测试都通过了:
const sut = new MyError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut.name).toBe('MyError');
expect(typeof sut.stack).toBe('string');
const sut = new MyChildError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut).toBeInstanceOf(MyChildError);
expect(sut.name).toBe('MyChildError');
expect(typeof sut.stack).toBe('string');
回答by zangw
class MyError extends Error {
constructor(message) {
super(message);
this.message = message;
this.name = 'MyError';
}
}
There is no need for
this.stack = (new Error()).stack;
trick thanks tosuper()
call.
this.stack = (new Error()).stack;
由于super()
通话,不需要技巧。
Although the above codes cannot output the stack trace unless this.stack = (new Error()).stack;
or Error.captureStackTrace(this, this.constructor.name);
is invoked in Babel. IMO, it maybe one issue in here.
虽然上面的代码不能输出堆栈跟踪,除非this.stack = (new Error()).stack;
或Error.captureStackTrace(this, this.constructor.name);
在Babel 中被调用。IMO,这可能是这里的一个问题。
Actually, the stack trace can be output under Chrome console
and Node.js v4.2.1
with this code snippets.
其实,堆栈跟踪下都可以输出Chrome console
并Node.js v4.2.1
与该代码片段。
class MyError extends Error{
constructor(msg) {
super(msg);
this.message = msg;
this.name = 'MyError';
}
};
var myerr = new MyError("test");
console.log(myerr.stack);
console.log(myerr);
Output of Chrome console
.
的输出Chrome console
。
MyError: test
at MyError (<anonymous>:3:28)
at <anonymous>:12:19
at Object.InjectedScript._evaluateOn (<anonymous>:875:140)
at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
at Object.InjectedScript.evaluate (<anonymous>:664:21)
Output of Node.js
输出 Node.js
MyError: test
at MyError (/home/bsadmin/test/test.js:5:8)
at Object.<anonymous> (/home/bsadmin/test/test.js:11:13)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Function.Module.runMain (module.js:467:10)
at startup (node.js:134:18)
at node.js:961:3
回答by Honza Stepanovsky
In addition to @zangw answer, you can define your errors like this:
除了@zangw 答案,您还可以这样定义错误:
'use strict';
class UserError extends Error {
constructor(msg) {
super(msg);
this.name = this.constructor.name;
}
}
// define errors
class MyError extends UserError {}
class MyOtherError extends UserError {}
console.log(new MyError instanceof Error); // true
throw new MyError('My message');
which will throws correct name, message and stacktrace:
这将抛出正确的名称、消息和堆栈跟踪:
MyError: My message
at UserError (/Users/honzicek/Projects/api/temp.js:5:10)
at MyError (/Users/honzicek/Projects/api/temp.js:10:1)
at Object.<anonymous> (/Users/honzicek/Projects/api/temp.js:14:7)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:475:10)
at startup (node.js:117:18)
at node.js:951:3
回答by Bergi
I am trying to extend Error with ES6
我正在尝试使用 ES6 扩展 Error
That class MyError extends Error {…}
syntax is correct.
那个class MyError extends Error {…}
语法是正确的。
Notice that transpilers still do have problems with inheriting from builtin objects. In your case,
请注意,转译器在继承内置对象方面仍然存在问题。在你的情况下,
var err = super(m);
Object.assign(this, err);
seems to fix the problem.
似乎解决了这个问题。
回答by Melbourne2991
Given this the accepted answer no longer works you could always use a factory as an alternative (repl):
鉴于此,接受的答案不再有效,您可以始终使用工厂作为替代方案(repl):
function ErrorFactory(name) {
return class AppError extends Error {
constructor(message) {
super(message);
this.name = name;
this.message = message;
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = (new Error(message)).stack;
}
}
}
}
// now I can extend
const MyError = ErrorFactory("MyError");
var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);
回答by B. Bohdan
I prefer more strong syntax than described above. Additional methods at error type will help you to create pretty console.log
or something else.
我更喜欢比上面描述的更强大的语法。错误类型的其他方法将帮助您创建漂亮console.log
或其他东西。
export class CustomError extends Error {
/**
* @param {string} message
* @param {number} [code = 0]
*/
constructor(message, code = 0) {
super();
/**
* @type {string}
* @readonly
*/
this.message = message;
/**
* @type {number}
* @readonly
*/
this.code = code;
/**
* @type {string}
* @readonly
*/
this.name = this.constructor.name;
/**
* @type {string}
* @readonly
*/
this.stack = CustomError.createStack(this);
}
/**
* @return {string}
*/
toString() {
return this.getPrettyMessage();
}
/**
* @return {string}
*/
getPrettyMessage() {
return `${this.message} Code: ${this.code}.`;
}
/**
* @param {CustomError} error
* @return {string}
* @private
*/
static createStack(error) {
return typeof Error.captureStackTrace === 'function'
? Error.captureStackTrace(error, error.constructor)
: (new Error()).stack;
}
}
To test this code you can run something similar:
要测试此代码,您可以运行类似的东西:
try {
throw new CustomError('Custom error was thrown!');
} catch (e) {
const message = e.getPrettyMessage();
console.warn(message);
}
Extending of CustomError
type are welcome. It is possible to add some specific functionality to the extended type or override existing. For example.
CustomError
欢迎扩展类型。可以向扩展类型添加一些特定功能或覆盖现有功能。例如。
export class RequestError extends CustomError {
/**
* @param {string} message
* @param {string} requestUrl
* @param {number} [code = 0]
*/
constructor(message, requestUrl, code = 0) {
super(message, code);
/**
* @type {string}
* @readonly
*/
this.requestUrl = requestUrl;
}
/**
* @return {string}
*/
getPrettyMessage() {
const base = super.getPrettyMessage();
return `${base} Request URL: ${this.requestUrl}.`;
}
}