---
# System prepended metadata

title: 2021/07 JavaScript 例外處理
tags: [讀書會]

---

# 2021/07 JavaScript 例外處理
###### tags: `讀書會` 'JavaScript`

* ## **例外處理 (error handling)** 
是 JavaScript 的一種程式流程控制，你可以在程式執行可能拋出 **"錯誤"**
的地方使用，主動捕捉並處理錯誤，避免整個程式因為發生錯誤而停止執行。

## **例外處理陳述式**
    * try：放入要測試的程式碼
    * catch：處理例外的程式碼，如果有錯誤，則錯誤訊息會被傳到這個區塊
            ，並且執行這個區塊的行為
    * finally： 結束執行的程式碼，不論有無錯誤最後這個區塊都會被執行
    * throw：拋出錯誤訊息
## 使用throw的時機 
Error.prototype 物件包含如下屬性：
constructor–指向例項的建構函式
message–錯誤資訊
name–錯誤的名字(型別)
```javascript=
console.log(Error.prototype)
```

```javascript=
class Account {
  constructor(name, number , balance){
    this.name = name;
    this.number = number;
    this.balance = balance;
  }

  withdraw(money){
    if (money> this.balance){
      // console.log('Insufficient Balance');
      throw new Error("Insufficient Balance (throw)");
    }    //客製化一個自己的錯誤物件 - new Error()：
    this.balance -= money;
  }

  deposit(money){
    if (money<0){
      // console.log("Insufficient deposit");
      throw new Error("Insufficient deposit (throw)");
    }   //客製化一個自己的錯誤物件 - new Error()：
    else{ this.balance +=money;
    }
  }
  toString() {
    return `(${this.name}, ${this.number}, ${this.balance})`;
  }
}

let kevinacc =  new Account('kevin',001,10000);
console.log(kevinacc.toString());
// kevinacc.withdraw(1000000);
kevinacc.deposit(-1000);

```
## 使用try-catch-finally例子
* 當try catch 區塊結束
* 跳出視窗 "Error : Insufficient Balance (throw)"
* Catch內有兩個錯誤物件(Error Object) 
        * name = 錯誤類型 "Error"
        * message= 文字說明 "Insufficient Balance (throw)" 
```javascript=
// 使用例子class Account()

let kevinacc =  new Account('kevin',001,10000);

try {
  kevinacc.withdraw(1000000)
}
catch(e){
  console.log(e.name + " : " +e.message);
}
finally{
  console.log(`Account information:${kevinacc.toString()}`);
}

```


##  try-catch 並不支援多的Catch區塊
```javascript=
try {
  doFoo();
}
catch (err) {
  if (err instanceof TypeError) {
    console.log('TypeError');
  }
  else if (err instanceof ReferenceError) {
    console.log('ReferenceError');

  }
} 
```
*** 
## 下面是一些常見錯誤的種類。

| 錯誤類型       | 說明                                                      |
| -------------- |:--------------------------------------------------------- 
| RangeError     | 一個數值超過允許範圍                                      |
| ReferenceError | 存取未宣告的變數                                          |
| SyntaxError    | 程式語法錯誤                                              |
| TypeError      | 型別錯誤                                                  |


* ## 可透過程式編譯器避免 
  *尚未宣告變數，或是輸入錯誤產生，此類錯誤通常會被程式編輯器提醒。*
### ReferenceError 

```javascript=
const PI = 3.1415926
console.log(pi) 
// ReferenceError: pi is not defined
```


### SyntaxError
    
```javascript=
function course(name){
this.name
console.log('I am taking '+ name + " class right now.";) //;的位置
}
course("PE")
//Uncaught SyntaxError: missing ) after argument list
```
```javascript=
// SyntaxError
try{
    Let x=1000;   //L應該小寫 let
}
catch(err){
    console.log(`${err.name}": ${err.message}`);
}
```



* ## 使用例外處理方法try-catch
### RangeError 
```javascript=
var MIN = 300;
var MAX = 600;
var check = function(num) {
    if (num < MIN || num > MAX) {
      throw new RangeError('Parameter must be between ' + MIN + ' and ' + MAX);
    } 
  };

  try {
    check(5000);
  }
  catch (e) {
    if (e instanceof RangeError) 
           console.log(`${e.name}:${e.message}`);
  } 
  
```

### TypeError 

```javascript=
let num = 1202;
try {
  num.toUpperCase();
}
catch (err) {
  console.log(err.message)
  console.log(err.stack)
  console.log(err.name)
}


// num.toUpperCase is not a function

// TypeError: num.toUpperCase is not a function

// TypeError 

```
![](https://i.imgur.com/zm4Jaze.png)

## 自訂錯誤型態
對於特定的要求與錯誤繼承
```javascript=
class illegalArgumentError extends Error { //1. 繼承Error
  constructor(message) {
    super(message);  // 2.呼叫Error建構式
  }

  get name() {
    return illegalArgumentError.name; //3.錯誤型態名稱
  }
}

class InsufficientException extends Error {
  constructor(message, balance) {
    super(message);
    this.balance = balance;
  }
  get name() {
    return InsufficientException.name;
  }
}


class Account {
  constructor(name, number, balance) {
    this.name = name;
    this.number = number;
    this.balance = balance;
  }

  withdraw(money) {
    if (money < 0) {  //引數不正確
      throw new illegalArgumentError('提款金額不得為負');
    }
    if (money > this.balance) { //餘額不正確
      throw new InsufficientException('餘額不足',this.balance);
    }
    this.balance -= money;
  }

  deposit(money) {
    if (money < 0) {    //引述不正確
      throw new illegalArgumentError('存款金額不得為負');
    }
    this.balance += money;
  }

  toString() {
    return `(${this.name}, ${this.number}, ${this.balance})`;
  }
}

let acct = new Account('kevin', '123-788', 1000);


try {
  acct.withdraw(5000);
}
catch (err) {
  if (err instanceof InsufficientException) { //餘額不足的處理
    console.log(`${err.name}:${err.message}`);
    console.log('目前的餘額balance: ', err.balance);
  }
  else {
    throw err; //再度出現錯誤
  }
}




```

## 非同步任務處理錯誤 - Promise


## 追蹤堆疊



首先(函式的)呼叫棧的原理 為後進先出 LIFO (last in, first out) 
```javascript=
function c() {
    console.log('c');
    console.trace();
}
function b() {
    console.log('b');
    c();
}
function a() {
    console.log('a');
    b();
}
a();
```
![](https://i.imgur.com/yPlJ7xw.png)
```javascript=
function c() {
    console.log('c');
    }
    function b() {
    console.log('b');
    c();
    console.trace();
    }
    function a() {
    console.log('a');
    b();
    }
    
    a();
```
![](https://i.imgur.com/rIk1BpL.png)


```javascript=
// 選擇性敘述的練習-season
// 輸入月份1~12月，利用switch判斷相對應的季節春、夏、秋、冬並印出。若不在此範圍則印出”輸入錯誤”。
        function season(month) {
            this.month = month;
            switch (this.month) {
                case 1: case 2: case 12: document.write("冬天"); break;
                case 3: case 4: case 5: document.write("春天"); break;
                case 6: case 7: case 8: document.write("夏天"); break;
                case 9: case 10: case 11: document.write("冬天"); break;
                default: document.write("輸入錯誤月份");
                    throw new Error("輸入錯誤月份");
            }
        }
        season(5);
        document.write("<br>");
        season(12);
        document.write("<br>");
        // 測試函數也可以指定給一個變數

        try {
            var seasontest = season;
            seasontest(13);
        }
        catch (err) {
            console.log(err.message)
            console.log(err.stack)
            console.log(err.name)
        }

```













## 參考網站
[JavaScript錯誤處理和堆疊追蹤詳解 | 程式前沿](https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/240477/)

[錯誤處理](https://www.slideshare.net/JustinSDK/7-194523942)

[Fooish 程式技術](https://www.fooish.com/javascript/error-handling-try-catch-finally.html#:~:text=JavaScript%20try%20catch%20finally%20Error%20Handling%20%28%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86%29%20%E4%BE%8B%E5%A4%96%E8%99%95%E7%90%86,try%20%E5%8D%80%E5%A1%8A%E4%B8%AD%EF%BC%9B%E7%84%B6%E5%BE%8C%E5%87%BA%E9%8C%AF%E6%99%82%E7%9A%84%E8%99%95%E7%90%86%E7%A8%8B%E5%BC%8F%E7%A2%BC%E6%94%BE%E5%9C%A8%20catch%20%E5%8D%80%E5%A1%8A%E4%B8%AD%EF%BC%9B%E8%80%8C%E6%94%BE%E5%9C%A8%20finally%20%E5%8D%80%E5%A1%8A%E4%B8%AD%E7%9A%84%E7%A8%8B%E5%BC%8F%E7%A2%BC%E7%84%A1%E8%AB%96%E5%A6%82%E4%BD%95%E9%83%BD%E6%9C%83%E5%9C%A8%E6%9C%80%E5%BE%8C%E8%A2%AB%E5%9F%B7%E8%A1%8C%E3%80%82.%20try-catch-finally%20%E7%94%A8%E6%B3%95%E4%BE%8B%E5%AD%90%EF%BC%9A.)
  
[MDN 流程控制與例外處理](https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Guide/Control_flow_and_error_handling)

[璇之又璇的網路世界](https://shawnlin0201.github.io/JavaScript/JavaScript-Exception-Handling/)

[卡斯博's blog](https://wcc723.github.io/development/2020/09/16/chrome-js-alert/)

[非同步](https://ithelp.ithome.com.tw/articles/10221800)

[IT邦幫忙 - [Day04] JavaScript - 程式控制結構](https://ithelp.ithome.com.tw/articles/10217417)

https://codertw.com/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/240477/