抛出异常
在 js 中,有时候我们需要处理一些异常或错误。比如编写的某个函数所接收的参数要求是 Number 类型的,如果在该函数被调用时传入的是字符串,就需要发出提醒。此时我们可以使用 throw 语句来抛出个异常:
// 例 1
function fn(num) {
if (typeof num !== 'number') throw '需传入数字'
console.log(num) // 不会打印
}
fn('0')
console.log('不会执行')
执行例 1 的代码结果如下:
因为第 7 行传入的是字符串,所以会导致第 3 行 throw
语句的执行,那么在函数 fn 内,之后的语句就不会执行了,这点和 return
一样。因为我们没有对第 7 行的 fn 函数的执行做异常捕获的操作,所以程序终止,其后的第 8 行也不会执行。
抛出的表达式类型
基本数据类型
例 1 中我们就是是抛出了一个基本数据类型 —— 字符串,当然还可以是数字等其它基本类型的数据。
对象
我们也可以抛出一个对象,这样可以传递更多的信息:
// 例 1.1
function fn(num) {
if (typeof num !== 'number')
throw {
code: -1,
msg: '类型错误'
}
console.log(num)
}
类的实例对象
如果每次抛出异常我们都像例 1.1 这样写个对象会比较繁琐,所以可以创建一个类,比如例 1.2 的 myError
,帮我们创建包含了错误信息的对象:
// 例 1.2
class myError {
constructor(code, msg) {
this.code = code
this.msg = msg
}
}
function fn(num) {
if (typeof num !== 'number') throw new myError(-1, '类型错误')
console.log(num)
}
这样执行 fn 时,如果不做异常捕获就会打印如下的报错信息:
Error 类的实例对象
事实上我们并不需要自己定义一个类来创建错误对象,js 本身就为我们提供了这么一个类 Error
,构建错误对象时传入错误的描述信息即可:
// 例 1.3
function fn(num) {
if (typeof num !== 'number') throw new Error('类型错误')
console.log(num)
}
fn('0')
在 node 中执行例 1.3,得到的结果会比我们自己定义的 myError
多出函数的调用栈的信息:
我们可以直接通过 Error
实例对象的 stack
属性查看调用栈,还有 message
和name
:
// 例 1.3.1
function fn(num) {
if (typeof num !== 'number') {
const err = new Error('类型错误')
console.log('name:', err.name)
console.log('message:', err.message)
console.log('stack:', err.stack)
throw err
}
console.log(num)
}
fn('0')
在 node 中执行例 1.3.1,第 5 ~ 7 的输出结果如下:
如果我们对例 1.3 进行些改造,不直接执行 fn('0')
而是让它在 bar 函数内被调用,然后在 foo 函数内调用 bar ,最后执行 foo()
:
// 例 1.3.2
function fn(num) {
if (typeof num !== 'number') throw new Error('类型错误')
console.log(num)
}
function foo() {
bar()
}
function bar() {
fn('0')
}
foo()
就可以看到调用栈信息又多了 2 条:
Error 的子类
Error 还有几个子类,比如上面的这些例子,因为属于类型错误,所以可以用更具体的 TypeError
类来生成错误对象:
// 例 1.4
function fn(num) {
if (typeof num !== 'number') throw new TypeError('类型错误')
console.log(num)
}
fn('0')
另外还有诸如引用错误 ReferenceError
和语法错误 SyntaxError
等。
处理异常
若一个异常被抛出而最终没有被捕获,那么会导致程序的终止执行。之所以加了“最终”两个字,是因为如果函数执行时抛出的异常没有被处理,异常会传递给执行了该函数的函数调用。以例 1.3.2 为例,第 10 行执行 fn('0')
导致抛出了异常,我们又没有在第 10 行对fn('0')
进行异常捕获,那么异常就会传给第 7 行的 bar()
,再传给第 12 行,也就是最顶层的 foo()
,此时还是没有对异常进行处理,才会导致报错并终止程序的运行。 只要我们在异常传递过程中的任何一处用 try...catch
语句对异常进行了捕获,比如下面的例 2,那么程序就不会被终止,异常会作为参数传递给 catch
子句,也就是第 15 行的 error
:
// 例 2
function fn(num) {
if (typeof num !== 'number') throw new Error('类型错误')
console.log(num) // 不会执行
}
function foo() {
bar()
}
function bar() {
fn('0')
}
try {
foo()
console.log('我不会继续执行')
} catch (error) {
console.log('error:', error.message)
} finally {
console.log('我无论是否有异常抛出都会执行')
}
console.log('我会继续执行')
执行例 2 的结果如下:
可以看到例 2 第 17 行还有个 finally
子句,无论是否有异常抛出或捕获它总是执行。
P.S. 从 ES10(ES2019)开始,第 15 行的 catch
子句可以省略掉 (error)
,也就是不去获取错误信息。
js中常见的系统异常:
- EvalError: raised when an error occurs executing code in eval() 当一个错误发生在()执行的代码
- RangeError: raised when a numeric variable or parameter is outside of its valid range 当一个数值变量或参数超出其有效范围时引发的
- ReferenceError: raised when de-referencing an invalid reference 无效的饮用
- SyntaxError: raised when a syntax error occurs while parsing code in eval() 当发生语法错误在()解析代码,而
- TypeError: raised when a variable or parameter is not a valid type 当一个变量或参数不是一个有效的类型时引发
- URIError: raised when encodeURI() or decodeURI() are passed invalid parameters 当encodeuri()或decodeuri()传递了无效的参数
注:上面的六种异常对象都继承自Error对象:
try {
throw new Error("Whoops!");
} catch (e) {
console.log(e.name + ": " + e.message);
}
总结
到此这篇关于JS中异常抛出和处理方法的文章就介绍到这了,更多相关JS异常抛出与处理内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!