再學(xué)一遍 try...catch

定義
首先來(lái)看下 MDN 的定義:
The try...catch statement marks a block of statements to try and specifies a response should an exception be thrown.
try...catch語(yǔ)句標(biāo)記要執(zhí)行的語(yǔ)句,并指定一個(gè)當(dāng)有異常拋出時(shí)候的響應(yīng)
簡(jiǎn)短的一句的確描述了try...catch的大部分功能。
但是,最MDN的最后,有一段話是這么寫(xiě)的:
Returning from a finally-block
If the finally-block returns a value, this value becomes the return value of the entire try-catch-finally statement, regardless of any return statements in the try and catch-blocks. This includes exceptions thrown inside of the catch-block:
finally語(yǔ)句塊的返回值
如果
finally語(yǔ)句塊中有返回值,那么這個(gè)值將作為整個(gè)try...catch語(yǔ)句的返回,無(wú)論try語(yǔ)句塊或者catch語(yǔ)句塊中是否有返回,這包括了catch中的異常。
ok,那我們就嘗試加上return,看看會(huì)發(fā)生什么。
case1
function fn() {
try {
console.log('try塊內(nèi)log');
} catch (error) {
console.log('catch塊內(nèi)log');
} finally {
console.log('finally塊內(nèi)log====');
}
return '一般情況下的return';
}
console.log(fn());

一切看起來(lái)都如我們所想,沒(méi)有問(wèn)題,繼續(xù)往下看。
case2
function fn() {
try {
console.log('try塊內(nèi)log');
return 'try中的return'; // <=== 多了這么一句
} catch (error) {
console.log('catch塊內(nèi)log');
return 'catch中的return語(yǔ)句';
} finally {
console.log('finally塊內(nèi)log====');
}
return '一般情況下的return';
}
console.log(fn());

正如上圖所示,這里打印的是
try的return,但是,finally語(yǔ)句塊中的log依然被執(zhí)行了??吹竭@里,我們可以知道,finally的執(zhí)行時(shí)機(jī)是在try(或者cache,cache同理)執(zhí)行return之前被執(zhí)行。那我們就可以驗(yàn)證下MDN上所說(shuō)的:finally語(yǔ)句塊的返回值 這句話的真正含義。
case3
function fn() {
try {
console.log('try塊內(nèi)log');
return 'try中的return'
} catch (error) {
console.log('catch塊內(nèi)log');
return 'catch中的return語(yǔ)句';
} finally {
console.log('finally塊內(nèi)log====');
return 'finaly中的return'; // <=== 多了這么一句
}
return '一般情況下的return';
}
console.log(fn());

ok,依然很正常,因?yàn)?code style="">finally會(huì)在try的return之前執(zhí)行,所以攔截了try中的return,打印了finally中的return。
你以為這樣就結(jié)束了嗎?
我們繼續(xù)往下看。
case4
function justLog(){
console.log('來(lái)自justLog的打印');
return '來(lái)自justLog的return'
}
function fn() {
try {
console.log('try塊內(nèi)log');
return justLog(); // <=== 這次我們r(jià)eturn了一個(gè)函數(shù)
} catch (error) {
console.log('catch塊內(nèi)log');
return 'catch中的return語(yǔ)句';
} finally {
console.log('finally塊內(nèi)log====');
return 'finaly中的return';
}
return '一般情況下的return';
}
console.log(fn());
先思考一下會(huì)打印什么?看看是否和真實(shí)的輸出一致。給我們幾秒鐘...

可以看到,紅框內(nèi)為 justLog函數(shù)的log,紅框下面是finally中的打印和返回。所以 finally真正的執(zhí)行時(shí)機(jī)是:try(或catch)中return關(guān)鍵字之前。所以我們才看到了 justLog中的打印。有關(guān) return關(guān)鍵字的實(shí)現(xiàn),可以自行查詢(xún)標(biāo)準(zhǔn),這里不贅述。
應(yīng)用場(chǎng)景
比如我們有這樣一個(gè)高階函數(shù):
function hoc(fn) {
return fn()
}
我們想要返回所傳遞參數(shù)的執(zhí)行結(jié)果,這樣做是沒(méi)問(wèn)題的。
那如果我們想在函數(shù)執(zhí)行之后,
return之前,做一些其他操作,應(yīng)該怎么做呢?
function hoc(fn) {
const res = fn();
// 其他操作
return res;
}
很簡(jiǎn)答,我們可以先獲取返回值,再進(jìn)行其他操作,然后 return。不過(guò)這樣我們就占用了額外的空間,而且無(wú)法便利的復(fù)用 return后的語(yǔ)句,這個(gè)時(shí)候,我們的try...catch就可以排上用場(chǎng)了:
function hoc(fn) {
try {
return fn();
} finally {
// 一些其他操作,這些操作會(huì)在 `fn()執(zhí)行后,return執(zhí)行前` 被執(zhí)行
}
}
總結(jié)
大白話來(lái)講,
finally語(yǔ)句塊會(huì)在try(或catch)中的return關(guān)鍵字之前執(zhí)行。一圖以概之:

1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的「點(diǎn)贊,在看」是我創(chuàng)作的動(dòng)力。
2.關(guān)注公眾號(hào)
程序員成長(zhǎng)指北,回復(fù)「1」加入高級(jí)前端交流群!「在這里有好多 前端 開(kāi)發(fā)者,會(huì)討論 前端 Node 知識(shí),互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長(zhǎng)。
“在看轉(zhuǎn)發(fā)”是最大的支持
