# 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()`函数被处理了。