当前位置:  开发笔记 > 编程语言 > 正文

JavaScript中的自定义例外

如何解决《JavaScript中的自定义例外》经验,为你挑选了10个好方法。

我可以在JavaScript中为用户定义的异常定义自定义类型吗?如果可以的话,我该怎么做?



1> jon077..:

来自WebReference:

throw { 
  name:        "System Error", 
  level:       "Show Stopper", 
  message:     "Error detected. Please contact the system administrator.", 
  htmlMessage: "Error detected. Please contact the system administrator.",
  toString:    function(){return this.name + ": " + this.message;} 
}; 


你怎么会发现这样的错误,可能会检查它的名字?
添加toString方法将使它在javascript控制台中很好地显示.没有它显示如下:未显示#与toString它显示如下:未捕获系统错误:检测到错误.请联系系统管理员.
除非您从Error继承,否则这将不允许您堆栈跟踪
@ b.long它出现在"JavaScript:The Good Parts"(伟大的IMO书)中.此Google图书预览会显示以下部分:http://books.google.com/books?id=PXa2bby0oQ0C&pg=PA32&lpg=PA32

2> asselin..:

您应该创建一个原型继承自Error的自定义异常.例如:

function InvalidArgumentException(message) {
    this.message = message;
    // Use V8's native method if available, otherwise fallback
    if ("captureStackTrace" in Error)
        Error.captureStackTrace(this, InvalidArgumentException);
    else
        this.stack = (new Error()).stack;
}

InvalidArgumentException.prototype = Object.create(Error.prototype);
InvalidArgumentException.prototype.name = "InvalidArgumentException";
InvalidArgumentException.prototype.constructor = InvalidArgumentException;

这基本上是上面发布的disfated的简化版本,其中增强了堆栈跟踪在Firefox和其他浏览器上的工作.它满足了他发布的相同测试:

用法:

throw new InvalidArgumentException();
var err = new InvalidArgumentException("Not yet...");

它的行为是预期的:

err instanceof InvalidArgumentException          // -> true
err instanceof Error                             // -> true
InvalidArgumentException.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err)               // -> true
err.constructor.name                             // -> InvalidArgumentException
err.name                                         // -> InvalidArgumentException
err.message                                      // -> Not yet...
err.toString()                                   // -> InvalidArgumentException: Not yet...
err.stack                                        // -> works fine!



3> Sergey Ilins..:

您可以实现自己的异常及其处理,例如:

// define exceptions "classes" 
function NotNumberException() {}
function NotPositiveNumberException() {}

// try some code
try {
    // some function/code that can throw
    if (isNaN(value))
        throw new NotNumberException();
    else
    if (value < 0)
        throw new NotPositiveNumberException();
}
catch (e) {
    if (e instanceof NotNumberException) {
        alert("not a number");
    }
    else
    if (e instanceof NotPositiveNumberException) {
        alert("not a positive number");
    }
}

还有另一种捕获类型异常的语法,虽然这不适用于每个浏览器(例如不在IE中):

// define exceptions "classes" 
function NotNumberException() {}
function NotPositiveNumberException() {}

// try some code
try {
    // some function/code that can throw
    if (isNaN(value))
        throw new NotNumberException();
    else
    if (value < 0)
        throw new NotPositiveNumberException();
}
catch (e if e instanceof NotNumberException) {
    alert("not a number");
}
catch (e if e instanceof NotPositiveNumberException) {
    alert("not a positive number");
}


MSN网站上有关于条件捕获的警告:**非标准**此功能是非标准的,不在标准轨道上.不要在面向Web的生产站点上使用它:它不适用于每个用户.实现之间可能存在很大的不兼容性,并且行为可能在将来发生变化.

4> Rob Kennedy..:

是.你可以扔任何你想要的东西:整数,字符串,对象,等等.如果要抛出一个对象,那么只需创建一个新对象,就像在其他情况下创建一个对象一样,然后抛出它.Mozilla的Javascript参考有几个例子.



5> Morgan ARR A..:
function MyError(message) {
 this.message = message;
}

MyError.prototype = new Error;

这允许使用像..

try {
  something();
 } catch(e) {
  if(e instanceof MyError)
   doSomethingElse();
  else if(e instanceof Error)
   andNowForSomethingCompletelyDifferent();
}



6> JBE..:

简而言之:

如果您使用的是没有转发器的ES6 :

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

请参阅使用ES6语法扩展Javascript中的错误,了解当前的最佳做法

如果您使用的是Babel转换器:

选项1:使用babel-plugin-transform-b​​uiltin-extend

选项2:自己动手(灵感来自同一个图书馆)

    function CustomError(...args) {
      const instance = Reflect.construct(Error, args);
      Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(this));
      return instance;
    }
    CustomError.prototype = Object.create(Error.prototype, {
      constructor: {
        value: Error,
        enumerable: false,
        writable: true,
        configurable: true
      }
    });
    Reflect.setPrototypeOf(CustomError, Error);

如果您使用的是纯ES5:

function CustomError(message, fileName, lineNumber) {
  const instance = new Error(message, fileName, lineNumber);
  Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
  return instance;
}
CustomError.prototype = Object.create(Error.prototype, {
  constructor: {
    value: Error,
    enumerable: false,
    writable: true,
    configurable: true
  }
});
if (Object.setPrototypeOf){
    Object.setPrototypeOf(CustomError, Error);
} else {
    CustomError.__proto__ = Error;
}

替代方案:使用Classtrophobic框架

说明:

为什么使用ES6和Babel扩展Error类是个问题?

因为CustomError的实例不再被识别.

class CustomError extends Error {}
console.log(new CustomError('test') instanceof Error);// true
console.log(new CustomError('test') instanceof CustomError);// false

事实上,从巴贝尔的官方文档,你不能扩展任何内置的JavaScript类如Date,Array,DOMError.

这个问题在这里描述:

Native扩展了HTMLELement,Array等

由类,数组,对象,字符串或错误等基类型扩展的类的对象不是此类的实例

其他SO答案怎么样?

所有给出的答案都可以解决instanceof问题,但是您会丢失常规错误console.log:

console.log(new CustomError('test'));
// output:
// CustomError {name: "MyError", message: "test", stack: "Error?    at CustomError (:4:19)?    at :1:5"}

而使用上述方法,不仅可以解决instanceof问题,还可以保留常规错误console.log:

console.log(new CustomError('test'));
// output:
// Error: test
//     at CustomError (:2:32)
//     at :1:5



7> disfated..:

以下是如何创建与本机Error行为完全相同的自定义错误.这种技术只适用于Chrome和Node.js的现在.如果你不明白它的作用,我也不建议使用它.

Error.createCustromConstructor = (function() {

    function define(obj, prop, value) {
        Object.defineProperty(obj, prop, {
            value: value,
            configurable: true,
            enumerable: false,
            writable: true
        });
    }

    return function(name, init, proto) {
        var CustomError;
        proto = proto || {};
        function build(message) {
            var self = this instanceof CustomError
                ? this
                : Object.create(CustomError.prototype);
            Error.apply(self, arguments);
            Error.captureStackTrace(self, CustomError);
            if (message != undefined) {
                define(self, 'message', String(message));
            }
            define(self, 'arguments', undefined);
            define(self, 'type', undefined);
            if (typeof init == 'function') {
                init.apply(self, arguments);
            }
            return self;
        }
        eval('CustomError = function ' + name + '() {' +
            'return build.apply(this, arguments); }');
        CustomError.prototype = Object.create(Error.prototype);
        define(CustomError.prototype, 'constructor', CustomError);
        for (var key in proto) {
            define(CustomError.prototype, key, proto[key]);
        }
        Object.defineProperty(CustomError.prototype, 'name', { value: name });
        return CustomError;
    }

})();

作为一种结果,我们得到了

/**
 * name   The name of the constructor name
 * init   User-defined initialization function
 * proto  It's enumerable members will be added to 
 *        prototype of created constructor
 **/
Error.createCustromConstructor = function(name, init, proto)

然后你可以像这样使用它:

var NotImplementedError = Error.createCustromConstructor('NotImplementedError');

NotImplementedError按照您的意愿使用Error:

throw new NotImplementedError();
var err = new NotImplementedError();
var err = NotImplementedError('Not yet...');

它的行为是预期的:

err instanceof NotImplementedError               // -> true
err instanceof Error                             // -> true
NotImplementedError.prototype.isPrototypeOf(err) // -> true
Error.prototype.isPrototypeOf(err)               // -> true
err.constructor.name                             // -> NotImplementedError
err.name                                         // -> NotImplementedError
err.message                                      // -> Not yet...
err.toString()                                   // -> NotImplementedError: Not yet...
err.stack                                        // -> works fine!

注意,这error.stack是绝对正确的,并且不包括NotImplementedError构造函数调用(感谢v8 Error.captureStackTrace()).

注意.有丑陋的eval().使用它的唯一原因是得到正确的err.constructor.name.如果您不需要它,您可以稍微简化一切.


`Error.apply(self,arguments)`是[指定不起作用](http://es5.github.io/#x15.11.1).我建议[复制堆栈跟踪](https://coderwall.com/p/m3-cqw),这是跨浏览器兼容的.

8> Matthias..:

我经常使用原型继承的方法.覆盖toString()为您提供了一个优势,即像Firebug这样的工具会记录实际信息而不是[object Object]控制台中的未捕获异常.

使用instanceof以确定异常的类型.

main.js

// just an exemplary namespace
var ns = ns || {};

// include JavaScript of the following
// source files here (e.g. by concatenation)

var someId = 42;
throw new ns.DuplicateIdException('Another item with ID ' +
    someId + ' has been created');
// Firebug console:
// uncaught exception: [Duplicate ID] Another item with ID 42 has been created

Exception.js

ns.Exception = function() {
}

/**
 * Form a string of relevant information.
 *
 * When providing this method, tools like Firebug show the returned 
 * string instead of [object Object] for uncaught exceptions.
 *
 * @return {String} information about the exception
 */
ns.Exception.prototype.toString = function() {
    var name = this.name || 'unknown';
    var message = this.message || 'no description';
    return '[' + name + '] ' + message;
};

DuplicateIdException.js

ns.DuplicateIdException = function(message) {
    this.name = 'Duplicate ID';
    this.message = message;
};

ns.DuplicateIdException.prototype = new ns.Exception();



9> Brunno..:

ES6

使用新的class和extend关键字,现在变得更加容易:

class CustomError extends Error {
  constructor(message) {
    super(message);
    //something
  }
}



10> Xn0vv3r..:

使用throw语句.

JavaScript并不关心异常类型是什么(就像Java那样).JavaScript只是注意到,有一个例外,当你抓住它时,你可以"看"异常"说".

如果您必须抛出不同的异常类型,我建议使用包含异常的字符串/对象的变量,即消息.在需要的地方使用"throw myException"并在catch中将捕获的异常与myException进行比较.

推荐阅读
小妖694_807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有