1. 程式人生 > >【javaScript基礎】異常處理

【javaScript基礎】異常處理

導致 mis develop eof 解決 ted var 有效 fin

? ? ? ? ?理解異常在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基礎】異常處理