由浅入深理解 try/catch/finally
本文首发于:我的知乎
学过 try/catch/finally 的人应该都知道,这是个比较简单的错误处理机制。但是对于初学者可能会有一些细节难以理解到位,此篇带你 由浅入深理解 try/catch/finally。
如果你觉得理解透了的话,那么不妨请先看看这道题。
const whoami = () => {
try {
try {
return ' ';
} catch(_) {
return ' ';
} finally {
return ' ';
}
throw ' ';
} catch (_) {
return ' ';
}
}
whoami();函数的返回值将是什么?
1. 为什么要用?
try/catch/finally
用于处理代码中可能出现的错误。之所以需要它是因为当执行 JavaScritp
发生错误时,会停止执行接下来的程序,出现的异常会导致程序崩溃。所以使用 try/catch/finally
来处理错误对以后项目的维护很重要。例如:
const PI = 3.14;
alertt('Hello!');
console.log(PI);
// ReferenceError: alertt is not defined
显然 alertt
拼错,于是后面的程序将不会执行。所以要用 try/catch/finally
处理异常
const PI = 3.14;
try {
alertt('Hello!');
} catch(err) {
console.log(err.message);
} finally {
console.log(PI);
}
/*
alertt is not defined
3.14
*/
2. 怎么用?
try
语句定义所执行的进行错误测试的代码。如果 try 里面没有抛出异常,catch 将被跳过。catch
语句定义当try
语句发生错误时,捕获该错误并对错误进行处理。只有当try
抛出了错误,才会执行。finally
语句无论前面是否有异常都会执行。|
当使用的时候,try
语句是必须的;catch(err) 里面的参数是必须的; catch
和 finally
都是可选的。 也就是以下三种形式
try...catch
try...finally
try...catch..finally
3. throw 与 Error对象
3.1 throw
我们可以通过 throw
语句产生错误并自定义抛出的异常
throw 'error!';
throw false;
例如,以下语句限制了 input
的形式
var input = 1314;
try {
if(input == '') throw "请您输入!";
if(isNaN(input)) throw "请输入数字!";
if(input <= 0) throw "请输入大于0的数!"
} catch(err) {
alert(err);
}
3.2 throw 与 try/catch/finally
我们把外层的 try
块叫做"outer"块,把内层的称为"inner"块。如下
// "outer块"
try {
// "inner块"
try {
throw "error";
} catch(err) {
console.log('inner:' + err);
throw "error";
}
} catch(err) {
console.log("outer:" + err);
}
/* 输出
inner:error
finally
outer:error
*/
最后的输出结果说明,抛出的异常只会被离它最近的 catch
捕获。而且, "inner" 层抛出的异常,"outer" 外层同样可以捕获到。
3.3 Error 对象
Error
有 name
和 message
两个属性
try {
adddlert("Welcome");
}
catch(err) {
console.log(err.name);
console.log(err.message);
}
/* 输出
ReferenceError
adddlert is not defined
*/
3.4 throw 与 Error 对象
throw new Error("error!")
4. return 与 try/catch/finally
我们都知道,在一个函数中,一旦 return
出现后,后面的语句就不会再执行了。那如果在 try/catch/finally
里出现 return
会怎么样呢? 无论是否出现异常,又或者前面的 try/catch 里面有 return,finally 里面的语句始终会执行
try {
return "hello";
} finally {
console.log("finally");
}
/*输出
finally
*/
若 try/catch/finally 里面提前出现了 return ,则该代码块里后面的部分都不会执行
const f = () => {
try {
return "hello";
console.log("try");
} finally {
return "hello";
console.log("finally");
}
}
f();
//无输出
若把 return 写入到了函数的 finally 里面,则最终函数(整个try/catch/finally)的返回值(或者抛出的异常)将是 finally 里面返回的值,即使前面 try/catch 出现了 retrun
const func = () => {
try {
try {
throw new Error("ERROR!");
} catch(err) {
console.log(err.message);
throw new Error("error from inner")
} finally {
return "finally";
}
} catch(err) {
console.log(err.message); // 未捕获到异常,此处不输出
}
};
func();
/* output
ERROR!
*/
若把上面的 return "finally"
注释掉,则将会输出 error from inner
。这告诫我们 不要轻易在 finally 里面写 return ,否则会覆盖前面返回的函数值甚至是抛出的错误
现在再去看看开头那道题吧~
参考链接
转载自:https://juejin.cn/post/7086738106283458574