初級程式人員和專家之間,最顯著的差別之一就是錯誤管理,無論程式人員的技能水準如何,錯誤都會發生,因為使用者會製造很多問題,但是經驗豐富的開發人員在發生錯誤時能夠妥善處理。
有三種避免與處理錯誤的方法:
try...catch 程式碼區塊的語法如下:
try{ ... }
catch(error){ ... }
catch 區塊可以對錯誤作出有關的回應,而錯誤變數也是一個物件,實際上在 OOP 中,try...catch 區塊內的錯誤通常稱作異常(Exception),其為錯誤的物件呈現形式,除非另作說明,物件的具體型別為 Error,這個物件有下列兩個有用的屬性(其他瀏覽器可能提供其他的 Error 物件屬性):
finally 子句是 try...catch 結構的一種補充,它總是出現在最後:
finally{ ... }
catch 和 finally 區塊都不是必需的,但是必須至少有這兩者之一,如果在 try 區塊編寫程式而不捕捉例外,向使用者回報的異常就無法和 try...catch 敘述的標準錯誤一樣,倘若因為某種理由,不希望在發生異常時做任何事情,則可建立空白的 catch 區塊:
到目前為止的程式碼基於這種思路:問題發生時 JavaScript 會引發異常。也可以自己觸發異常,並由 catch 區塊捕捉,透過
try 區塊的程式碼往往在函數呼叫失敗時拋出異常──或許是因為該函數沒有接收到正確的參數,也可透過自己的函數拋出異常:
try...catch 有許多良好的常見用法,像是
使用 try 和 catch 敘述更新函數的步驟如下:
有三種避免與處理錯誤的方法:
- 異常處理:透過 JavaScript 內建語法「try...catch」
- 使用斷言(assertion):這是編寫程式碼時採用的簡單偵錯工具
- 單元測試
1捕捉和拋出錯誤
這裡大都採用基本的 if-else 結構監控錯誤,這種方法對簡單的程式碼已經綽綽有餘,但針對更複雜的情況,尤其是物件導向程式設計(OOP)中,還有更佳的系統──異常處理,此機制包含 try 和 catch 敘述以及 throw 和 finally。捕捉錯誤
try...catch 程式碼區塊的語法如下:
try{ ... }
catch(error){ ... }
try {
...
} catch(error) {
//使用錯誤
}
當 try 程式區塊(大括號之間的部份)發生錯誤時,程式流立即轉到 catch 區塊,catch 能夠處理任何程式碼中出現的錯誤;如果 try 區塊中沒有任何錯誤,則完全不執行 catch 區塊。catch 區塊可以對錯誤作出有關的回應,而錯誤變數也是一個物件,實際上在 OOP 中,try...catch 區塊內的錯誤通常稱作異常(Exception),其為錯誤的物件呈現形式,除非另作說明,物件的具體型別為 Error,這個物件有下列兩個有用的屬性(其他瀏覽器可能提供其他的 Error 物件屬性):
- .name:儲存錯誤型別
- .message:儲存錯誤訊息
console.log(error.name + ': ' + error.message + '\n');
可以想像 catch 區塊的異常變數為一個函數參數,僅存在於此類程式區塊之中。
依型別捕捉
catch 區塊處理 try 區塊中可能發生的所有異常,但是異常也可以按照具體的類型來捕捉,例如,當操作錯誤的物件型別時,標準的 JavaScript 程式碼可能拋出 TypeError 異常,而於數字超出允許值範圍時拋出 RangeError 異常,因為這些問題有顯著的不同,所以可對它們進行單獨的處理,為此建議採用多個 catch 程式區塊,並指出每個區塊要捕捉的異常類型,其內可搭配 instanceof 運算子和條件敘述,以便捕捉具體的異常類型。
try {
...
} catch (ex if ex instanceof TypeError){
//使用錯誤
} catch (ex if ex instanceof RangeError){
//使用錯誤
}
一旦知道如何建立自己的物件類型後,就能以程式碼攔截自訂的異常類型。
finally 子句
finally 子句是 try...catch 結構的一種補充,它總是出現在最後:
finally{ ... }
try {
...
} catch(ex) {
//使用錯誤
} finally {
//結束程式碼
}
不管是否發生錯誤,總會執行 finally 區塊中的程式碼,finally 區塊通常用來執行清理工作,無論之前發生過什麼,這些工作都必須進行,例如,finally 子句中的程式可以刪除錯誤處理器,或者為不再需要的 Ajax 物件填入 null 值。catch 和 finally 區塊都不是必需的,但是必須至少有這兩者之一,如果在 try 區塊編寫程式而不捕捉例外,向使用者回報的異常就無法和 try...catch 敘述的標準錯誤一樣,倘若因為某種理由,不希望在發生異常時做任何事情,則可建立空白的 catch 區塊:
try {
...
} catch(ex) {
}
參考 MSDN try...catch...finally 陳述式:https://msdn.microsoft.com/zh-tw/library/4yahc5d8(v=vs.94).aspx
參考 W3school JavaScript try/catch/finally Statement:http://www.w3schools.com/jsref/jsref_try_catch.asp
拋出異常
到目前為止的程式碼基於這種思路:問題發生時 JavaScript 會引發異常。也可以自己觸發異常,並由 catch 區塊捕捉,透過
throw 敘述便能做到這一點:- throw something:可以拋出數字、字串、Error 物件或是自訂的異常物件,但物件需要有
name和message屬性,因為大部分 catch 區塊都需要這兩項資訊
throw 2;
throw 'No such HTML element!';
throw new Error('No such HTML element!');
var error = {name: 'Division Error', message: 'Cannot divide by zero.'}
throw error;
儘管如此最好是拋出 Error 物件,如此便能編寫一致性的 catch 區塊,以便使用 name 和 message 屬性。Error 物件還有一個附加的好處,在某些瀏覽器中該物件還有更多有用的屬性。try 區塊的程式碼往往在函數呼叫失敗時拋出異常──或許是因為該函數沒有接收到正確的參數,也可透過自己的函數拋出異常:
function $(id){
'use strict';
if(typeof id != 'undefined'){
return document.getElementById(id);
}else{
throw Error('The function requires one argument.');
}
}
try{
var elem = $();
elem.innerHTML = 'blah'
}catch(ex){
console.log('Could not update element because: ' + ex.message + '\n');
document.getElementById('btn').innerHTML = 'ex.name: ' + ex.name + '
ex.message: ' + ex.message + '';
}
參考 MSDN throw 陳述式:https://msdn.microsoft.com/zh-tw/library/85fscz6h(v=vs.94).aspx
參考 W3school JavaScript Errors - Throw and Try to Catch:http://www.w3schools.com/js/js_errors.asp
整合
try...catch 有許多良好的常見用法,像是
getXMLHttpRequestObject() 函數,具體地說,這些程式試圖建立一個 ActiveXObject 物件,如果無法產生,則捕捉發生的所有異常。使用 try 和 catch 敘述更新函數的步驟如下:
- 在文字編輯器或 IDE 中開啟 ajax.js
-
利用下列內容代替建立新 ActiveXObject 物件的程式:
try { ajax = new ActiveXObject('MSXML2.XMLHTTP.3.0'); } catch(error) { console.log('Could not create the ActiveXObject: ' + error.message + '\n'); }現在試圖建立 ActiveXObject 的程式碼放在 try 區塊中,如果建立失敗,將捕捉和回報異常,可以擴充此法,使其嘗試產生不同類型的 ActiveXObject,從最新的版本(MSXML2.XMLHTTP.6.0)開始,並且回溯到支援的版本。 - 儲存 ajax.js 檔案