🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 22.异常处理 > 原文: [http://exploringjs.com/impatient-js/ch_exception-handling.html](http://exploringjs.com/impatient-js/ch_exception-handling.html) 本章介绍 JavaScript 如何处理异常。 暂且不说:JavaScript 直到 ES3 才支持异常。这就解释了为什么它们被语言及其标准库谨慎使用。 ### 22.1。动机:抛出和捕捉异常 请考虑以下代码。它将存储在文件中的配置文件读入具有类`Profile`实例的数组: ```js function readProfiles(filePaths) { const profiles = []; for (const filePath of filePaths) { try { const profile = readOneProfile(filePath); profiles.push(profile); } catch (err) { // (A) console.log('Error in: '+filePath, err); } } } function readOneProfile(filePath) { const profile = new Profile(); const file = openFile(filePath); // ··· (Read the data in `file` into `profile`) return profile; } function openFile(filePath) { if (!fs.existsSync(filePath)) { throw new Error('Could not find file '+filePath); // (B) } // ··· (Open the file whose path is `filePath`) } ``` 让我们来看看 B 行发生了什么:发生错误,但处理问题的最佳位置不是当前位置,而是 A 行。在那里,我们可以跳过当前文件并转到下一个文件。 因此: * 在 B 行中,我们使用`throw`语句来指示存在问题。 * 在 A 行中,我们使用`try-catch`语句来处理问题。 当我们抛出时,以下构造是活动的: ```js readProfiles(···) for (const filePath of filePaths) try readOneProfile(···) openFile(···) if (!fs.existsSync(filePath)) throw ``` `throw`走上这个构造链,直到找到`try`语句。在`try`语句的`catch`子句中继续执行。 ### 22.2。 `throw` ```js throw «value»; ``` 可以抛出任何值,但最好抛出`Error`的实例: ```js throw new Error('Problem!'); ``` #### 22.2.1。用于创建错误对象的选项 * 使用类`Error`。这在 JavaScript 中比在更静态的语言中更少限制,因为您可以将自己的属性添加到实例: ```js const err = new Error('Could not find the file'); err.filePath = filePath; throw err; ``` * 使用`Error`的 JavaScript 子类之一(后面列出 [](ch_exception-handling.html#error-classes) )。 * 子类`Error`自己。 ```js class MyError extends Error { } function func() { throw new MyError; } assert.throws( () => func(), MyError); ``` ### 22.3。 `try-catch-finally` `try`语句的最大版本如下所示: ```js try { // try_statements } catch (error) { // catch_statements } finally { // finally_statements } ``` `try`子句是必需的,但您可以省略`catch`或`finally`(但不能同时省略)。从 ECMAScript 2019 开始,如果您对抛出的值不感兴趣,也可以省略`(error)`。 #### 22.3.1。 `catch`条款 如果在`try`块中抛出异常(并且之前未捕获),则将其分配给`catch`子句的参数,并执行该子句中的代码。除非它被指向其他地方(通过`return`或类似),否则在`catch`子句之后继续执行:使用`finally`子句 - 如果存在 - 或在`try`语句之后。 以下代码演示了行 A 中抛出的值确实在行 B 中捕获。 ```js const errorObject = new Error(); function func() { throw errorObject; // (A) } try { func(); } catch (err) { // (B) assert.equal(err, errorObject); } ``` #### 22.3.2。 `finally`条款 让我们看一下`finally`的一个常见用例:你已经创建了一个资源,并希望在你完成它时总是销毁它 - 无论在使用它时发生了什么。你可以按如下方式实现: ```js const resource = createResource(); try { // Work with `resource`: errors may be thrown. } finally { resource.destroy(); } ``` 始终执行`finally` - 即使抛出错误(行 A): ```js let finallyWasExecuted = false; assert.throws( () => { try { throw new Error(); // (A) } finally { finallyWasExecuted = true; } }, Error ); assert.equal(finallyWasExecuted, true); ``` 始终执行`finally` - 即使有`return`语句(行 A): ```js let finallyWasExecuted = false; function func() { try { return; // (A) } finally { finallyWasExecuted = true; } } func(); assert.equal(finallyWasExecuted, true); ``` ### 22.4。错误类及其属性 引用 [ECMAScript 规范](https://tc39.github.io/ecma262/#sec-native-error-types-used-in-this-standard): * `Error` [根类] * `RangeError`:表示不在允许值的设置或范围内的值。 * `ReferenceError`:表示检测到无效的参考值。 * `SyntaxError`:表示发生了解析错误。 * `TypeError`:用于表示当其他 _NativeError_ 对象都不是故障原因的适当指示时不成功的操作。 * `URIError`:表示其中一个全局 URI 处理函数的使用方式与其定义不兼容。 #### 22.4.1。错误类的属性 考虑`err`,`Error`的一个实例: ```js const err = new Error('Hello!'); assert.equal(String(err), 'Error: Hello!'); ``` `err`的两个属性特别有用: * `.message`:仅包含错误消息。 ```js assert.equal(err.message, 'Hello!'); ``` * `.stack`:包含堆栈跟踪。它受到所有主流浏览器的支持。 ```js assert.equal( err.stack, ` Error: Hello! at Context.<anonymous> (ch_exception-handling.js:1:13) `.trim()); ``` ![](https://img.kancloud.cn/3e/d5/3ed5755d562179ae6c199264f5e21157.svg) **练习:异常处理** `exercises/exception-handling/call_function_test.js` ![](https://img.kancloud.cn/ff/a8/ffa8e16628cad59b09c786b836722faa.svg) **测验** 参见[测验应用程序](ch_quizzes-exercises.html#quizzes)。