我想在我的JS代码中抛出一些东西,我想让它们成为instanceof Error,但我也想让它们成为其他东西。

在Python中,通常会子类化Exception。

在JS中应该做什么?


当前回答

如果你不关心错误的性能,这是你能做的最小的

Object.setPrototypeOf(MyError.prototype, Error.prototype)
function MyError(message) {
    const error = new Error(message)
    Object.setPrototypeOf(error, MyError.prototype);
    return error
}

你可以不使用new只使用MyError(message)

通过在构造函数Error被调用后更改原型,我们不必设置调用堆栈和消息

其他回答

在上面的例子中。apply (also 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';

我建议的解决方案是使用error的.name属性来区分错误类型,而不是instancof

这并没有完全回答问题,但我认为这是一个合理的解决方案,至少在某些情况下。

我所看到的能够拥有一个instanceof CustomError的好处是,您可以在promise catch处理程序中进行自定义处理。

例如:

class CustomError extends Error {/** ... **/}

axios
  .post(url, payload)
  .then(data => {
    if (!data.loggedIn) throw CustomError("not logged in");
    return data;
  })
  .catch(error => {
    if (error instanceof CustomError) {/** custom handling of error*//}
    throw error
  })

如果这是你想要达到的目的,.name参数也很适合你:

export const ERROR_NOT_LOGGED_IN = "ERROR_NOT_LOGGED_IN";

axios
  .post(url, payload)
  .then(data => {
    if (!data.loggedIn) throw Error("not logged in").name=ERROR_NOT_LOGGED_IN ;
    return data;
  })
  .catch(error => {
    if (error.name === ERROR_NOT_LOGGED_IN) {/** custom handling of error*//}
    throw error
  })

Mohsen has a great answer above in ES6 that sets the name, but if you're using TypeScript or if you're living in the future where hopefully this proposal for public and private class fields has moved past stage 3 as a proposal and made it into stage 4 as part of ECMAScript/JavaScript then you might want to know this is then just a little bit shorter. Stage 3 is where browsers start implementing features, so if your browser supports it the code below just might work. (Tested in the new Edge browser v81 it seems to work fine). Be warned though this is an unstable feature at the moment and should be used cautiously and you should always check browser support on unstable features. This post is mainly for those future dwellers when browsers might support this. To check support check MDN and Can I use. It's currently got 66% support across the browser market which is getting there but not that great so if you really want to use it now and don't want to wait either use a transpiler like Babel or something like TypeScript.

类EOFError扩展错误{ name = " EOFError " } 抛出新的EOFError("Oops error ");

将此与一个无名错误进行比较,该错误在抛出时不会记录其名称。

类NamelessEOFError扩展错误{} 抛出新的NamelessEOFError("Oops error ");

自定义错误装饰器

这是基于George Bailey的回答,但扩展并简化了最初的想法。它是用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 }"

Use

现在创建新的错误类型就很简单了。

StorageError   = BaseError "Storage"
SignatureError = BaseError "Signature"

为了好玩,现在可以定义一个函数,如果调用时带有太多参数,则抛出SignatureError。

f = -> throw SignatureError "too many args" if arguments.length

这已经被测试得很好,似乎在V8上工作得很好,保持回溯,位置等。

注意:在构造自定义错误时,使用new是可选的。

这段代码显示了这一切。

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