try...catch 語法

try...catch 語法標記出一整塊需要測試的語句,並指定一個以上的回應方法,萬一有例外拋出時,try...catch 語句就會捕捉。

try...catch 語法由 try 區塊所組成,其中內含一個以上的語句,和零個以上的 catch 區塊,其中內含語句用���指明當例外在 try 區塊裡拋出時要做些什麼。也就是當你希望 try 區塊成功,但如果他不成功時,你會想要把控制權移交給 catch 區塊。如果任何在 try 區塊內部裡的語句(或者在 try 區塊內部呼叫的函數裡)拋出例外,控制權將立即轉移給 catch 區塊。如果沒有例外從 try 區塊裡拋出,就會跳過 catch 區塊。finally 區塊會在 trycatch 區塊執行之後才執行,但會在 try...catch 語法後面的語句之前執行。

以下範例使用 try...catch 語法。本範例呼叫函數,這個函數是用來在陣列裡根據傳給函數的值來查詢月份的名稱。如果傳入的值不符合月份的數字 (1-12),就會拋出值為 InvalidMonthNo 的例外,而且在 catch 區塊裡的語句會把 monthName 變數設定為 unknown

js
function getMonthName(mo) {
  mo = mo - 1; // 針對陣列索引調整月份的數字 (1=Jan, 12=Dec)
  var months = new Array(
    "Jan",
    "Feb",
    "Mar",
    "Apr",
    "May",
    "Jun",
    "Jul",
    "Aug",
    "Sep",
    "Oct",
    "Nov",
    "Dec",
  );
  if (months[mo] != null) {
    return months[mo];
  } else {
    throw "InvalidMonthNo";
  }
}

try {
  // 需要測試的語句
  monthName = getMonthName(myMonth); // 可拋出例外的函數
} catch (e) {
  monthName = "unknown";
  logMyErrors(e); // 把例外物件傳給錯誤處理器
}

catch 區塊

你可以使用單一的 catch 區塊來處理所有在 try 區塊裡可能會產生的例外,或者你也可以使用分離的 catch 區塊,每一個皆各自處理特定的例外類型。

單一 catch 區塊 使用單一 try...catch 語法的 catch 區塊針對在 try 區塊裡拋出的所有例外來執行錯誤處理的代碼。

單一的 catch 區塊語句如下︰

js
catch (catchID) {
  statements
}

catch 區塊所指定的識別子(前面語句裡的 catchID)持有由 throw 語法所指定的值。你可以使用這個識別子來取得有關於被拋出的例外的資訊。當進入 catch 區塊時,JavaScript 就會建立這個識別子。識別子只能在 catch 區塊的期間內持續作用。catch 區塊執行結束以後,識別子就不再能使用。

舉例來說,以下代碼會拋出例外。當例外出現的時候,控制權就轉移給 catch 區塊。

js
try {
  throw "myException"; // 產生例外
} catch (e) {
  // 用來處理任何例外的語句
  logMyErrors(e); // 把例外物件傳給錯誤處理器
}

多重 catch 區塊 單一的 try 語句可以對應複數個有前提條件的 catch 區塊,每一個皆可處理特定的例外的類型。於是,當指定的的例外被拋出時,就只會進入適當條件的 catch 區塊。你也可以針對所有未指定的例外,使用選用性的對應所有例外的 catch 區塊來作為語法裡最後一個的 catch 區塊。

舉例來說,以下函數呼叫三個其他的函數(已在別處定義了)來檢驗自己的參數。如果檢驗函數判斷出他所要檢驗的元素是無效的話,他就返回 0,導致呼叫者拋出對應的例外。

js
function getCustInfo(name, id, email) {
  var n, i, e;

  if (!validate_name(name)) throw "InvalidNameException";
  else n = name;
  if (!validate_id(id)) throw "InvalidIdException";
  else i = id;
  if (!validate_email(email)) throw "InvalidEmailException";
  else e = email;
  cust = n + " " + i + " " + e;
  return cust;
}

有各種條件的 catch 區塊會把控制權安排給適當的例外處理器。

js
try {
// 可以拋出三個例外的函數
   getCustInfo("Lee", 1234, "lee@netscape.com")
}

catch (e if e == "InvalidNameException") {
// 針對無效的名稱呼叫處理器
   bad_name_handler(e)
}

catch (e if e == "InvalidIdException") {
// 針對無效的 ID 呼叫處理器
   bad_id_handler(e)
}

catch (e if e == "InvalidEmailException") {
// 針對無效的電子郵件位址呼叫處理器
   bad_email_handler(e)
}

catch (e){
// 不知道該做什麼,就記在日誌裡
   logError(e)
}

finally 區塊

finally 區塊內含的語句,會在 try 和 catch 區塊執行以後、並在 try...catch 語法後面的語句之前來執行。無論有沒有被拋出的例外,finally 區塊都會執行。如果有被拋出的例外,即使沒有 catch 區塊來處理這些例外,還是會執行 finally 區塊裡的語句。

當出現例外時,你可以使用 finally 區塊來使你的 Script 優美的停止。舉例來說,你可能需要釋放 Script 所佔用的資源。以下範例開��了檔案,並執行使用這個檔案(伺服端的 JavaScript 可讓你存取檔案)的語句。如果在開啟檔案時有例外被拋出,finally 區塊會在 Script 停止之前把檔案關閉。

js
openMyFile();
try {
  writeMyFile(theData); // 這裡有可能拋出錯誤
} catch (e) {
  handleError(e); // 如果我們得到錯誤,就處理他
} finally {
  closeMyFile(); // 永遠會關閉這項資源
}

try...catch 語法的嵌套

你可以嵌套一個以上的 try...catch 語法。如果有一個內部的 try...catch 語法沒有 catch 區塊,圍住這些 try...catch 語法的 catch 區塊就會被用來比對。

Error 物件的用處

根據錯誤的類型,你有可能使用 「name」 和 「message」 屬性來取得更多明確的訊息。「name」 提供錯誤的一般類別(例如,「DOMException」 或 「Error」),「message」 通常提供更為簡練的訊息,如此就能把錯誤物件轉換為字串來取得訊息。

如果你要拋出你自己的例外,以從這些屬性取得好處(例如,如果你的 catch 區塊不區分你自己的例外和系統的例外的話),你可以使用錯誤建構子。例如︰

js
function doSomethingErrorProne () {
   if (ourCodeMakesAMistake()) {
      throw (new Error('The message'));
   }
   else {
      doSomethingToGetAJavascriptError();
   }
}
....
try {
   doSomethingErrorProne();
}
catch (e) {
   alert(e.name);// 警報 'Error'
   alert(e.message); // 警報 'The message' 或 JavaScript 錯誤訊息
}