第5章:02-throw/try/catch/finally 语句

异常:发生了某种异常情况或错误时产生的一个信号。

抛出异常:用信号通知发生了错误或异常状况。(使用 throw 语句)

捕获异常:采取必要的手段处理这个信号。(使用 catch 语句)

throw/try/catch/finally 语句

throw 语句作用:显式地抛出异常。

throw 语法throw exception;exception 的值是任意类型)


try/catch/finally 语句是 JS 的异常处理机制。

try:定义了需要处理的异常所在的代码块。

catch:当 try 块内某处发生了异常时,调用 catch 内的代码逻辑。

finally:不管 try 块中是否发生异常,finally 块内的逻辑总是执行。

注意:catch 从句和 finally 从句是可选的,但 try 从句需要至少两者之一组成完整的语句。也就是说,try 从句不能单独存在。


JS 解析器抛出异常的时候通常采用 Error 类型或其子类型。Error 的 name 属性表示错误类型,message 属性表示错误的提示信息。

function fun(x) {
  // 如果输入参数是非法的,则抛出一个异常
  if (x < 0) throw new Error('x 不能是负数')
  return x
}
fun(-1);

上面代码中,输入的 x 是非法的,程序通过 throw 语句显示的抛出一个异常。


当抛出异常时,JS 解析器会立即停止当前正在执行的逻辑,并跳转至最近的异常处理程序。

function fun(x) {
  try {
    if (x < 0) {
      console.log('第4行:此行代码可以执行...')
      throw new Error('发生异常...')
      console.log('第6行:此行代码无法执行...')
    }
  } catch (e) {
    console.log('第9行:异常在此被捕获--' + e)
  }
}
fun(-1)

上面代码中,由于 throw 从句会抛出一个异常并停止正在执行的逻辑,所以第6行不会被执行。抛出的异常会被 catch 从句捕获并处理。


如果抛出异常的代码块没有相关联的 catch 从句,解析器会检查更高层的闭合代码块是否有异常处理程序。以此类推,直到找到异常处理程序为止。否则,JS 会把该异常当做程序错误来处理,并报告给用户。

function fun1 (x) {
    if (x < 0) {
      throw new Error('此异常发生在 fun1 中...')
    }
}

function fun2 (x) {
  try {
    fun1(x);
  } catch (e) {
    console.log('在 fun2 中处理异常:' + e)
  }
}

fun2(-1)

上面代码中,fun2 在 内部中调用了 fun1。程序在 fun1 中抛出异常,但是该代码块中没有异常处理程序,解析器会向上一层(fun2)代码块中检查,所以异常会被 fun2 中的 catch 从句捕获并处理。


不管是 try 从句中是否产生异常,finally 从句内的逻辑总是会执行。

function fun () {
  try {
    console.log('try')
  } finally {
    console.log('finally')
  }
}

fun()

上面代码中,try 从句中的逻辑不发生异常,之后会接着执行 finally 从句中的逻辑。


如果在 try 从句中发生了异常,并存在相关联的局部 catch 从句,解析器会先执行 catch 从句中的逻辑,然后执行 finally 从句中的逻辑。

function fun () {
  try {
    throw new Error('try 中发生异常...')
  } catch (e) {
    console.log('在 catch 中捕获异常:' + e);
  } finally {
    console.log('finally: 我都会被执行')
  }
}

fun()

上面代码中,try 从句中抛出异常,被局部 catch 从句捕获并处理,接着执行 finally 从句中的逻辑。


如果不存在处理异常的局部 catch 从句,解析器会首先执行 finally 中的逻辑,然后向上传播这个异常,直到找到能处理这个异常的 catch 从句。

function fun1 () {
  try {
    throw new Error('try:不行了,我要抛出异常了...')
  } finally {
    console.log('finally:先执行我,再传播异常...')
  }
}

function fun2 () {
  try {
    fun1()
  } catch (e) {
    console.log('catch:嘻嘻,又捕获到一个小笨蛋--' + e)
  }
}

fun2()

上面代码中,try 从句中抛出异常,但没有局部 catch 从句处理异常,所以会先执行 finally 从句,然后被上一层的 catch 从句捕获。


当由于 returncontinuebreak 语句使得解析器跳出 try 从句时,解析器在执行新的目标代码之前会先执行 finally 从句中的逻辑。

function fun1 () {
  try {
    return 'cez'
  } finally {
    console.log('finally: 在执行新的目标代码之前,会先执行我哦...')
  }
}

function fun2 () {
  fun1()
  console.log('新的目标代码:我执行在 finally 从句之后哦...')
}

fun2()


如果在 tryfinally 从句中都抛出异常,finally 中的异常将替代 try 中的异常。

function fun1 () {
  try {
    throw new Error('在 try 中抛出异常...')
  } finally {
    throw new Error('在 finally 中抛出异常...')
  }
}

function fun2 () {
  try {
    fun1()
  } catch (e) {
    console.log('catch:'+ e)
  }
}

fun2()



如果 finally 从句中有 return 语句,尽管抛出了异常并且这个异常还没有处理,但这个方法依然会正常返回。

function fun1 () {
  try {
    throw new Error('在 try 中抛出异常...')
  } finally {
    return 'finally'
  }
}

function fun2 () {
  try {
    console.log(fun1())
  } catch (e) {
    console.log('catch:' + e)
  }
}

fun2()

如果 finally 中有 return 语句,则该方法会有正常的返回值,并且 try 中抛出的异常将不会被更高层的 catch 从句捕获到,但会被局部的 catch 从句捕获,如下:

function fun1 () {
  try {
    throw new Error('在 try 中抛出异常...')
  } catch (e) {
    console.log('局部 catch:' + e)
  } finally {
    return 'finally'
  }
}

function fun2 () {
  console.log(fun1())
}

fun2()

此时 try 中抛出的异常会被局部 catch 从句捕获。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值