由浅入深理解 try/catch/finally

·  阅读 498

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第14天,点击查看活动详情


本文首发于:我的知乎

学过 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) 里面的参数是必须的; catchfinally 都是可选的。 也就是以下三种形式

  • 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 对象

Errornamemessage 两个属性

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 ,否则会覆盖前面返回的函数值甚至是抛出的错误

现在再去看看开头那道题吧~

参考链接

分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改