使用ES6语法扩展Javascript中的错误&巴别

时间:2015-06-27 14:28:27

标签: javascript ecmascript-6 babeljs transpiler

我试图用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

Error对象永远不会得到正确的消息集。

Try in Babel REPL

现在我已经在SO(for example here)上看到了一些解决方案,但它们看起来都非常非ES6-y。如何以漂亮的ES6方式做到这一点? (那是在巴贝尔工作)

14 个答案:

答案 0 :(得分:173)

根据KarelBí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);

这将在堆栈中打印MyError,而不是通用Error

它还会将错误消息添加到堆栈跟踪中 - 这是Karel示例中缺少的。

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

使用Babel 6,您需要transform-builtin-extendnpm)才能生效。

答案 1 :(得分:38)

结合this answerthis answerthis code,我已经制作了这个小型的“助手”类,看起来效果很好。

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

答案 2 :(得分:25)

最后让它休息。在Babel 6中,显然开发人员不支持从内置扩展。虽然这个技巧不会帮助Map,{{1}它等确实适用于Set。这很重要,因为可以引发异常的语言的核心思想之一是允许自定义错误。这是非常重要的,因为Promises变得更有用,因为它们被设计为reject an Error

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

Example in Babel REPL

自定义错误模式

Error

另一方面,Babel 6有一个插件允许这样做。

https://www.npmjs.com/package/babel-plugin-transform-builtin-extend

更新(截至2016-09-29)经过一些测试后,看来babel.io没有正确解释所有断言(从自定义扩展错误扩展)。但在Ember.JS中,扩展错误按预期工作:https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce

答案 3 :(得分:11)

修改:在Typescript 2.1

中打破更改
  

扩展错误,数组和地图等内置插件可能不再有效。

     

作为建议,您可以在任何超级(...)调用后立即手动调整原型。

编辑Lee Benson的原始答案对我有用。这还会为实例添加stackExtendableError类的其他方法。

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);

答案 4 :(得分:10)

随着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;

import MyError from './MyError';

export default class MyChildError extends MyError {
    constructor (message) {
        super(message);
    }
}

结果所有这些测试都通过了:

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');

答案 5 :(得分:4)

Quoting

class MyError extends Error {
  constructor(message) {
    super(message);
    this.message = message;
    this.name = 'MyError';
  }
}
  

由于this.stack = (new Error()).stack;来电,无需super()技巧。

虽然上述代码无法输出堆栈跟踪,除非在Babel中调用this.stack = (new Error()).stack;Error.captureStackTrace(this, this.constructor.name);。国际海事组织,这可能是一个问题。

实际上,可以使用此代码片段在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);

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)

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

答案 6 :(得分:4)

除@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');

将抛出正确的名称,消息和堆栈跟踪:

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

答案 7 :(得分:2)

  

我正在尝试使用ES6扩展Error

class MyError extends Error {…}语法是正确的。

请注意,转换程序仍然存在继承内置对象的问题。在你的情况下,

var err = super(m);
Object.assign(this, err);

似乎解决了这个问题。

答案 8 :(得分:2)

鉴于此接受的答案不再适用,您可以随时使用工厂作为替代方案(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);

答案 9 :(得分:1)

正如@sukima所提到的,你无法扩展原生JS。 OP的问题无法回答。

Melbourne2991's answer类似,我确实使用了工厂,但是遵循了MDN's recommendation for customer error types

function extendError(className){
  function CustomError(message){
    this.name = className;
    this.message = message;
    this.stack = new Error().stack; // Optional
  }
  CustomError.prototype = Object.create(Error.prototype);
  CustomError.prototype.constructor = CustomError;
  return CustomError;
}

答案 10 :(得分:1)

我更喜欢比上述语法更强的语法。错误类型的其他方法将帮助您创建漂亮的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;
    }
}

要测试此代码,您可以运行类似的内容:

try {
    throw new CustomError('Custom error was thrown!');
} catch (e) {
    const message = e.getPrettyMessage();

    console.warn(message);
}

欢迎扩展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}.`;
    }
}

答案 11 :(得分:1)

这对我有用:

/**
 * @class AuthorizationError
 * @extends {Error}
 */
export class AuthorizationError extends Error {
    message = 'UNAUTHORIZED';
    name = 'AuthorizationError';
}

答案 12 :(得分:0)

不使用Babel,但在普通的ES6中,以下似乎对我有用:

class CustomError extends Error {
    constructor(...args) {
        super(...args);
        this.name = this.constructor.name;
    }
}

从REPL进行测试:

> const ce = new CustomError('foobar');
> ce.name
'CustomError'
> ce.message
'foobar'
> ce instanceof CustomError
true
> ce.stack
'CustomError: foobar\n    at CustomError (repl:3:1)\n ...'

如您所见,堆栈包含错误名称和消息。我不确定我是否遗漏了一些东西,但所有其他答案似乎都使​​事情过于复杂。

答案 13 :(得分:0)

我以这种方式改进了@Lee Benson的解决方案:

extendableError.js

class ExtendableError extends Error {
    constructor(message, errorCode) {
        super(message);
        this.name = this.constructor.name;
        this.errorCode = errorCode
        if (typeof Error.captureStackTrace === 'function') {
            Error.captureStackTrace(this, this.constructor);
        } else {
            this.stack = (new Error(message)).stack;
        }
    }


}

export default ExtendableError

错误示例

import ExtendableError from './ExtendableError'

const AuthorizationErrors = {
    NOT_AUTHORIZED: 401,
    BAD_PROFILE_TYPE: 402,
    ROLE_NOT_ATTRIBUTED: 403
}

class AuthorizationError extends ExtendableError {
    static errors = AuthorizationErrors 
}

export default AuthorizationError 

然后,您可以对错误进行分组,同时让选项说明符决定在某些特定于应用程序的情况下应采取的不同操作

new AuthorizationError ("The user must be a seller to be able to do a discount", AuthorizationError.errors.BAD_PROFILE_TYPE )