【问题标题】:How do I create a custom Error in JavaScript?如何在 JavaScript 中创建自定义错误?
【发布时间】:2010-10-21 11:51:20
【问题描述】:

由于某种原因,构造函数委托在以下 sn-p 中似乎不起作用:

function NotImplementedError() { 
  Error.apply(this, arguments); 
}
NotImplementedError.prototype = new Error();

var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")

运行它会得到The message is: ''。关于原因的任何想法,或者是否有更好的方法来创建新的Error 子类? applying 到我不知道的原生 Error 构造函数是否存在问题?

【问题讨论】:

  • 在您的更改之后,nie instanceof NotImplementedError 断言是否有效?我认为为了使它起作用,您需要明确定义 NotImplementedError.prototype.constructor。
  • 下一次,请删除所有不需要证明您的问题的无关代码。另外, wtc 是 js.jar 吗?是否需要重现问题?
  • 编辑了这个问题,以便在 10 秒而不是 10 分钟内理解它
  • 我创建了一个继承自错误类型的继承/类库:github.com/fresheneesz/proto
  • jsfiddle 获取一些热门答案。

标签: javascript exception


【解决方案1】:

更新您的代码以将您的原型分配给 Error.prototype 并且 instanceof 和您的断言工作。

function NotImplementedError(message = "") {
    this.name = "NotImplementedError";
    this.message = message;
}
NotImplementedError.prototype = Error.prototype;

但是,我只会抛出您自己的对象并检查 name 属性。

throw {name : "NotImplementedError", message : "too lazy to implement"}; 

基于 cmets 编辑

在查看了 cmets 并试图记住为什么我会将原型分配给 Error.prototype 而不是像 Nicholas Zakas 在他的 article 中所做的那样分配给 new Error() 之后,我使用以下代码创建了一个 jsFiddle

function NotImplementedError(message = "") {
  this.name = "NotImplementedError";
  this.message = message;
}
NotImplementedError.prototype = Error.prototype;

function NotImplementedError2(message = "") {
  this.message = message;
}
NotImplementedError2.prototype = new Error();

try {
  var e = new NotImplementedError("NotImplementedError message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

try {
  var e = new NotImplementedError2("NotImplementedError2 message");
  throw e;
} catch (ex1) {
  console.log(ex1.stack);
  console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
  console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
  console.log("ex1.name = " + ex1.name);
  console.log("ex1.message = " + ex1.message);
}

控制台输出是这样的。

undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
    at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message

这证实了我遇到的“问题”是错误的堆栈属性是创建new Error() 的行号,而不是throw e 发生的位置。但是,这可能比具有影响 Error 对象的 NotImplementedError.prototype.name = "NotImplementedError" 行的副作用更好。

另外,请注意NotImplementedError2,当我没有明确设置.name 时,它等于“错误”。但是,正如 cmets 中所述,由于该版本将原型设置为 new Error(),因此我可以设置为 NotImplementedError2.prototype.name = "NotImplementedError2" 并且可以。

【讨论】:

  • 最佳答案,但直接采用Error.prototype 可能是不好的形式。如果您以后想添加一个NotImplementedError.prototype.toString,则该对象现在别名为Error.prototype.toString——最好是NotImplementedError.prototype = new Error()
  • 我还是有点迷失在所有这些原型的东西上。为什么在您的示例中将名称分配给 this.name 而不是 NotImplementedError.prototype.name?你能回答吗,这对我的理解很重要:)
  • 根据code.google.com/p/chromium/issues/detail?id=228909 subclass.prototype = new Error() 是错误的形式。您应该改用subclass.prototype = Object.create(superclass.prototype)。我希望它也可以解决堆栈跟踪问题。
  • 获得有意义的堆栈跟踪的简单技巧是在构造函数中生成错误并保存它的堆栈。它将为构造函数提供适当的调用堆栈 + 1 行(这是一个合适的回报):this.stack = new Error().stack;
  • -1;这是错误的。执行NotImplementedError.prototype = Error.prototype; 不会使instanceofNotImplementedError 视为Error子类,它会使instanceof 将它们视为完全相同的类。如果将上面的代码粘贴到控制台并尝试new Error() instanceof NotImplementedError,您将得到true,这显然是错误的。
【解决方案2】:

以上所有答案都非常糟糕 - 真的。甚至是107 ups的那个!真正的答案在这里:

Inheriting from the Error object - where is the message property?

TL;DR:

A.未设置 message 的原因是 Error 是一个返回新 Error 对象的函数,并且以任何方式操纵 this

B.做到这一点的方法是从构造函数返回 apply 的结果,以及以通常复杂的 javascripty 方式设置原型:

function MyError() {
    var temp = Error.apply(this, arguments);
    temp.name = this.name = 'MyError';
    this.message = temp.message;
    if(Object.defineProperty) {
        // getter for more optimizy goodness
        /*this.stack = */Object.defineProperty(this, 'stack', { 
            get: function() {
                return temp.stack
            },
            configurable: true // so you can change it if you want
        })
    } else {
        this.stack = temp.stack
    }
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
    constructor: {
        value: MyError,
        writable: true,
        configurable: true
    }
});

var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n 
// <stack trace ...>


 
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/

您可能会做一些技巧来枚举tmp 错误的所有不可枚举属性来设置它们,而不是显式设置仅stackmessage,但是ie 不支持这种技巧

【讨论】:

  • 此解决方案也适用于使用现有错误实例化自定义错误。如果您使用第三方库并想用您自己的自定义类型包装现有错误,则其他方法无法正常工作。仅供参考,您可以通过将现有错误传递给普通错误来实例化它们。
  • 你不应该在构造函数中return this
  • 我稍微简化和改进了这种方法:jsbin.com/rolojuhuya/1/edit?js,console
  • @MattKantor 或许可以回答这个问题?我想我最喜欢你的。
  • 你可以用temp.name = this.name = this.constructor.name代替temp.name = this.name = 'MyError'。这样它也适用于MyError 的子类。
【解决方案3】:

在 ES2015 中,您可以使用 class 干净地做到这一点:

class NotImplemented extends Error {
  constructor(message = "", ...args) {
    super(message, ...args);
    this.message = message + " has not yet been implemented.";
  }
}

这不会修改全局Error原型,允许您自定义messagename等属性,并正确捕获堆栈。它的可读性也很好。

当然,如果您的代码将在旧版浏览器上运行,您可能需要使用像 babel 这样的工具。

【讨论】:

【解决方案4】:

如果有人好奇如何创建自定义错误获取堆栈跟踪:

function CustomError(message) {
  this.name = 'CustomError';
  this.message = message || '';
  var error = new Error(this.message);
  error.name = this.name;
  this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);

try {
  throw new CustomError('foobar');
}
catch (e) {
  console.log('name:', e.name);
  console.log('message:', e.message);
  console.log('stack:', e.stack);
}

【讨论】:

    【解决方案5】:

    标准的这一部分可以解释为什么Error.apply调用没有初始化对象:

    15.11.1 作为函数调用的错误构造函数

    当 Error 作为函数而不是构造函数调用时,它会创建和 初始化一个新的 Error 对象。因此函数调用 Error(...) 是 等效于对象创建表达式 new Error(...) 与 相同的论点。

    在这种情况下,Error 函数可能确定它没有被作为构造函数调用,因此它返回一个新的 Error 实例而不是初始化 this 对象。

    使用以下代码进行测试似乎表明这实际上是正在发生的事情:

    function NotImplementedError() { 
       var returned = Error.apply(this, arguments);
       console.log("returned.message = '" + returned.message + "'");
       console.log("this.message = '" + this.message + "'");
    }
    NotImplementedError.prototype = new Error();
    
    var nie = new NotImplementedError("some message");
    

    运行时会生成以下输出:

    returned.message = 'some message'
    this.message = ''
    

    【讨论】:

    • 如何使用自定义错误类进行模拟?例如,我的自定义错误类如何同时用作创建实例的函数和构造函数?
    • 不,这不是真的。如果它返回一个新的 Error 实例,那么他的 msg 属性就会起作用。
    • @BT 新实例上的 msg 属性如何影响 Error.apply(this, arguments);this 上的 msg 属性?我是说这里对 Error 的调用是在构造一个新对象,该对象被丢弃;未初始化分配给 nie 的已构造对象。
    • @BT 我添加了一些示例代码,希望能更清楚地说明我想说的话。
    • @Dave 我可能误解了这里的目的,但您的NotImplementedError 实现不应该返回returned 变量吗?
    【解决方案6】:
    function InvalidValueError(value, type) {
        this.message = "Expected `" + type.name + "`: " + value;
        var error = new Error(this.message);
        this.stack = error.stack;
    }
    InvalidValueError.prototype = new Error();
    InvalidValueError.prototype.name = InvalidValueError.name;
    InvalidValueError.prototype.constructor = InvalidValueError;
    

    【讨论】:

    • 这是最好的答案。它很简洁,并且以这种方式创建的异常在所有情况下都会正确运行。它还保留了堆栈跟踪,这在非平凡的应用程序中非常重要。我只会用“prototype = Object.create(Error.prototype)”替换“prototype = new Error()”。对于 Node.js,有一个小型库可以为您执行此操作:npmjs.com/package/node-custom-errors
    【解决方案7】:

    Accoring to Joyent 你不应该弄乱堆栈属性(我在这里给出的很多答案中都看到了),因为它会对性能产生负面影响。他们是这样说的:

    stack:一般来说,不要搞砸这个。甚至不要增加它。 V8 仅在有人实际读取该属性时才计算它,这显着提高了可处理错误的性能。如果您只是为了增加它而读取该属性,即使您的调用者不需要堆栈,您最终也会付出代价。

    我喜欢并想提一下their idea of wrapping the original error,它可以很好地替代在堆栈上传递。

    考虑到上述情况,这就是我创建自定义错误的方法:

    es5 版本:

    function RError(options) {
        options = options || {}; // eslint-disable-line no-param-reassign
        this.name = options.name;
        this.message = options.message;
        this.cause = options.cause;
    
        // capture stack (this property is supposed to be treated as private)
        this._err = new Error();
    
        // create an iterable chain
        this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
    }
    RError.prototype = Object.create(Error.prototype, {
        constructor: {
            value: RError,
            writable: true,
            configurable: true
        }
    });
    
    Object.defineProperty(RError.prototype, 'stack', {
        get: function stack() {
            return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
        }
    });
    
    Object.defineProperty(RError.prototype, 'why', {
        get: function why() {
            var _why = this.name + ': ' + this.message;
            for (var i = 1; i < this.chain.length; i++) {
                var e = this.chain[i];
                _why += ' <- ' + e.name + ': ' + e.message;
            }
            return _why;
        }
    });
    
    // usage
    
    function fail() {
        throw new RError({
            name: 'BAR',
            message: 'I messed up.'
        });
    }
    
    function failFurther() {
        try {
            fail();
        } catch (err) {
            throw new RError({
                name: 'FOO',
                message: 'Something went wrong.',
                cause: err
            });
        }
    }
    
    try {
        failFurther();
    } catch (err) {
        console.error(err.why);
        console.error(err.stack);
        console.error(err.cause.stack);
    }

    es6 版本:

    class RError extends Error {
        constructor({name, message, cause}) {
            super();
            this.name = name;
            this.message = message;
            this.cause = cause;
        }
        [Symbol.iterator]() {
            let current = this;
            let done = false;
            const iterator = {
                next() {
                    const val = current;
                    if (done) {
                        return { value: val, done: true };
                    }
                    current = current.cause;
                    if (!val.cause) {
                        done = true;
                    }
                    return { value: val, done: false };
                }
            };
            return iterator;
        }
        get why() {
            let _why = '';
            for (const e of this) {
                _why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
            }
            return _why;
        }
    }
    
    // usage
    
    function fail() {
        throw new RError({
            name: 'BAR',
            message: 'I messed up.'
        });
    }
    
    function failFurther() {
        try {
            fail();
        } catch (err) {
            throw new RError({
                name: 'FOO',
                message: 'Something went wrong.',
                cause: err
            });
        }
    }
    
    try {
        failFurther();
    } catch (err) {
        console.error(err.why);
        console.error(err.stack);
        console.error(err.cause.stack);
    }

    我已经把我的解决方案放到了一个模块中,这里是:https://www.npmjs.com/package/rerror

    【讨论】:

      【解决方案8】:

      我喜欢这样做:

      • 利用name 所以 toString() 抛出"{code}: {message}"
      • 将相同的内容返回给 super,使其在堆栈跟踪中显示相同
      • 将代码附加到error.code,因为在代码中检查/解析代码比检查消息更好,例如您可能希望将其本地化
      • 将消息附加到error.message 以替代error.toString()

      class AppException extends Error {
        constructor(code, message) {
          const fullMsg = message ? `${code}: ${message}` : code;
          super(fullMsg);
          this.name = code;
          this.code = code;
          this.message = fullMsg;
        }
        
        toString() {
          return this.message;
        }
      }
      
      // Just a code
      try {
        throw new AppException('FORBIDDEN');
      } catch(e) {
        console.error(e);
        console.error(e.toString());
        console.log(e.code === 'FORBIDDEN');
      }
      
      // A code and a message
      try {
        throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
      } catch(e) {
        console.error(e);
        console.error(e.toString());
        console.log(e.code === 'FORBIDDEN');
      }

      【讨论】:

        【解决方案9】:

        我遇到了类似的问题。我的错误必须是instanceofErrorNotImplemented,并且它还需要在控制台中产生连贯的回溯。

        我的解决方案:

        var NotImplemented = (function() {
          var NotImplemented, err;
          NotImplemented = (function() {
            function NotImplemented(message) {
              var err;
              err = new Error(message);
              err.name = "NotImplemented";
              this.message = err.message;
              if (err.stack) this.stack = err.stack;
            }
            return NotImplemented;
          })();
          err = new Error();
          err.name = "NotImplemented";
          NotImplemented.prototype = err;
        
          return NotImplemented;
        }).call(this);
        
        // TEST:
        console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
        console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
        console.log("message: "+(new NotImplemented('I was too busy').message));
        throw new NotImplemented("just didn't feel like it");
        

        使用 node.js 运行的结果:

        instanceof Error: true
        instanceof NotImplemented: true
        message: I was too busy
        
        /private/tmp/t.js:24
        throw new NotImplemented("just didn't feel like it");
              ^
        NotImplemented: just didn't feel like it
            at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
            at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
            at Module._compile (module.js:449:26)
            at Object.Module._extensions..js (module.js:467:10)
            at Module.load (module.js:356:32)
            at Function.Module._load (module.js:312:12)
            at Module.runMain (module.js:487:10)
            at process.startup.processNextTick.process._tickCallback (node.js:244:9)
        

        该错误通过了我的所有 3 个标准,尽管 stack 属性是非标准的,但 it is supported in most newer browsers 在我的情况下是可以接受的。

        【讨论】:

          【解决方案10】:
          class NotImplementedError extends Error {
            constructor(message) {
              super(message);
              this.message = message;
            }
          }
          NotImplementedError.prototype.name = 'NotImplementedError';
          module.exports = NotImplementedError;
          

          try {
            var e = new NotImplementedError("NotImplementedError message");
            throw e;
          } catch (ex1) {
            console.log(ex1.stack);
            console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
            console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
            console.log("ex1.name = " + ex1.name);
            console.log("ex1.message = " + ex1.message);
          }
          

          它只是this答案的类表示。

          输出

          NotImplementedError: NotImplementedError message
            ...stacktrace
          ex1 instanceof NotImplementedError = true
          ex1 instanceof Error = true
          ex1.name = NotImplementedError
          ex1.message = NotImplementedError message
          

          【讨论】:

            【解决方案11】:

            我使用构造函数模式来创建新的错误对象。我定义了原型链,例如Error 实例。请参阅 MDN Error constructor 参考。

            你可以在这个 gist 上查看这个 sn-p。

            实施

            // Creates user-defined exceptions
            var CustomError = (function() {
              'use strict';
            
              //constructor
              function CustomError() {
                //enforces 'new' instance
                if (!(this instanceof CustomError)) {
                  return new CustomError(arguments);
                }
                var error,
                  //handles the arguments object when is passed by enforcing a 'new' instance
                  args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
                  message = args.shift() || 'An exception has occurred';
            
                //builds the message with multiple arguments
                if (~message.indexOf('}')) {
                  args.forEach(function(arg, i) {
                    message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
                  });
                }
            
                //gets the exception stack
                error = new Error(message);
                //access to CustomError.prototype.name
                error.name = this.name;
            
                //set the properties of the instance
                //in order to resemble an Error instance
                Object.defineProperties(this, {
                  stack: {
                    enumerable: false,
                    get: function() { return error.stack; }
                  },
                  message: {
                    enumerable: false,
                    value: message
                  }
                });
              }
            
              // Creates the prototype and prevents the direct reference to Error.prototype;
              // Not used new Error() here because an exception would be raised here,
              // but we need to raise the exception when CustomError instance is created.
              CustomError.prototype = Object.create(Error.prototype, {
                //fixes the link to the constructor (ES5)
                constructor: setDescriptor(CustomError),
                name: setDescriptor('JSU Error')
              });
            
              function setDescriptor(value) {
                return {
                  configurable: false,
                  enumerable: false,
                  writable: false,
                  value: value
                };
              }
            
              //returns the constructor
              return CustomError;
            }());
            

            用法

            CustomError 构造函数可以接收许多参数来构建消息,例如

            var err1 = new CustomError("The url of file is required"),
                err2 = new CustomError("Invalid Date: {0}", +"date"),
                err3 = new CustomError("The length must be greater than {0}", 4),
                err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");
            
            throw err4;
            

            这就是自定义错误的外观:

            【讨论】:

            • 投反对票的人,你有意见,或者投反对票的理由吗?或者只是不明白代码中的意图。
            • 我刚刚注意到我一定是在浏览此页面时不小心点击了否决按钮而没有意识到(可能是从我的手机浏览)。我今天在浏览我的历史时才注意到。这绝对不是故意的,但我无法撤消它,因为它已经过了宽限期。您提供了一个信息丰富的答案,绝对不值得。如果您进行编辑,我会很乐意撤消反对票。对此感到抱歉。
            【解决方案12】:

            我只需要实现这样的东西,发现堆栈在我自己的错误实现中丢失了。我必须做的是创建一个虚拟错误并从中检索堆栈:

            My.Error = function (message, innerException) {
                var err = new Error();
                this.stack = err.stack; // IMPORTANT!
                this.name = "Error";
                this.message = message;
                this.innerException = innerException;
            }
            My.Error.prototype = new Error();
            My.Error.prototype.constructor = My.Error;
            My.Error.prototype.toString = function (includeStackTrace) {
                var msg = this.message;
                var e = this.innerException;
                while (e) {
                    msg += " The details are:\n" + e.message;
                    e = e.innerException;
                }
                if (includeStackTrace) {
                    msg += "\n\nStack Trace:\n\n" + this.stack;
                }
                return msg;
            }
            

            【讨论】:

            • 这不会设置消息
            【解决方案13】:

            这是我的实现:

            class HttpError extends Error {
              constructor(message, code = null, status = null, stack = null, name = null) {
                super();
                this.message = message;
                this.status = 500;
            
                this.name = name || this.constructor.name;
                this.code = code || `E_${this.name.toUpperCase()}`;
                this.stack = stack || null;
              }
            
              static fromObject(error) {
                if (error instanceof HttpError) {
                  return error;
                }
                else {
                  const { message, code, status, stack } = error;
                  return new ServerError(message, code, status, stack, error.constructor.name);
                }
              }
            
              expose() {
                if (this instanceof ClientError) {
                  return { ...this };
                }
                else {
                  return {
                    name: this.name,
                    code: this.code,
                    status: this.status,
                  }
                }
              }
            }
            
            class ServerError extends HttpError {}
            
            class ClientError extends HttpError { }
            
            class IncorrectCredentials extends ClientError {
              constructor(...args) {
                super(...args);
                this.status = 400;
              }
            }
            
            class ResourceNotFound extends ClientError {
              constructor(...args) {
                super(...args);
                this.status = 404;
              }
            }
            

            示例用法 #1:

            app.use((req, res, next) => {
              try {
                invalidFunction();
              }
              catch (err) {
                const error = HttpError.fromObject(err);
                return res.status(error.status).send(error.expose());
              }
            });
            

            用法示例 #2:

            router.post('/api/auth', async (req, res) => {
              try {
                const isLogged = await User.logIn(req.body.username, req.body.password);
            
                if (!isLogged) {
                  throw new IncorrectCredentials('Incorrect username or password');
                }
                else {
                  return res.status(200).send({
                    token,
                  });
                }
              }
              catch (err) {
                const error = HttpError.fromObject(err);
                return res.status(error.status).send(error.expose());
              }
            });
            

            【讨论】:

              【解决方案14】:

              构造函数需要像工厂方法一样,返回你想要的。如果您需要其他方法/属性,可以在返回之前将它们添加到对象中。

              function NotImplementedError(message) { return new Error("Not implemented", message); }
              
              x = new NotImplementedError();
              

              虽然我不确定你为什么需要这样做。为什么不直接使用 new Error... ?自定义异常在 JavaScript(或者可能是任何无类型语言)中并没有真正增加太多。

              【讨论】:

              • 您必须在 JavaScript 中打开 Error-type-hierarchy 或 object-value,因为您只能指定一个 catch 块。在您的解决方案中, (x instanceof NotImplementedError) 为假,这在我的情况下是不可接受的。
              【解决方案15】:

              这在 Cesium DeveloperError 中很好地实现了:

              它的简化形式:

              var NotImplementedError = function(message) {
                  this.name = 'NotImplementedError';
                  this.message = message;
                  this.stack = (new Error()).stack;
              }
              
              // Later on...
              
              throw new NotImplementedError();
              

              【讨论】:

              • 这很好用,除了堆栈将包含错误构造函数的额外行,这可能是一个问题。
              • 另外,没有通过error instanceof Error 测试,这可能会有所帮助。
              【解决方案16】:

              以无法使用instanceof为代价,以下保留原始堆栈跟踪,不使用任何非标准技巧。

              // the function itself
              var fixError = function(err, name) {
                  err.name = name;
                  return err;
              }
              
              // using the function
              try {
                  throw fixError(new Error('custom error message'), 'CustomError');
              } catch (e) {
                  if (e.name == 'CustomError')
                      console.log('Wee! Custom Error! Msg:', e.message);
                  else
                      throw e; // unhandled. let it propagate upwards the call stack
              }
              

              【讨论】:

              • 为了能够使用 instanceof,您只需抛出新的 fixError 而不仅仅是 fixError
              • @BT:上面的fixError 函数不行。调用时添加new 只会创建一个被丢弃的对象。
              • 哦,我想我的意思是使用“instanceof fixError”——当然,“instanceof Error”就行不通了..我想那更糟..
              【解决方案17】:

              另一种选择,可能无法在所有环境中工作。至少保证它在 nodejs 0.8 中工作 这种方法使用了一种非标准的方式来修改内部 proto prop

              function myError(msg){ 
                    var e = new Error(msg); 
                    _this = this; 
                    _this.__proto__.__proto__ = e;
              }
              

              【讨论】:

                【解决方案18】:

                如果您使用的是 Node/Chrome。以下 sn-p 将为您提供满足以下要求的扩展。

                • err instanceof Error
                • err instanceof CustomErrorType
                • console.log() 使用消息创建时返回 [CustomErrorType]
                • console.log() 在创建时返回 [CustomErrorType: message] 而没有消息
                • throw/stack 提供错误创建时的信息。
                • 在 Node.JS 和 Chrome 中发挥最佳作用。
                • 将在 Chrome、Safari、Firefox 和 IE 8+ 中通过 instanceof 检查,但在 Chrome/Safari 之外没有有效堆栈。我可以接受,因为我可以在 chrome 中进行调试,但是需要特定错误类型的代码仍然可以跨浏览器运行。 如果您只需要 Node,您可以轻松删除 if 语句,一切顺利

                片段

                var CustomErrorType = function(message) {
                    if (Object.defineProperty) {
                        Object.defineProperty(this, "message", {
                            value : message || "",
                            enumerable : false
                        });
                    } else {
                        this.message = message;
                    }
                
                    if (Error.captureStackTrace) {
                        Error.captureStackTrace(this, CustomErrorType);
                    }
                }
                
                CustomErrorType.prototype = new Error();
                CustomErrorType.prototype.name = "CustomErrorType";
                

                用法

                var err = new CustomErrorType("foo");
                

                输出

                var err = new CustomErrorType("foo");
                console.log(err);
                console.log(err.stack);
                
                [CustomErrorType: foo]
                CustomErrorType: foo
                    at Object.<anonymous> (/errorTest.js:27:12)
                    at Module._compile (module.js:456:26)
                    at Object.Module._extensions..js (module.js:474:10)
                    at Module.load (module.js:356:32)
                    at Function.Module._load (module.js:312:12)
                    at Function.Module.runMain (module.js:497:10)
                    at startup (node.js:119:16)
                    at node.js:906:3
                
                /errorTest.js:30
                        throw err;
                              ^
                CustomErrorType: foo
                    at Object.<anonymous> (/errorTest.js:27:12)
                    at Module._compile (module.js:456:26)
                    at Object.Module._extensions..js (module.js:474:10)
                    at Module.load (module.js:356:32)
                    at Function.Module._load (module.js:312:12)
                    at Function.Module.runMain (module.js:497:10)
                    at startup (node.js:119:16)
                    at node.js:906:3
                

                【讨论】:

                  【解决方案19】:

                  以下内容对我有用,取自官方 Mozilla 文档Error

                  function NotImplementedError(message) {
                      var instance = new Error(message);
                      instance.name = 'NotImplementedError';
                  
                      Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
                      if (Error.captureStackTrace) {
                          Error.captureStackTrace(instance, NotImplementedError);
                      }
                      return instance;
                  }
                  
                  NotImplementedError.prototype = Object.create(Error.prototype, {
                      constructor: {
                          value: Error,
                          enumerable: false,
                          writable: true,
                          configurable: true
                      }
                  });
                  

                  【讨论】:

                    【解决方案20】:

                    为用户定义的错误类型的每个实例尝试一个新的原型对象。它允许instanceof 检查正常运行,并且在 Firefox 和 V8(Chome、nodejs)中正确报告类型和消息。

                    function NotImplementedError(message){
                        if(NotImplementedError.innercall===undefined){
                            NotImplementedError.innercall = true;
                            NotImplementedError.prototype = new Error(message);
                            NotImplementedError.prototype.name = "NotImplementedError";
                            NotImplementedError.prototype.constructor = NotImplementedError;
                    
                            return new NotImplementedError(message);
                        }
                        delete NotImplementedError.innercall;
                    }
                    

                    请注意,附加条目将在其他正确的堆栈之前。

                    【讨论】:

                    • 不起作用。试试:var a = new NotImplementedError('a'), b = new NotImplementedError('b');。现在a instanceof NotImplementedError == falseb instanceof NotImplementedError == true
                    【解决方案21】:

                    这是最快的方法:

                        let thisVar = false
                    
                        if (thisVar === false) {
                                throw new Error("thisVar is false. It should be true.")
                        }
                    

                    【讨论】:

                      【解决方案22】:

                      更简单的方法。你可以让你的对象继承自 Error 对象。 示例:

                      function NotImplementError(message)
                      {
                          this.message = message;
                          Error.call();
                          Error.call(message);
                      } 
                      

                      我们正在做的是使用函数 call(),它调用 Error 类的构造函数,因此与在其他面向对象语言中实现类继承基本相同。

                      【讨论】:

                        【解决方案23】:

                        MDN 有一个excellent example:

                        try {
                          throw new Error('Whoops!');
                        } catch (e) {
                          console.log(e.name + ': ' + e.message);
                        }
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 2022-09-30
                          • 2019-04-17
                          • 2017-10-03
                          • 2019-03-23
                          • 1970-01-01
                          • 1970-01-01
                          • 2021-10-29
                          相关资源
                          最近更新 更多