# try...catch...finally ```js "use strict"; var r1, r2, s = null; try{ r1 = s.length; // TypeError:null变量没有length属性 r2 = 100; }catch(e){ console.log("出错了:" + e); }finally{ console.log("finally"); } console.log("r1 = " + r1); console.log("r2 = " + r2); ``` 输出 ```bash 出错了:TypeError: Cannot read property 'length' of null finally r1 = undefined r2 = undefined ``` 当代码块被`try { ... }`包裹的时候,就表示这部分代码执行过程中可能会发生错误,一旦发生错误,就不再继续执行后续代码,转而跳到`catch`块。`catch (e) { ... }`包裹的代码就是错误处理代码,变量`e`表示捕获到的错误。最后,无论有没有错误,`finally`一定会被执行。 所以,有错误发生时,执行流程像这样: 1. 先执行`try { ... }`的代码; 2. 执行到出错的语句时,后续语句不再继续执行,转而执行`catch (e) { ... }`代码; 3. 最后执行`finally { ... }`代码。 而没有错误发生时,执行流程像这样: 1. 先执行`try { ... }`的代码; 2. 因为没有出错,`catch (e) { ... }`代码不会被执行; 3. 最后执行`finally { ... }`代码。 最后请注意,`catch`和`finally`可以不必都出现。也就是说,`try`语句一共有三种形式。 完整的try...catch..finally ```js try { ... } catch(e){ ... } finally{ ... } ``` 只有try...catch,没有finally ```js try { ... } catch(e){ ... } ``` 只有try...finally,没有catch ```bash try { ... } finally { ... } ``` # 错误类型 JavaScript有一个标准的`Error`对象表示错误,还有从`Error`派生的`TypeError`、`ReferenceError`等错误对象。我们在处理错误时,可以通过`catch(e)`捕获的变量`e`访问错误对象: ``` try { ... } catch (e) { if (e instanceof TypeError) { alert('Type error!'); } else if (e instanceof Error) { alert(e.message); } else { alert('Error: ' + e); } } ``` 使用变量`e`是一个习惯用法。 # 抛出错误 程序也可以主动抛出一个错误,让执行流程直接跳转到`catch`块。抛出错误使用`throw`语句。 例如,下面的代码让用户输入一个数字,程序接收到的实际上是一个字符串,然后用`parseInt()`转换为整数。当用户输入不合法的时候,我们就抛出错误。 最后,当我们用catch捕获错误时,一定要编写错误处理语句 # 错误传播 如果代码发生了错误,又没有被try ... catch捕获,那么,程序执行流程会跳转到哪呢? 如果在一个函数内部发生了错误,它自身没有捕获,错误就会被抛到外层调用函数,如果外层函数也没有捕获,该错误会一直沿着函数调用链向上抛出,直到被JavaScript引擎捕获,代码终止执行。所以,我们不必在每一个函数内部捕获错误,只需要在合适的地方来个统一捕获,一网打尽: ```js "use strict"; function main(s){ console.log("BEGIN main()"); try{ foo(s); }catch (e){ console.log("出错了:"+e); } console.log("END main()"); } function foo(s){ console.log("BEGIN foo()"); bar (s); console.log("END foo()"); } function bar(s){ console.log("BEGIN bar()"); console.log("length = " + s.length); console.log("END bar()"); } main(null); ``` 输出 ```bash BEGIN main() BEGIN foo() BEGIN bar() 出错了:TypeError: Cannot read property 'length' of null END main() ``` 当`bar()`函数传入参数`null`时,代码会报错,错误会向上抛给调用方`foo()`函数,`foo()`函数没有try ... catch语句,所以错误继续向上抛给调用方`main()`函数,`main()`函数有try ... catch语句,所以错误最终在`main()`函数被处理了。