JavaScript
原生提供了7种错误类型,分别是 Error
, EvalError
, SyntaxError
, RangeError
, ReferenceError
, TypeError
, 和 URIError
。当咱们在编写提供给其余开发者使用的库(包)时,为了在必要的时候给予开发者错误信息反馈(例如,开发者所传参数类型不正确),咱们一般会抛出错误,可是原生提供的这些错误类型不够有针对性,不能让开发者一眼就能看出是咱们的库所抛出的错误,因此咱们须要定制本身的错误类型,当开发者错误使用库而且运行代码时可以在控制台看到咱们所定义的错误类型,例如:javascript
CustomError: something bad happened.
而不是 :java
Error: something bad happened.
另外,咱们能够为本身的错误类型添加额外的信息字段,原生提供的错误只有 name
(错误类型),message
(错误信息),stack
(部分js环境提供堆栈追踪信息),这些字段可能不可以知足咱们的需求,咱们想给咱们所抛出的错误添加一个 reason
字段来代表抛出错误的缘由,那么咱们就须要自定义错误类型。app
Error
类咱们自定义的错误类型最好继承自Error
类,但这并非强制规定,这只是一种良好的代码习惯,由于当开发者经过 try / catch
捕获到异常时,可能会进行进一步的判断:函数
if (error instanceof Error) { ... }
这样咱们的自定义错误才能被有效捕获。测试
ES5
自定义错误的写法function CustomError(message) { // 实例化自定义错误时所传的错误信息参数 this.message = message // name 指明该错误类型(同时在控制台所打印的错误类型即由此字段指明),不指明默认为Error。 this.name = 'CustomError' // 捕获到当前执行环境的堆栈追踪信息,为自定义错误实例添加 `stack` 字段进行保存, // 第二个参数的含义为:堆栈追踪只会展现到`CustomError`这个函数(即自定义错误的构造函数)被调用以前。 Error.captureStackTrace(this, CustomError) } // 原型链继承 (详见 JS高程 一书) CustomError.prototype = new Error // 在自定义错误的原型上添加构造器函数为CustomError, // 若不添加构造器,当获取自定义错误的构造器时,获取的是上一步`new Error`实例的原型的构造器,即`Error`构造函数 CustomError.prototype.constructor = CustomError
ES6
自定义错误的写法ES6 添加了 class 这一语法糖,能够方便的写出继承关系:this
class CustomError extends Error { constructor (message) { super(message) this.name = 'CustomError', // 这一步可不写,默认会保存堆栈追踪信息到自定义错误构造函数以前, // 而若是写成 `Error.captureStackTrace(this)` 则自定义错误的构造函数也会被保存到堆栈追踪信息 Error.captureStackTrace(this, this.constructor) } }
接下来咱们经过ES 5/6 两种不一样的写法来自定义错误类型后, 使用下面的代码在 Node.js
中进行测试。咱们先推测堆栈追踪自栈顶向下依次应该是:prototype
at new CustomError // 若堆栈追踪到自定义错误的构造函数时,会有此打印 at c at b at a
测试代码:code
// `c` 函数抛出自定义错误 function c() { throw new CustomError('something bad happened!') } // `b` 函数调用 `c` function b() { c() } // `a` 函数调用 `b` function a() { b() } try { a() // 执行 `a` 函数 } catch (err) { // 判断所抛出的错误是否为 `Error` 的子类实例 if (err instanceof Error) { console.log('Capture the error:') console.log(err.stack) // 打印堆栈追踪信息 console.log(err instanceof CustomError, err instanceof Error) // 错误是否为(或继承自)CustomError 和 Error 类型 console.log(err.constructor.name) // 自定义错误的构造器名称 } }
对比ES 5/6 两种自定义错误的方式,运行结果均为:继承
Capture the error: CustomError: something bad happened! at c (/Users/xavier/Documents/demos/javascript-demo/test.js:19:8) at b (/Users/xavier/Documents/demos/javascript-demo/test.js:23:2) at a (/Users/xavier/Documents/demos/javascript-demo/test.js:27:2) at Object.<anonymous> (/Users/xavier/Documents/demos/javascript-demo/test.js:31:2) at Module._compile (internal/modules/cjs/loader.js:689:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10) at Module.load (internal/modules/cjs/loader.js:599:32) at tryModuleLoad (internal/modules/cjs/loader.js:538:12) at Function.Module._load (internal/modules/cjs/loader.js:530:3) at Function.Module.runMain (internal/modules/cjs/loader.js:742:12) true true CustomError
测试说明两种自定义错误的方式效果相同,ES6 class
写法虽然方便,但只是语法糖,ES5
的写法有利于咱们理解 JavaScript
基于原型的继承方式,二者各有利弊。ip