【轉】JS中異常處理的理解
JS里的異常處理
JS的異常捕獲與處理可以從它的 try-catch 語法結構說起,具體形式如下:
try{ ... //異常的拋出 }catch(e){ ... //異常的捕獲與處理 }finally{ ... //結束處理 }
其中,try塊:
try塊包含的是可能產生異常的代碼,在這里面直接或者在里面通過調用函數里間接拋出的異常都可以捕獲到。部分瀏覽器還可以找到具體拋出的位置。詳見e.stack。
catch塊:
catch塊,是捕獲異常,並處理異常的地方,包括條件捕獲和非條件捕獲。
//條件捕獲與非條件捕獲 try { throw new Err(); }catch(e instanceof ErrBob) { console.log(e.name + ' Bob''); }catch(e instanceof ErrTom) { console.log(e.name + ' Tom''); }catch(e instanceof ErrLily) { console.log(e.name + ' Lily''); }catch(e) { console.log('that's all'); }
條件捕獲,如 catch(e instanceof obj) 的形式,用 instanceof 判斷異常的對象類型,實現指定的異常處理方式。
非條件捕獲,如 catch(e) 的形式,當異常拋出時,無論異常的類型都進行捕獲並處理。
這里有兩點注意,如果條件捕獲和非條件捕獲共用,那么非條件捕獲必須放在最后,因為它是無條件的捕獲類型,捕獲后會忽略后面的任意 catch 塊。
另外,對異常的處理必須考慮周全,在 catch 里要么處理所有的異常,要么再次拋出異常(假定外層還有異常處理),否則在調試過程中會非常困難,因為出現的異常被忽略了。
finally塊:
無論是否捕獲異常,都會在 try 或 catch塊后立即執行。
finally塊常常用以文件的關閉,標記的取消等操作,更多的時候作為一種 ”優雅的失敗“ 而存在,常常代替 catch 塊。
在JS的DOM對象中,還有一個 window.onerror 作為事件監聽來從全局處理JS運行時的錯誤。由於瀏覽器的差異,實際上許多錯誤事件不能觸發 window.onerror ,因此要小心使用,詳見《Why window.onerror Is Not Enough》。
那么如何拋出異常呢?
JS里用 throw 指定一個用戶定義的異常類型,並拋出。拋出點可以在 try 或 catch 塊中。
throw e; //拋出用於自定義的異常 throw 'error'; throw '21'; throw true; throw new myError();
這里的異常類型包括字符串、數字、布爾值和對象,如例子中所示。為了獲取有用的信息,以及有條件地捕獲異常,其中只有對象類型最為常用。
JS里內置的Error對象方便我們使用,‘throw new Error();’ ,同時提供了6種錯誤類型便於我們捕獲,包括EvalError、RangeError、ReferenceError、SyntaxError、 TypeError、URIError,詳見這里。
更為便利的是定制一個異常的對象,可以自定義,也可以繼承Error對象,主要包括 name 和 message 屬性即可,例如:
try{ throw { name : 'err1', message : 'here it is' }; }catch(e){ console.log(e.name + ' : ' + e.message); }
JS里異常處理的有兩個特點:
1、活動鏈域和性能
當對異常進行捕獲並進入到 catch 塊中,此時的異常對象 e 將成為一個新的活動對象,並提到活動鏈域的最前面。如下栗子:
try{ ... }catch(e){ var name = 'jberry'; alert(name + e.message); //e 在活動鏈域的最前面
//handleFn(e);
}
此時 catch 塊中的任何標識符(例子中的 ‘name’)都將在活動鏈域的第二個活動對象里訪問,這樣降低了訪問的性能。好的方法的是調用異常處理函數,減少在catch塊中對標識符的訪問(例子中 ‘handleFn(e);')。
2、錯誤和異常有什么區別?
在如Java一些語言中,錯誤和異常有所區別,它們分屬不同的類別。
通常錯誤是非正常的系統級的嚴重錯誤,出現后程序直接終止,這種錯誤是不應該、或是不可預見的,不推薦用 try-catch 來捕獲處理。
異常是程序運行時不滿足某些條件而出現的非嚴重的錯誤,應盡量使用 try-catch 來捕獲它。
而在JS中,只定義了錯誤(Error),作為其內置的對象,其原型對象一般包括 name 和 message 兩個屬性。不同的瀏覽器還實現了不同的錯誤類型以及附加的屬性和方法。
異常(Exception)只是錯誤的另一種說法,它們實際上一個東西,都可以用 try-catch 來處理,因此不用在意它們的處理方式。一個異常的對象,在JS里實際上就是一個擁有 name 和 message 屬性的Error實例罷了。
唯一不同的是,如上面所述,JS中異常可以以字符串、數字、布爾值或對象的形式來拋出處理,而錯誤則通常特指Error對象及其繼承的自定義子對象。