【javaScript基礎】異常處理
? ? ? ? ?理解異常在javaScript面向對象編程是非常重要的,異常是一種非常強大的處理錯誤的方式。
錯誤處理
? ? ? ? ?首先我們來看一個有問題的代碼:
nonexistant();
在以上這個樣例中,訪問一個不存在的變量,在這樣的情況下,程序會怎麽處理?非常早曾經的處理方式就是程序直接崩潰死掉,所以我們不能容忍這樣的處理方式,須要有辦法來處理。
? ? 最簡單的處理方式是先檢查,像這樣:
if (window.func) { func(); }
? ? ? ? ?上面這樣的處理方式,仍然可能還會出現錯誤。
由於window.func可能不是一個函數。因此我們仍須要這樣檢查:
if (typeof(func) == ‘function‘) {
func();
}
在上面的樣例中,typeof確保變量存在並確保是個函數。
???????? 我們滿懷希望地做了非常多須要的檢查來確保運行func是安全的。可是假設func的函數體內有錯誤呢?我們更想做的是處理錯誤,而不是讓程序死掉。
???????? 我們能夠用trycatch結構來處理。
Try catch 結構
? ? ? ? ?用try…catch來取代我們經常使用的if語句結構來處理錯誤,我們用例如以下代碼來改寫上面的樣例:
try {
func()
} catch(e) {
alert(e)
}
? ? ? ? ?假設在try塊中出現錯誤,這個時候catch塊會起作用,參數e被賦值為一個特別的異常對象。該對象包含異常發生時的一些信息。
???????? 變量e是Error對象的一個實例(或者從TypeError,ReferenceError等繼承)。
???????? 這個錯誤的屬性在不同瀏覽器有點不一樣。詳情參考Error in MDN?和?Error inMSDN。
可是基本屬性是同樣的:
name:錯誤類型,對於瀏覽器產生的error會匹配error構造函數如TypeError,?ReferenceError?等。
message: 告訴我們更具體的error信息。
在下面樣例中,我們在try塊中添加其它聲明,name和message會被打印出來。
try {
var a = 5
var res = func(a)
if (res > 0) doA()
else doB()
} catch(e) {
alert("name:" + e.name + "\nmessage:" + e.message)
}
非常多異常都能夠被try..catch捕獲,你僅需通過try來檢測可能的錯誤即可了。
獲取棧的信息
? ? ? ? ?Firefox,Chrome, Opera瀏覽器提供了stack屬性,通過stack屬性我們能夠看到全部導致異常的嵌套的調用信息,樣例例如以下:
function f(a) {
g(a+1)
}
function g(a) {
notexists;
}
try { f(1) } catch(e) { alert(e.stack)
? ? ? ? ?不幸的是在IE中沒有這個屬性。甚至在IE9中也沒有。
Try…catch…finally完整形式
? ? ? ? ?完整的組成形式是由3部分組成:
try {
.. try statemenets ..
} catch(exception) {
.. catch statements ..
} finally {
.. finally statements ..
運行步驟例如以下:
1.?Try中的聲明會被運行。假設沒有發生錯誤,catch部分會被忽視。
2.?假設發生錯誤,exception變量會被賦值為錯誤對象。而且catch中的聲明也會被運行。
3.?在以上兩種情況下,在try或者catch中無論有沒有運行,finally代碼都會被運行。
try…catch…finally…return
在下面樣例中,假設try中有return語句而且有finally塊時,finally中的運行完後,運行return語句。
function inc(a) {
try {
return a+1
} catch(e) {
// ..
} finally {
alert(‘done‘)
}
}
alert( inc(1) )
//運行結果:‘done’, 2
Throw聲明
全部的錯誤能夠被分成兩種:
1.?程序設計錯誤:通常是由開發者造成的。如輸入錯誤。
2.?異常流錯誤:這個錯誤是程序運行過程中的正常部分。一個常見的錯誤是表單驗證。
假設用戶輸入了一些錯誤,正常的做法是處理這個錯誤而且叫用戶反復輸入。
???????? 用try…catch來處理異常錯誤,須要通過throw手動拋出錯誤。
???????? 語法是:throw e,e能夠是不論什麽東西。無論你拋出什麽,都能夠被catch…捕獲,可是假設在try塊外面拋出程序可能會崩潰。
???????? 下面的樣例展示了throw是怎樣工作的。
try {
throw 5
} catch(e) {
alert("Caught: "+e)
}
表單驗證樣例
? ? ? ? ?比如,我們對年齡進行驗證,檢查是否合法。
function validateAge(age) { // age is a text to check
if (age === ‘‘) return; // no age is valid
age = +age
if (isNaN(age)) {
throw { name: ‘BadAge‘, message: ‘Invalid age‘ }
}
if (age < 5 || age > 150) {
throw { name: ‘BadAge‘, message: ‘Age out of range‘ }
}
}
try {
var age = prompt("Enter your age please?")
validateAge(age)
alert("The age is accepted!")
} catch(e) {
alert("Error: "+e.message)
}
經常來說。拋出的異常對象最好是從Error對象繼承。提供一種更好的方式來管理error在上面的樣例中應該這樣實現:throw new BadAgeError("Invalid age")。
驗證變化
如今假設須要加入一個驗證條件,驗證用戶所提供的值是必須提供的。而且是有效的年齡。
比方我們實現了validateAge和validateRequired。
錯誤的檢測方法
var value = input.value
// VALIDATE
var error = validateRequired(value)
if (!error) {
error = validateAge(value)
}
if (!error) {
/* another validator... */
}
// FINISHED VALIDATING
if (error) {
/* process error */
} else {
/* success */
}
Try…catch方法
這樣的方式就是當檢測到錯誤時手動拋出。
var value = input.value
try {
validateRequired(value)
validateAge(value)
// other validators in a row
/* success */
} catch(e) {
/* process error */
}
我們不須要一個一個地來檢測,僅僅須要把可能出現錯誤的驗證放到try塊中即可了。假設一有錯誤。在catch中就會捕獲到。沒有錯誤自然非常順利地運行。不會進入到catch塊中。
比較
用try..catch處理錯誤有一些長處和缺點:
1.?Try…catch方法處理錯誤更幹凈、簡單可依賴,能夠捕獲全部錯誤。
2.?有可能存在一些不能檢測的異常,try…catch是唯一能解決辦法。
比如檢測瀏覽器的一些特性。
3.?Try…catch結構會占領幾行代碼的位置,看起來代碼不太優雅。
異常分析和又一次拋出
? ? ? ? ?有時代碼會產生不同的錯誤,這樣的情況下,經經常使用if來選擇正確的處理方式。下面是偽代碼。
try {
// 1. do smth
} catch(e) {
if (e instanceof ValidationError) {
// 2.1 process e
} else if (e instanceof PermissionError) {
// 2.2 process e
} else {
// 3. we don‘t know how to deal with e
throw e
}
}
1.?在try塊中的代碼比較復雜,或許會拋出異常。有些異常我們知道怎麽處理,比方ValidationError,可是其它一些異常不知道。
2.?在catch塊中,我們分析異常而且處理它。
3.?否則。異常又一次拋出,假定在外面另一層try…catch塊知道怎麽處理該異常。
異常要麽被又一次拋出,要麽被處理。千萬不要無論它。除非你全然知道你在做什麽。
try {
func()
} catch(e) {
if (e instanceof KnownError) {
// ...
}
}
在上面代碼片段中。除了KnownError異常外,其它異常都被忽視了。
坦白地說。在java的世界裏有這樣的不處理異常的情況存在,可是留下不處理的異常總有隱患。
???????? 想象下,假設在func中代碼有輸入錯誤,這將會非常難調試。由於TypeError?和ReferenceError?異常被忽視了。
總結
1.?Try…catch…finally結構同意你在try塊中加入幾種聲明,能夠在各自的catch塊中進行異常處理。
2.??同意處理全部錯誤。包含JS自己產生的和手動拋出的。
3.??嚴格來說javaScript同意throw不論什麽值,可是推薦全部的錯誤繼承Error對象,形成繼承層級。在這樣的情況下,instanceof?工作得非常好。比如你能夠捕獲全部e instanceof ValidationError的異常。ValidationError包含AgeValidationError,?RequiredValidationError?等。
【javaScript基礎】異常處理