十三、错误处理

错误是开发人员需要修复或处理的代码中的错误。例如,由于缺少括号,下面的代码行将触发语法错误。

console.log("Hi";

遇到错误时,浏览器会暂停脚本的执行。大多数浏览器在出错时不会通知用户。相反,可以在浏览器的开发人员控制台中找到有关错误的信息。这些信息包括文件名、行号和错误描述,如下所示。

SyntaxError: missing ) after argument list

虽然语法错误很容易发现和解决,但其他错误可能更难发现,因为它们可能只在特定情况下出现。此外,由于开发人员无法控制的原因,可能会出现一些错误。例如,如果某个函数由外部文件定义,并且该文件无法加载,则该函数可能不可用。这会触发参考误差。

// Uncaught ReferenceError: missingFunc is not defined

missingFunc();

防止脚本执行暂停的一种方法是在调用函数之前检查它是否存在,这可以通过以下方式实现。

if (typeof missingFunc === "function") {

missingFunc(); // safe to use function

}

假设这个错误发生在一个函数中,并且这个函数不能继续运行。然后,该函数需要通知它的调用者它失败了。这通常是通过从函数返回 null 或错误代码来完成的。

function foo() {

if (typeof missingFunc === "function") {

missingFunc(); // safe to use function

}

else { return null; }

}

这通常是函数处理错误或异常的最佳方式,因为调用方通常拥有决定如何响应异常所必需的上下文。然而,有时可能有多个堆叠的函数调用,使得这种方法更加麻烦。随着每个函数返回到它的调用者,异常的上下文逐渐丢失,最后一个返回 null 值的函数不知道哪里出错了。为了解决这个问题,JavaScript 提供了try - catch语句。

试着接住

try - catch语句由一个包含可能导致异常的代码的try块和一个用于处理异常的catch子句组成。如果try块成功执行,程序将在try - catch语句后继续运行,但如果出现异常,执行将被传递到catch块。

try {

missingFunc();

}

catch(e) {}

有了这个语句,异常处理代码只在知道如何处理错误时才是必需的。错误和异常处理程序之间的函数不需要关心异常。

捕捉块

catch子句定义了一个异常对象。此对象可用于获取有关异常的更多信息,例如来自消息属性的异常描述。

catch(e) {

// "missingFunc is not defined"

console.log(e.message);

}

请注意,JavaScript 没有提供选择性捕获异常的直接方法。所有潜在的异常都需要在同一个catch块中处理。还要记住,语法错误是无法捕捉的。

最后

作为try - catch语句的最后一个子句,可以添加一个finally块。该块用于清理try块中分配的资源,无论是否有异常,都将一直执行。

try {

missingFunc();

}

catch(e) { }

finally {

console.log("Always executed");

}

抛出异常

用户定义的异常可以用throw语句生成。当到达该语句时,函数停止执行,异常沿调用方堆栈向上传播,直到被try - catch语句捕获,或者被浏览器处理。

function bar()

{

if (typeof missingFunc === "function") {

missingFunc();

}

else { throw new Error("missingFunc(): Function missing"); }

}

关键字throw后面可以跟函数想要发出的信号。在这个例子中,Error构造函数用于创建一个异常值。这种标准类型通常用于创建用户定义的异常。它将错误描述作为字符串参数。该参数可通过 error 对象的 message 属性获得。

try {

bar();

}

catch(e) {

// "missingFunc(): Function missing"

console.error(e.message);

}

Error对象也包含一个name属性。对于用Error构造函数创建的对象,该属性的值为“错误”。

console.error(e.name); // "Error"

为了更容易识别异常,最好抛出自定义错误对象。当try子句中的代码可以抛出多种类型的异常时,这尤其有用。在下面的代码示例中,引发了一个带有自定义名称和消息属性的对象文本。可以在catch子句中检查name属性,以确定应该如何处理异常。

throw {

name: 'CustomError',

message: 'Error description'

}