# 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
```

## 自訂錯誤型態
對於特定的要求與錯誤繼承
```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();
```

```javascript=
function c() {
console.log('c');
}
function b() {
console.log('b');
c();
console.trace();
}
function a() {
console.log('a');
b();
}
a();
```

```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/