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

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

在JS中应该做什么?


当前回答

我不喜欢所有其他的答案,太长,太复杂,或者没有正确地跟踪堆栈。这里是我的方法,如果你需要更多的自定义道具,将它们传递给构造函数,并像name一样设置它们。

class CustomError extends Error {
  constructor (message) {
    super(message)

    // needed for CustomError instanceof Error => true
    Object.setPrototypeOf(this, new.target.prototype);

    // Set the name
    this.name = this.constructor.name

    // Maintains proper stack trace for where our error was thrown (only available on V8)
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor)
    }
  }
}

// create own CustomError sub classes
class SubCustomError extends CustomError{}

// Tests
console.log(new SubCustomError instanceof CustomError) // true
console.log(new SubCustomError instanceof CustomError) // true 
console.log(new CustomError instanceof Error) // true
console.log(new SubCustomError instanceof Error) // true

throw new SubCustomError ('test error')

其他回答

因为JavaScript异常很难子类化,所以我不子类化。我只是创建了一个新的Exception类,并在其中使用一个Error。我修改了Error.name属性,使它看起来像我在控制台上的自定义异常:

var InvalidInputError = function(message) {
    var error = new Error(message);
    error.name = 'InvalidInputError';
    return error;
};

上面的new异常可以像普通的Error一样被抛出,它会像预期的那样工作,例如:

throw new InvalidInputError("Input must be a string");
// Output: Uncaught InvalidInputError: Input must be a string 

注意:堆栈跟踪并不是完美的,因为它只会把你带到创建新错误的地方,而不是你抛出错误的地方。这在Chrome上不是什么大问题,因为它直接在控制台中为您提供了完整的堆栈跟踪。但在Firefox上问题就更多了。

我想再补充一下大家已经说过的话:

为了确保自定义错误类在堆栈跟踪中正确显示,您需要将自定义错误类的原型的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开发工具):

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)

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

为了避免针对每种不同类型的错误的样板文件,我将一些解决方案的智慧结合到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';
});

我会退一步考虑你为什么要这么做?我认为关键是要以不同的方式处理不同的错误。

例如,在Python中,您可以限制catch语句仅捕获MyValidationError,也许您希望能够在javascript中执行类似的操作。

catch (MyValidationError e) {
    ....
}

你不能在javascript中这样做。只有一个捕捉块。你应该对错误使用if语句来确定它的类型。

抓住(e) { 如果(isMyValidationError (e)) { ... }其他{ //可能重新抛出? 把e; } }

我想我会抛出一个原始对象,其中包含类型、消息和您认为合适的任何其他属性。

throw { type: "validation", message: "Invalid timestamp" }

当你捕捉到错误时:

catch(e) {
    if(e.type === "validation") {
         // handle error
    }
    // re-throw, or whatever else
}