JavaScript中的自定义例外

我可以在JavaScript中为用户定义的exception定义自定义types吗? 如果可以的话,我会怎么做?

来自: http : //www.webreference.com/programming/javascript/rg32/2.html

throw { name: "System Error", level: "Show Stopper", message: "Error detected. Please contact the system administrator.", htmlMessage: "Error detected. Please contact the <a href=\"mailto:sysadmin@acme-widgets.com\">system administrator</a>.", toString: function(){return this.name + ": " + this.message;} }; 

你可以实现你自己的exception和他们的处理例如像这样:

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

还有一种捕获typesexception的语法,虽然这不适用于每个浏览器(例如不在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"); } 

您应该创build一个自定义exception,从原型inheritanceError。 例如:

 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; 

这基本上是一个简化的版本,上面提到了堆栈跟踪在Firefox和其他浏览器上工作的增强function。 它符合他发布的相同testing:

用法:

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

它会performance出预期:

 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! 

是。 你可以扔任何你想要的东西:整数,string,对象等等。 如果你想抛出一个对象,那就简单地创build一个新的对象,就像你在其他情况下创build一个对象一样,然后抛出它。 Mozilla的Javascript参考有几个例子。

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

我经常使用原型inheritance的方法。 重写toString()给你的好处是,像Firebug这样的工具将logging实际的信息,而不是[object Object]到控制台的未捕获的exception。

使用instanceof来确定exception的types。

main.js

 // just an exemplary namespace var ns = ns || {}; // include JavaScript of the following // source files here (eg 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(); 

以下是如何创build与本地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...'); 

它会performance出预期:

 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 。 如果你不需要它,你可以简化一切。

使用throw语句。

JavaScript不关心什么样的exception(就像Java一样)。 JavaScript只是注意到,有一个例外,当你捕捉它,你可以“看”什么例外“说”。

如果你必须抛出不同的exceptiontypes,我build议使用包含exceptionstring/对象的variables,即消息。 在你需要的地方使用“throw myException”并在catch中比较捕获到的exception和myException。

简而言之:

  • 如果您使用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; } 
  • 替代scheme:使用疏散框架

说明:

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

因为CustomError的一个实例不再被认为是这样的。

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

事实上,从Babel的官方文档,你不能扩展任何内置的JavaScript类 ,如DateArrayDOMError

这里描述的问题是:

  • 本机扩展了HTMLELement,Array和其他
  • 该类的类的一个对象,如Array,Number,Object,String或Error等基types扩展不是此类的实例

那么其他的答案呢?

所有给出的答案解决了instanceof问题,但是你失去了常规错误console.log

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

而使用上面提到的方法,不仅你解决instanceof问题,但你也保持常规错误console.log

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

在MDN中查看这个例子 。

如果你需要定义多个错误(在这里testing代码!):

 function createErrorType(name, initFunction) { function E(message) { this.message = message; if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor); else this.stack = (new Error()).stack; initFunction && initFunction.apply(this, arguments); } E.prototype = Object.create(Error.prototype); E.prototype.name = name; E.prototype.constructor = E; return E; } var InvalidStateError = createErrorType( 'InvalidStateError', function (invalidState, acceptedStates) { this.message = 'The state ' + invalidState + ' is invalid. Expected ' + acceptedStates + '.'; }); var error = new InvalidStateError('foo', 'bar or baz'); function assert(condition) { if (!condition) throw new Error(); } assert(error.message); assert(error instanceof InvalidStateError); assert(error instanceof Error); assert(error.name == 'InvalidStateError'); assert(error.stack); error.message; 

代码主要从以下方面复制: 在JavaScript中扩展错误的好方法是什么?

与ES2015类一起使用的组件的答案的替代scheme

 class InvalidArgumentException extends Error { constructor(message) { super(); Error.captureStackTrace(this, this.constructor); this.name = "InvalidArgumentException"; this.message = message; } } 
 //create error object var error = new Object(); error.reason="some reason!"; //business function function exception(){ try{ throw error; }catch(err){ err.reason; } } 

现在,我们设置添加我们想要的错误对象的原因或任何属性,并检索它。 通过使错误更合理。