使用 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 06:12:03  来源:igfitidea点击:

Extending Error in Javascript with ES6 syntax & Babel

javascriptecmascript-6babeljstranspiler

提问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 对象永远不会得到正确的消息集。

Try in Babel REPL.

尝试使用 Babel REPL

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 MyErrorin 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 captureStackTraceif it's available.

captureStackTrace如果可用,它也会使用。

With Babel 6, you need transform-builtin-extend(npm) for this to work.

使用 Babel 6,你需要transform-b​​uiltin-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);

Try in REPL

在 REPL 中尝试

回答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.

终于把这件事平息了。在通天六是明确的,开发商不支持从内置的扩展。虽然这一招不会的东西帮助像MapSet等它确实工作Error。这很重要,因为可以抛出异常的语言的核心思想之一是允许自定义错误。这一点很重要,因为 Promise 变得越来越有用,因为它们旨在拒绝 Error

The sad truth is you still need to perform this the old way in ES2015.

可悲的事实是您仍然需要在 ES2015 中以旧方式执行此操作。

Example in Babel REPL

Babel REPL 中的示例

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-b​​uiltin-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 stackand additional methods of ExtendableErrorclass 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-b​​uiltin-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

Quoting

引用

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 to super()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 consoleand Node.js v4.2.1with this code snippets.

其实,堆栈跟踪下都可以输出Chrome consoleNode.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.logor 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 CustomErrortype 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}.`;
    }
}