try catch finally

try catch finally

用法

1
2
3
4
5
6
7
8
9
10
11
12
13
try {
try_statements
}
[catch (exception_var_1 if condition_1) { // non-standard
catch_statements_1
}]
...
[catch (exception_var_2) {
catch_statements_2
}]
[finally {
finally_statements
}]

try_statements => 需要被执行的语句。

catch_statements_1, catch_statements_2 => 如果在 try 块里有异常被抛出时执行的语句。

exception_var_1, exception_var_2 => 用于保存关联 catch 子句的异常对象的标识符。

condition_1 => 一个条件表达式。

finally_statements => 在 try 语句块之后执行的语句块。无论是否有异常抛出或捕获这些语句都将执行。

说明

try语句包含了由一个或者多个语句组成的try块, 和至少一个catch块或者一个finally块的其中一个,或者两个兼有, 下面是三种形式的try声明:

  • try...catch
  • try...finally
  • try...catch...finally

catch子句包含try块中抛出异常时要执行的语句。也就是,你想让try语句中的内容成功, 如果没成功,你想控制接下来发生的事情,这时你可以在catch语句中实现。 如果在try块中有任何一个语句(或者从try块中调用的函数)抛出异常,控制立即转向catch子句。如果在try块中没有异常抛出,会跳过catch子句。

finally子句在try块和catch块之后执行但是在下一个try声明之前执行。无论是否有异常抛出或捕获它总是执行。

可以嵌套一个或者更多的try语句。如果内部的try语句没有catch子句,那么将会进入包裹它的try语句的catch子句。

无条件 catch

无条件catch块就是单个子句的try..catch抛出的异常都会被catch捕获,例如,当在下面的代码中发生异常时,控制转移到catch子句。

1
2
3
4
5
6
7
try {
nonExistentFunction() // 不存在的函数
} catch (error) {
console.error(error)
// 控制台打印: ReferenceError: nonExistentFunction is not defined
// 被catch捕获错误。
}

打印出来的错误时可以自定义的。catch块指定一个标识符,该标识符保存由throw语句指定的值。catch块是唯一的,因为当输入catch块时,JavaScript 会创建此标识符,并将其添加到当前作用域;标识符仅在catch块执行时存在;catch块执行完成后,标识符不再可用。

1
2
3
4
5
6
7
8
9
10
11
12
try {
throw "自定义一些文字错误"; // generates an exception
}
catch (e) {
console.log(e); // 控制台打印:自定义一些文字错误
}
try {
throw {name: '张三'}; // 自定义
}
catch (e) {
console.log(e); // 打印: {name: '张三'}
}

try块中的抛出一个异常时,exception_var(如catch (e)中的e)用来保存被抛出声明指定的值。你可以用这个标识符来获取关于被抛出异常的信息。

这个标识符是catch子语句内部的。换言之,当进入catch子语句时标识符创建,catch子语句执行完毕后,这个标识符将不再可用。

finally

finally块包含的语句在try块和catch之后,try..catch..finally块后的语句之前执行。请注意,无论是否抛出异常finally子句都会执行。此外,如果抛出异常,即使没有catch子句处理异常,finally子句中的语句也会执行。

1
2
3
4
5
6
7
8
openMyFile()
try {
// tie up a resource
writeMyFile(theData);
}
finally {
closeMyFile(); // always close the resource
}

嵌套try

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try {
try {
throw new Error("oops"); // 抛出oops错误对象
}
finally {
console.log("finally"); // 必须执行的
}
}
catch (ex) {
console.error("outer", ex.message);
}

// 结果:
// "finally"
// "outer" "oops"

例2:如果已经在 try 语句中,通过增加一个 catch 语句块捕获了异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
try {
try {
throw new Error("oops"); // 抛出异常
}
catch (ex) {
console.error("inner", ex.message); // 被捕获到了
}
finally {
console.log("finally"); // 怎么样都会执行
}
}
catch (ex) {
console.error("outer", ex.message); // 属于这个try catch 没有异常抛出
}

// 结果:
// "inner" "oops"
// "finally"

例3:在新增的catch里不干正事继续抛错误

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try {
try {
throw new Error("oops"); // 异常
}
catch (ex) {
console.error("inner", ex.message); // 捕获到异常
throw ex; // 不干正事的抛出异常 但是还是会先执行finally内的内容
}
finally {
console.log("finally"); // try 和 catch 执行完就执行。不管别人
}
}
catch (ex) {
console.error("outer", ex.message); // 捕获到属于这个try -catch 的异常
}

// 结果:
// "inner" "oops"
// "finally"
// "outer" "oops"

例4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function setName () {
try {
try {
throw new Error("oops");
}
catch (ex) {
console.error("inner", ex.message);
throw ex;
}
finally {
console.log("finally");
return;
}
}
catch (ex) {
console.error("outer", ex.message);
}

// 注: 此 try catch 语句需要在 function 中运行才能作为函数的返回值, 否则直接运行会报语法错误
// 结果:
// "inner" "oops"
// "finally"
}

如果从finally块中返回一个值,那么这个值将会成为整个try-catch-finally的返回值,无论是否有return语句在trycatch中。这包括在catch块里抛出的异常。因为 finally 块里的 return 语句,"oops" 没有抛出到外层,从 catch 块返回的值同样适用。