异常

当函数无法正常工作时,我们只希望停止当前任务,并立即跳转到负责处理问题的位置。这就是异常处理的功能。

异常是一种当代码执行中遇到问题时,可以触发(或抛出)异常的机制,异常只是一个普通的值。触发异常类似于从函数中强制返回:异常不只跳出到当前函数中,还会跳出函数调用方,直到当前执行流初次调用函数的位置。这种方式被称为“堆栈展开(Unwinding the Stack)”。你可能还记得我们在第3章中介绍的函数调用栈,异常会减小堆栈的尺寸,并丢弃所有在缩减程序栈尺寸过程中遇到的函数调用上下文。

如果异常总是会将堆栈尺寸缩减到栈底,那么异常也就毫无用处了。它只不过是换了一种方式来彻底破坏你的程序罢了。异常真正强大的地方在于你可以在堆栈上设置一个“障碍物”,当异常缩减堆栈到达这个位置时会被捕获。一旦发现异常,你可以使用它来解决问题,然后继续运行该程序。

  1. function promptDirection(question) {
  2. let result = prompt(question, "");
  3. if (result.toLowerCase() == "left") return "L";
  4. if (result.toLowerCase() == "right") return "R";
  5. throw new Error("Invalid direction: " + result);
  6. }
  7. function look() {
  8. if (promptDirection("Which way?") == "L") {
  9. return "a house";
  10. } else {
  11. return "two angry bears";
  12. }
  13. }
  14. try {
  15. console.log("You see", look());
  16. } catch (error) {
  17. console.log("Something went wrong: " + error);
  18. }

throw关键字用于引发异常。 异常的捕获通过将一段代码包装在一个try块中,后跟关键字catch来完成。 当try块中的代码引发异常时,将求值catch块,并将括号中的名称绑定到异常值。 在catch块结束之后,或者try块结束并且没有问题时,程序在整个try / catch语句的下面继续执行。

在本例中,我们使用Error构造器来创建异常值。这是一个标准的 JavaScript 构造器,用于创建一个对象,包含message属性。在多数 JavaScript 环境中,构造器实例也会收集异常创建时的调用栈信息,即堆栈跟踪信息(Stack Trace)。该信息存储在stack属性中,对于调用问题有很大的帮助,我们可以从堆栈跟踪信息中得知问题发生的精确位置,即问题具体出现在哪个函数中,以及执行失败为止调用的其他函数链。

需要注意的是现在look函数可以完全忽略promptDirection出错的可能性。这就是使用异常的优势:只有在错误触发且必须处理的位置才需要错误处理代码。其间的函数可以忽略异常处理。

嗯,我们要讲解的理论知识差不多就这些了。