摘要:類型的錯誤會在數值超出相應范圍時觸發。最常發生類型錯誤的情況,就是傳遞給函數的參數事先未經檢查,結果傳入類型與預期類型不相符。捕獲錯誤的目的在于避免瀏覽器以默認方式處理它們而拋出錯誤的目的在于提供錯誤發生具體原因的消息。
0 前言
目前讀到了《高程3》的錯誤檢測部分,現在先挖一個坑,關于錯誤檢測應該寫三篇總結:firebug檢測錯誤和輸出信息;try-catch錯誤捕獲;常見錯誤種類。
本篇邏輯思路如下:首先介紹進行錯誤捕獲的try-catch語句;然后介紹常見的錯誤類型,這點會結合firebug來說明;其次介紹try-catch語句和錯誤類型結合使用以捕獲錯誤;但是如果捕獲的錯誤以瀏覽器的語言表示,還是很難找到錯誤,因此推薦使用throw拋出開發者自定義的錯誤,這樣,錯誤的位置和原因就會更易發現;最后就錯誤拋出和錯誤捕獲進行了總結討論。
1 try-catch簡介良好的錯誤處理機制可以讓用戶和開發者及時得到提醒,知道到底發生了什么事,因而不會驚惶失措。ECMA-262 第 3 版引入了 try-catch 語句,作為 JavaScript 中處理異常的一種標準方式?;镜恼Z法如下所示,
try{ // 可能會導致錯誤的代碼 } catch(error){ // 在錯誤發生時怎么處理 }
我們應該把所有可能會拋出錯誤的代碼都放在 try 語句塊中,而把那些用于錯誤處理的代碼放在 catch 塊中。如果 try 塊中的任何代碼發生了錯誤,就會立即退出代碼執行過程,然后接著執行 catch 塊。此時, catch 塊會接收到一個包含錯誤信息的對象。即使你不想使用這個錯誤對象,也要指定一個參數名。這個對象中包含的實際信息會因瀏覽器而異,但共同的是有一個保存著錯誤消息的 message 屬性。這個 message 屬性是唯一一個能夠保證所有瀏覽器都支持的屬性,除此之外, IE、 Firefox、 Safari、 Chrome 以及 Opera 都為錯誤對象添加了其他相關信息。在跨瀏覽器編程時,最好還是只使用 message 屬性。
一個測試例子:
只要代碼中包含 finally 子句,則無論 try 或 catch 語句塊中包含什么代碼——甚至 return 語句,都不會阻止 finally 子句的執行。如下例所示:
function testFinally() { try { return 2; } catch (error) { return 1; } finally { return 0; } } function testWithoutFinally() { try { return 2; } catch (error) { return 1; } } console.log(testFinally());//輸出0 console.log(testWithoutFinally());//輸出2
如果提供 finally 子句,則 catch 子句就成了可選的(catch 或 finally 有一個即可)。 IE7 及更早版本中有一個 bug:除非有 catch 子句,否則 finally 中的代碼永遠不會執行。IE8 修復了這個 bug。如果你仍然要考慮 IE 的早期版本,那就只好提供一個 catch 子句,哪怕里面什么都不寫。
另一個測試實例:
var example = function() { try { window.someNonexistentFunction(); } catch (error) { console.log(error.name); console.log(error.message); return 1; } finally { console.log("everything is over"); } }; example();
測試結果:先后執行了try/catch/finally中的語句,問題是為什么會在最后執行一次catch中的return語句?留給自己一個問題吧。
每種錯誤都有對應的錯誤類型,而當錯誤發生時,就會拋出相應類型的錯誤對象(error object)。ECMA-262 定義了下列 7 種錯誤類型:
1) Error 是基類型,其他錯誤類型都繼承自該類型。因此,所有錯誤類型共享了一組相同的屬性(錯誤對象中的方法全是默認的對象方法)。
2)EvalError 類型的錯誤會在使用 eval()函數而發生異常時被拋出,但是拋出的錯誤不一定是EvalError 類型。如果沒有把 eval()當成函數調用,Firefox 4+和 IE8 對此拋出 TypeError。
3)RangeError 類型的錯誤會在數值超出相應范圍時觸發。例如,在定義數組時,如果指定了數組不支持的項數(如-20 或 Number.MAX_VALUE),就會觸發這種錯誤。
4)在找不到對象的情況下,會發生 ReferenceError(這種情況下,會直接導致人所共知的"object expected"瀏覽器錯誤)。通常,在訪問不存在的變量時,就會發生這種錯誤。
5) 至于 SyntaxError,當我們把語法錯誤的 JavaScript 字符串傳入 eval()函數時,就會導致此類錯誤。如果語法錯誤的代碼出現在 eval()函數之外,則不太可能使用 SyntaxError,因為此時的語法錯誤會導致 JavaScript 代碼立即停止執行。
6)TypeError 類型在 JavaScript 中會經常用到,在變量中保存著意外的類型時,或者在訪問不存在的方法時,都會導致這種錯誤。錯誤的原因雖然多種多樣,但歸根結底還是由于在執行特定于類型的操作時,變量的類型并不符合要求所致。最常發生類型錯誤的情況,就是傳遞給函數的參數事先未經檢查,結果傳入類型與預期類型不相符。
7) 在使用 encodeURI()或 decodeURI(),而 URI 格式不正確時,就會導致 URIError 錯誤。這種錯誤也很少見,因為前面說的這兩個函數的容錯性非常高。
上述測試過程在FF如下:
3 使用try-catch語句捕獲錯誤要想知道錯誤的類型,可以像下面這樣在 try-catch 語句的 catch 語句中使用 instanceof 操作符。
try { someFunction(); } catch (error){ if (error instanceof TypeError){ //處理類型錯誤 } else if (error instanceof ReferenceError){ //處理引用錯誤 } else { //處理其他類型的錯誤 } }
在跨瀏覽器編程中,檢查錯誤類型是確定處理方式的最簡便途徑;而包含在 message 屬性中的錯誤消息會因瀏覽器而異。
使用 try-catch 最適合處理那些我們無法控制的錯誤。假設你在使用一個大型 JavaScript 庫中的函數,該函數可能會有意無意地拋出一些錯誤。由于我們不能修改這個庫的源代碼,所以大可將對該函數的調用放在 try-catch 語句當中,萬一有什么錯誤發生,也好恰當地處理它們。
與 try-catch 語句相配的還有一個 throw 操作符,用于隨時拋出自定義錯誤。拋出錯誤時,必須要給 throw 操作符指定一個值,這個值是什么類型,沒有要求。在遇到 throw 操作符時,代碼會立即停止執行。僅當有 try-catch 語句捕獲到被拋出的值時,代碼才會繼續執行。
通過使用自定義的內置錯誤類型,可以更真實地模擬瀏覽器錯誤。每種錯誤類型的構造函數接收一個參數,即實際的錯誤消息。下面是例子。
throw new Error("Something bad happened."); throw new SyntaxError("I don’t like your syntax."); throw new TypeError("What type of variable do you take me for?"); throw new RangeError("Sorry, you just don’t have the range."); throw new EvalError("That doesn’t evaluate."); throw new URIError("Uri, is that you?"); throw new ReferenceError("You didn’t cite your references properly.");
瀏覽器會像處理自己生成的錯誤一樣,來處理這些代碼拋出的錯誤。換句話說,瀏覽器會以常規方式報告這一錯誤,并且會顯示這里的自定義錯誤消息。
拋出自定義錯誤的意義:方便快速定位錯誤并糾錯。雖然瀏覽器會自己報錯,但是這些報錯信息在瀏覽器中達不到統一,而且如果出現同種類型錯誤,查找來源是復雜的,尤其是在數千行代碼中。但是如果你知道可能的代碼錯誤,可以直接在代碼中添加這些自定義的錯誤,一旦發生這些錯誤,瀏覽器就報出自定義錯誤,關鍵是這個錯誤的位置和類型顯而易見。
實例:一個必須接收數組作為參數的函數如果接收字符串作為參數就會報錯。
function process(values){ values.sort(); for (var i=0, len=values.length; i < len; i++){ if (values[i] > 100){ return values[i]; } } return -1; } var a = process("string"); console.log(a);
firebug中結果:
添加自定義錯誤后的代碼:
function process(values){ if (!(values instanceof Array)){ throw new Error("process(): Argument must be an array."); } values.sort(); for (var i=0, len=values.length; i < len; i++){ if (values[i] > 100){ return values[i]; } } return -1; } var a = process("string"); console.log(a);
firebug中結果:
如果 values 參數不是數組,就會拋出一個錯誤。錯誤消息中包含了函數的名稱,以及為什么會發生錯誤的明確描述。如果一個復雜的 Web 應用程序發生了這個錯誤,那么查找問題的根源也就容易多了。
利用原型鏈還可以通過繼承 Error 來創建自定義錯誤類型。此時,需要為新創建的錯誤類型指定 name 和 message 屬性。
一個實例:
//通過繼承Error實現自定義錯誤類型,要定義name和message屬性 function CustomError(message){ this.name = "CustomError"; this.message = message; } CustomError.prototype = new Error(); function process(values){ //如果出現錯誤,就拋出自定義錯誤類型的對象實例 if (!(values instanceof Array)){ throw new CustomError("process(): Argument must be an array."); } values.sort(); for (var i=0, len=values.length; i < len; i++){ if (values[i] > 100){ return values[i]; } } return -1; } process("string");
firebug顯示自定義類型的錯誤:
5 拋出錯誤與使用 try-catch捕獲錯誤關于何時該拋出錯誤,而何時該使用 try-catch 來捕獲它們,是一個老生常談的問題。一般來說,應用程序架構的較低層次中經常會拋出錯誤,但這個層次并不會影響當前執行的代碼,因而錯誤通常得不到真正的處理。如果你打算編寫一個要在很多應用程序中使用的 JavaScript 庫,甚至只編寫一個可能會在應用程序內部多個地方使用的輔助函數,我都強烈建議你在拋出錯誤時提供詳盡的信息。然后,即可在應用程序中捕獲并適當地處理這些錯誤。
說到拋出錯誤與捕獲錯誤,我們認為只應該捕獲那些你確切地知道該如何處理的錯誤。捕獲錯誤的目的在于避免瀏覽器以默認方式處理它們;而拋出錯誤的目的在于提供錯誤發生具體原因的消息。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87976.html
摘要:類型的錯誤會在數值超出相應范圍時觸發。最常發生類型錯誤的情況,就是傳遞給函數的參數事先未經檢查,結果傳入類型與預期類型不相符。捕獲錯誤的目的在于避免瀏覽器以默認方式處理它們而拋出錯誤的目的在于提供錯誤發生具體原因的消息。 0 前言 目前讀到了《高程3》的錯誤檢測部分,現在先挖一個坑,關于錯誤檢測應該寫三篇總結:firebug檢測錯誤和輸出信息;try-catch錯誤捕獲;常見錯誤種類。...
錯誤處理與調試 錯誤處理 try-catch語句 try{ //可能會導致錯誤的代碼 }catch(error){ //在錯誤發生時怎么處理 } 發生錯誤時可以顯示瀏覽器給出的信息 try{ window.someNonexistentFunction(); }catch(error){ alert(error.message); } 在try-catch語句中是可選的,但...
摘要:不允許直接訪問內存中的位置,也就是說不能直接操作對象的內存空間。在操作對象時,實際上是在操作對象的引用而不是實際的對象。解除引用的真正作用是讓值脫離執行環境,以便垃圾收集器下次運行時將其回收 1 基本類型和引用類型的值 基本數據類型是按值訪問的,因為可以操作保存在變量中的實際的值 基本類型值在內存中占據固定大小的空間,因此被保存在棧內存中 引用類型的值是保存在內存中的對象。JavaSc...
摘要:使用函數發生異常時拋出。數值超出相應范圍時拋出。拋出錯誤與相配的還有一個操作符,用于拋出自定義錯誤。錯誤事件沒有通過處理的錯誤都會觸發對象的事件。任何瀏覽器中,事件處理程序都不會創建對象,但它可以接受個參數錯誤消息錯誤所在的和行號。 try-catch語句 該語句最適合處理那些我們無法控制的錯誤,在明明白白地知道自己的代碼會發生錯誤時,再使用該語句就不太合適了。 ECMA-262第3...
摘要:標識符按以下規則組合第一個字符必須是一個字母,下劃線或一個美元符號。包含值的變量和尚未定義的變量是不一樣的,例子報錯然而,對未初始化的變量執行操作符會返回值,對未聲明的變量執行操作符統一也會返回值。 1. 語法 1.1 區分大小寫 變量、函數名和操作費都區分大小寫。 1.2 標識符 標識符指變量、函數、屬性的名字,或者函數的參數。標識符按以下規則組合: 第一個字符必須是一個字母,下劃線...
閱讀 423·2019-08-29 12:44
閱讀 3001·2019-08-26 17:49
閱讀 2398·2019-08-26 13:40
閱讀 1180·2019-08-26 13:39
閱讀 3656·2019-08-26 11:59
閱讀 1814·2019-08-26 10:59
閱讀 2454·2019-08-23 18:33
閱讀 2687·2019-08-23 18:30