[JS] try-catch-finally 的不常见用法
try
,catch
和 finally
,有一些不太常见的使用方式。
我们来总结下,在这些场景,程序会怎样表现。
1. 可省语句块
catch
或 finally
可省,但是不能都省略
// 省略 catch
try {
} finally {
}
// 省略 finally
try {
} catch (e) { // 只能写一个参数
}
// 省略形参
try {
} catch { // 不写形参
} finally {
}
注:
(1)try
,catch
和finally
中,如果没有 return
也没有 throw
,
则还会执行 try-catch-finally
语句块后面的代码。
(2)没有 catch
的情况下,如果 try
抛异常,则外层函数会直接抛异常。
(3)catch
的形参只能写一个,不能写多个,形参的名字可以不是 e
。
即,不能写 catch () {
,也不能写 catch (e, c) {
。
(4)catch
可省略形参,即,catch {
。
(5)finally
中的代码总会执行,不论 try
或 catch
是否 return
或 throw
。
2. 提前返回
try
,catch
或 finally
中的 return
会导致函数直接返回
// try直接返回
(() => {
try {
console.log(1);
return 2; // try -> finally -> 返回try中的return
} catch (e) {
console.log(3);
} finally {
console.log(4);
}
console.log(5);
return 6;
})(); // 1 4
// 返回:2
// catch直接返回
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
return 4; // try -> catch -> finally -> 返回catch中的return
} finally {
console.log(5);
}
console.log(6);
return 7;
})(); // 1 3 5
// 返回:4
// finally直接返回
(() => {
try {
console.log(1);
} catch (e) {
console.log(2);
} finally {
console.log(3);
return 4; // try -> finally -> 返回finally中的return
}
console.log(5);
return 6;
})(); // 1 3
// 返回:4
注:
(1)try
,catch
和finally
中都可以写 return
,
则 try-catch-finally
语句块后面的代码就不执行了,外层函数直接返回。
(2)即使 try
或 catch
中写了 return
,finally
也会执行完再 return
。
3. 提前抛异常
try
中抛异常,但是 catch
没捕获;catch
或 finally
里的 throw
,
会导致函数直接抛异常
// try抛异常,省略了catch
(() => {
try {
console.log(1);
throw 2; // 抛出try中的throw
} finally {
console.log(3);
}
console.log(4);
return 5;
})(); // 1 3
// 异常:Uncaught 2
// catch抛异常
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
throw 4; // try -> catch -> finally -> 抛出catch中的throw
} finally {
console.log(5);
}
console.log(6);
return 7;
})(); // 1 3 5
// 异常:Uncaught 4
// finally抛异常
(() => {
try {
console.log(1);
} catch (e) {
console.log(2);
} finally {
console.log(3);
throw 4; // try -> finally -> 抛出finally中的throw
}
console.log(5);
return 6;
})(); // 1 3
// 异常:Uncaught 4
注:
(1)try
,catch
和finally
中都可以写 throw
,
或者 try
中抛异常,但是 catch
没捕获,
则 try-catch-finally
语句块后面的代码就不执行了,外层函数直接抛异常。
(2)即使 try
或 catch
中写了 throw
,finally
也会执行完再 throw
。
4. 覆盖返回值或异常
finally
中的 return
或 throw
会覆盖 try
或 catch
中的 return
或 throw
// finally return 覆盖 try return
(() => {
try {
console.log(1);
return 2; // 丢弃
} catch (e) {
console.log(3);
} finally {
console.log(4);
return 5; // try -> finally -> 返回finally中的return
}
console.log(6);
return 7;
})(); // 1 4
// 返回:5
// finally return 覆盖 try throw(省略了catch时)
(() => {
try {
console.log(1);
throw 2; // 丢弃
} finally {
console.log(3);
return 4; // try -> finally -> 返回finally中的return
}
console.log(5);
return 6;
})(); // 1 3
// 返回:4
// finally throw 覆盖 try return
(() => {
try {
console.log(1);
return 2; // 丢弃
} catch (e) {
console.log(3);
} finally {
console.log(4);
throw 5; // try -> finally -> 抛出finally中的throw
}
console.log(6);
return 7;
})(); // 1 4
// 异常:Uncaught 5
// finally throw 覆盖 try throw(省略了catch时)
(() => {
try {
console.log(1);
throw 2; // 丢弃
} finally {
console.log(3);
throw 4; // try -> finally -> 抛出finally中的throw
}
console.log(5);
return 6;
})(); // 1 3
// 异常:Uncaught 4
// finally return 覆盖 catch return
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
return 4; // 丢弃
} finally {
console.log(5);
return 6; // try -> catch -> finally -> 返回finally中的return
}
console.log(7);
return 8;
})(); // 1 3 5
// 返回:6
// finally return 覆盖 catch throw
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
throw 4; // 丢弃
} finally {
console.log(5);
return 6; // try -> catch -> finally -> 返回finally中的return
}
console.log(7);
return 8;
})(); // 1 3 5
// 返回:6
// finally throw 覆盖 catch return
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
return 4; // 丢弃
} finally {
console.log(5);
throw 6; // try -> catch -> finally -> 抛出finally中的throw
}
console.log(7);
return 8;
})(); // 1 3 5
// 异常:Uncaught 6
// finally throw 覆盖 catch throw
(() => {
try {
console.log(1);
throw 2;
} catch (e) {
console.log(3);
throw 4; // 丢弃
} finally {
console.log(5);
throw 6; // try -> catch -> finally -> 抛出finally中的throw
}
console.log(7);
return 8;
})(); // 1 3 5
// 异常:Uncaught 6
注:
(1)try-catch-finally
语句块的返回值由 finally
决定,只要 finally
中有 return
(即使是 return undefined;
)或 throw
,则 try
或 catch
中的 return
或 throw
都会被覆盖。
(2)return
可以覆盖 throw
,throw
也可以覆盖 return
。
总结
finally
总是会执行,执行完了以后,再根据 finally
,确定返回值,以及是否抛异常。