## 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());
```
 **練習:異常處理**
`exercises/exception-handling/call_function_test.js`
 **測驗**
參見[測驗應用程序](ch_quizzes-exercises.html#quizzes)。
- I.背景
- 1.關于本書(ES2019 版)
- 2.常見問題:本書
- 3. JavaScript 的歷史和演變
- 4.常見問題:JavaScript
- II.第一步
- 5.概覽
- 6.語法
- 7.在控制臺上打印信息(console.*)
- 8.斷言 API
- 9.測驗和練習入門
- III.變量和值
- 10.變量和賦值
- 11.值
- 12.運算符
- IV.原始值
- 13.非值undefined和null
- 14.布爾值
- 15.數字
- 16. Math
- 17. Unicode - 簡要介紹(高級)
- 18.字符串
- 19.使用模板字面值和標記模板
- 20.符號
- V.控制流和數據流
- 21.控制流語句
- 22.異常處理
- 23.可調用值
- VI.模塊化
- 24.模塊
- 25.單個對象
- 26.原型鏈和類
- 七.集合
- 27.同步迭代
- 28.數組(Array)
- 29.類型化數組:處理二進制數據(高級)
- 30.映射(Map)
- 31. WeakMaps(WeakMap)
- 32.集(Set)
- 33. WeakSets(WeakSet)
- 34.解構
- 35.同步生成器(高級)
- 八.異步
- 36. JavaScript 中的異步編程
- 37.異步編程的 Promise
- 38.異步函數
- IX.更多標準庫
- 39.正則表達式(RegExp)
- 40.日期(Date)
- 41.創建和解析 JSON(JSON)
- 42.其余章節在哪里?