异常处理

所谓异常就是程序的非正常运行,通俗的说就是程序发生了错误。至于这些错误,有的是认为疏忽造成的异常(Exception),有的是程序本身的错误(Error)。

比如有的时候我们希望两个数相加,因为人为疏忽,代码里写成了乘号,那么这种错误大部分情况下是得不到你想要的结果的,但是幸运又不幸的是,这个程序没有语法错误,依然可以返回结果,但是无法报错。

另一种情况就是你的程序无法被JavaScript引擎执行,这种异常引擎会抛出一个异常,这个时候如果你没有捕获异常,那么程序就会被中断,无法执行下去。

code1:

alert('js运行了!')
let a = b + 1
alert('程序结束')

pic1

这个时候我们的浏览器客户端作为JavaScript引擎就会捕获一条异常报告,俗称报错了。 因为此时代码中的 b 是尚未定义的,抛出了ReferenceError这个异常,下面是JavaScript中经常遇到的异常类型,大概分类有如下几种:

  • 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

上面的六种异常对象都继承自Error对象。他们都支持以下两种构造方法: new Error(); new Error(“异常信息”);

try/catch/finlly语句

上面介绍了几种程序抛出的异常,那么现在就需要对异常进行处理,其中try从句中定义了需要处理和判断的代码块,catch从句中放置当程序发生异常后进行处理的代码,catch从句后跟随finally块,finally中放置清理代码,不管try块中是否产生异常。finally块中的逻辑代码都会执行,其中catch和finally都是可选的,但是必须选择两种中之一和try从句组成完整的语句。 try、catch、finally语句块都需要使用花括号括起来,即使语句中只有一条语句也不能省略,记住,这里的花括号是必须的

下面的代码说明了try/catch/finlly语句的用法和作用

try {
    // 这里是你可能会出现异常的代码
    //  可以通过throw直接抛出异常
    // 或者通过调用一个方法间接抛出
} catch(e) {
    // 当try语句块抛出了异常,这里的代码就会执行
    // 可以通过局部变量e来获取该异常Error对象的信息
    // 可以通过throw重新抛出异常
} finally {
    // 无论是否抛出异常,都会执行这里的代码
    // 终止语句块的方法有:
    // 1. 正常执行最后一条语句终止
    // 2. 通过break、continue、或return终止
    // 3. 抛出异常,被try捕获
    // 4. 抛出异常,异常未被捕获,继续向上传播
}

我们看到,catch后面接了个标识符e,这个标识符和函数参数很想,当捕获一个异常时,把和这个异常相关的值(比如Error对象)赋值给这个参数,和普通的变量不同,这条catch句中的标识符具有块级作用域,它只在catch语块内有定义。这个Error对象有几个主要属性,如下:

  • description: 错误描述 (仅IE可用).
  • fileName: 出错的文件名 (仅Mozilla可用).
  • lineNumber: 出错的行数 (仅Mozilla可用).
  • message: 错误信息 (在IE下同description)
  • name: 错误类型.
  • number: 错误代码 (仅IE可用).
  • stack: 像Java中的Stack Trace一样的错误堆栈信息 (仅Mozilla可用).

下面就使用一个try/catch语句把pic1中的代码包裹起来

try{
    //这里放置可能会出错的代码
    let a = b + 1
} catch(e)
{
    //代码出错后执行这里。
    console.debug(' name: ' + e.name +  
          ' message: ' + e.message +  
          ' lineNumber: ' + e.lineNumber +  
          ' fileName: ' + e.fileName +  
          ' stack: ' + e.stack);  
} finally {
    console.log('执行了finally')
}

将上面的代码复制到chrome控制台,会看到下面的信息,说明异常已经被捕获,并且,最终执行了finally pic2

通常状况下,解释器执行到try语句块的尾部,然后开始执行finally中的代码,以便进行必要的清理工作。当由于return、continue、break语句使得解释器跳出try语句块时,解释器在执行新的目标代码之前先执行finally中的代码。

如果在try中产生了异常,而且存在一条与之相关的catch从句来处理这个异常,解释器首先执行catch中的逻辑,然后执行finally中的逻辑,如果不存在处理异常的局部catch从句,解释器会首先执行finally中的逻辑,然后向上传播异常,直到找到能处理这个异常的catch从句。

如果finally快使用了return、continue、break或者throw语句时程序发生跳转,或者通过调用了抛出异常的方法改变了程序执行流程,不管这个跳转使程序挂起还是继续执行,解释器都会将其忽略。例如finally从句抛出一个异常,这个异常将替代正在抛出的异常。如果finally从句运行倒了return语句,尽管已经抛出了异常且这个异常还没有处理,这个方法依然会正常返回。

throw语句

在JavaScript运行的时候,若使用throw语句时就会电视的抛出异常。 throw语句的语法如下:

throw expression

expression的值是任意类型的。可以抛出代表错误码的数字亦或是让人明白意思的字符串。JavaScript解释器抛出异常的时候通常采用Error类型和其子类型。

function getMoney(money) {
    // 若传入的参数非法,直接抛出异常
    if (money < 0) 
        throw new Error('金额不能为负数')
    return money
}

在chrome控制台里试试,这个时候如果传入的参数小于0就会直接抛出一个自定义字符串的异常了,见下图:

pic#

最后

当程序抛出异常时,JavaScript解释器会立即停止当前正在执行的逻辑,并跳转至就近的异常处理程序,如果抛出异常的代码块中没有try/catch语句,解释器会检查更高层次的闭合代码块,看它是否有关联异常处理程序。以此类推,直到找到异常处理程序为止。

注意:异步方法调用并不能直接使用 try{}catch(e){} 块捕获异常。

results matching ""

    No results matching ""