有的时候,我们编写的代码可能会报错, 而浏览器报错是十分危险的,因为该错误后续代码一律不执行
或者有的时候,我们编写了一个工具函数,而调用者使用错误,此时我们希望给调用者相关的错误提示信息的时候
我们就可以抛出对应的错误,也可以捕获对应的错误,并对错误进行处理
抛出异常
throw语句用于抛出一个用户自定义的异常
当遇到throw语句时,当前的函数执行会被停止(throw后面的语句不会执行)
throw表达式就是在throw后面可以跟上一个表达式来表示具体的异常信息
throw表达式后边可以跟上如下类型:
- 基本数据类型:比如number、string、Boolean
- 对象类型:对象类型可以包含更多的信息
function foo() {
console.log(1)
// throw后边可以接基本数据类型和复杂数据类型
// 一般使用对象,因为使用对象可以表达更具体的错误信息
throw { message: 'error msg', code: -1001 }
// throw抛出异常后,throw表达式后边的代码将不在继续执行
console.log(2)
console.log(3)
}
foo()
然而我们每次都需要自己编写对应的错误信息,就会比较繁琐
为此,JavaScript已经给我们提供了一个Error类,我们可以直接创建这个类的实例对象
Error的实例对象包含以下三个属性:
| 属性名 | 描述 |
|---|---|
| messsage | 创建Error对象时传入的message |
| name | Error的名称,通常和类的名称一致 |
| stack | 整个Error的错误信息,包括函数的调用栈 当我们直接打印Error对象时,打印的就是stack |
为了可以表示更为具体的错误信息,JS提供了Error的一些子类
| 子类 | 说明 |
|---|---|
| RangeError | 下标值越界时使用的错误类型 |
| SyntaxError | 解析语法错误时使用的错误类型 |
| TypeError | 出现类型错误时,使用的错误类型 |
function foo() {
try {
throw new Error('err msg')
} catch (e) {
console.log(e.message) // => err msg
console.log(e.name) // => Error -- 错误对应的类名
console.log(e.stack) // => 错误调用栈
// 所谓错误调用者 -- 即错误是在哪里被触发的,一层层是怎么被传递到浏览器顶层的
}
}
function bar() {
foo()
}
bar()
捕获异常
一个函数抛出了异常,调用它的时候程序会被强制终止
这是因为如果我们在调用一个函数时,这个函数抛出了异常,但是我们并没有对这个异常进行处理,那么这个异常会继续传递到上一个函数调用中,而如果到了最顶层(全局)的代码中依然没有对这个异常的处理代码,这个时候就会在控制台中报错并且终止程序的运行
但是很多情况下当出现异常时,我们并不希望程序直接推出,而是希望可以正确的处理异常
这个时候,我们就可以使用try-catch来捕获对应的异常并进行处理
function foo() {
// 使用try-catch来捕获异常
try {
throw new Error('err msg')
// return 'try'
} catch(e) {
console.log(e.message)
return 'catch'
} finally {
// finally表示最终一定会被执行的代码结构
console.log('无论是否抛出异常,都会被执行的代码')
// 如果finally和try/catch中都有返回值,那么会使用finally中的返回值
// 相当于后边的返回值 会将前边的返回值 给覆盖掉
return 'finally'
}
}
function bar() {
const res = foo()
console.log(res) // => finally
}
bar()
在ES10(ES2019)中,catch后面绑定的error如果不使用的时候,是可以省略的,但是不推荐,可读性变差
function foo() {
try {
throw new Error('err msg')
} catch {
console.log('发生了错误')
} finally {
console.log('无论是否抛出异常,都会被执行的代码')
}
}
function bar() {
foo()
}
bar()