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

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

在JS中应该做什么?


当前回答

重要提示:这个答案来自2016年,现在可能已经过时了。JavaScript总体上,特别是Node.js进步了很多,现在提供了更多的语法可能性来实现相同的结果。下面的内容是出于历史原因而保留的,只是为了以防有人正在处理遗留的Node.js版本。


最初的回答:

为了完整起见——因为之前的回答都没有提到这个方法——如果你正在使用Node.js,不必关心浏览器兼容性,那么使用内置的util模块继承(官方文档在这里)就很容易达到预期的效果。

例如,假设你想要创建一个自定义错误类,将错误代码作为第一个参数,错误消息作为第二个参数:

文件custom-error.js:

'use strict';

var util = require('util');

function CustomError(code, message) {
  Error.captureStackTrace(this, CustomError);
  this.name = CustomError.name;
  this.code = code;
  this.message = message;
}

util.inherits(CustomError, Error);

module.exports = CustomError;

现在你可以实例化并传递/抛出你的CustomError:

var CustomError = require('./path/to/custom-error');

// pass as the first argument to your callback
callback(new CustomError(404, 'Not found!'));

// or, if you are working with try/catch, throw it
throw new CustomError(500, 'Server Error!');

注意,对于这个代码片段,堆栈跟踪将具有正确的文件名和行,错误实例将具有正确的名称!

这是由于使用了captureStackTrace方法,该方法在目标对象上创建了一个堆栈属性(在本例中,实例化了CustomError)。有关它如何工作的更多细节,请查看这里的文档。

其他回答

在ES6:

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

在上面的例子中。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
  })

Crescent Fresh的答案是误导性的。尽管他的警告是无效的,但还有其他一些限制他没有提到。

首先,Crescent的“警告:”段落中的推理没有意义。这种解释意味着,与多个catch语句相比,编码“一堆if (error instanceof MyError) else…”在某种程度上是累赘或冗长的。单个catch块中的多个instanceof语句与多个catch语句一样简洁——干净简洁的代码,没有任何技巧。这是模拟Java出色的特定于可抛出子类型的错误处理的好方法。

WRT“显示子类的消息属性没有得到设置”,如果使用正确构造的Error子类,则不会出现这种情况。要创建自己的ErrorX Error子类,只需复制以"var MyError ="开头的代码块,将"MyError"改为"ErrorX"。(如果您想向子类添加自定义方法,请遵循示例文本)。

The real and significant limitation of JavaScript error subclassing is that for JavaScript implementations or debuggers that track and report on stack trace and location-of-instantiation, like FireFox, a location in your own Error subclass implementation will be recorded as the instantiation point of the class, whereas if you used a direct Error, it would be the location where you ran "new Error(...)"). IE users would probably never notice, but users of Fire Bug on FF will see useless file name and line number values reported alongside these Errors, and will have to drill down on the stack trace to element #1 to find the real instantiation location.

我的观点是:

为什么又是另一个答案?

a)因为访问错误。Stack属性(如某些答案)有很大的性能损失。

b)因为只有一行。

c)因为https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error的解决方案似乎没有保存堆栈信息。

//MyError class constructor
function MyError(msg){
    this.__proto__.__proto__ = Error.apply(null, arguments);
};

使用的例子

http://jsfiddle.net/luciotato/xXyeB/

它能做什么?

this.__proto__。__proto__是MyError.prototype。__proto__,所以它为所有实例设置__proto__ MyError的一个特定的新创建的错误。它保留MyError类的属性和方法,并将新的Error属性(包括.stack)放在__proto__链中。

明显的问题:

你不能有一个以上的MyError实例和有用的堆栈信息。

如果你不完全理解this.__proto__。__proto__ =。