您好,登錄后才能下訂單哦!
本文實例講述了JavaScript錯誤處理操作。分享給大家供大家參考,具體如下:
良好的錯誤處理機制可以讓用戶得到及時的提醒,所以讓我們來看看 JavaScript 提供了哪些針對錯誤處理的工具和方法吧O(∩_∩)O~
ECMA-262 第 3 版引入了 try-catch 語句,這時 JavaScript 處理異常的標準方式:
try{ //可能會導致錯誤的代碼 } catch (error){ //錯誤處理 }
如果 try 塊中的代碼發生了錯誤,會立即執行 catch 塊的代碼。 catch 塊有一個包含錯誤信息的對象,它有一個 message 屬性,表示的是瀏覽器給出的錯誤消息:
<script type="text/javascript"> try { window.someNonexistenceFunction(); } catch (error) { console.log(error.message); } </script>
message 屬性是所有的瀏覽器都支持的屬性,所以在跨瀏覽器編程中,最好只使用這個屬性。
finally 子句是可選的,如果使用了 finally 子句,里面包含的代碼是絕對會被執行的!甚至連 return 語句都無法阻止它被執行:
<script type="text/javascript"> function testFinally() { try { return 2; } catch (error) { return 1; } finally { return 0; } } console.log(testFinally());//0 </script>
IE7 及更早的版本有一個 bug:除非有 catch 子句,否則 finally 中的代碼永遠不會被執行!IE8 修復了這個 bug。
注意:只要在代碼中使用了 finally 子句,那么不管 return 放在 try 還是 catch 語句中,都會被忽略!
當錯誤發生時,會拋出相應類型的錯誤對象。ECMA-262 定義了 7 種錯誤類型:
1.2.1 Error
Error 是基類型,即其他的錯誤類型都是從 Error 繼承來的。可以利用 Error 來自定義錯誤類型。
1.2.2 EvalError
EvalError 是在使用 eval() 函數發生異常時被拋出。怎么才算是異常呢?如果沒有把 eval() 當作函數來使用,就會拋出 EvalError:
new eval();//拋出 EvalError eval = foo;//拋出 EvalError
實際開發中很少這樣使用 eval()
函數的(除非腦袋秀逗了O(∩_∩)O~),所以很少會遇到 EvalError。
1.2.3 RangeError
RangeError 會在數值超出規定范圍時被拋出。比如在定義數組時,指定了數組不支持的數組項數,就會拋出這個錯誤:
var item1 = new Array(-20);//拋出 RangeError var item1 = new Array(Number.MAX_VALUE);//拋出 RangeError
1.2.4 ReferenceError
找不到對象時,會拋出 ReferenceError(這就是瀏覽器的知名的 “object expected” 錯誤)。一般在訪問不存在的變量時,會拋出這個錯誤:
var obj = x;//x 還未被聲明,所以拋出 ReferenceError
1.2.5 SyntaxError
如果把帶著錯誤語法的字符串傳入 eval()
函數時,就會拋出 SyntaxError:
eval("a ++ b");//拋出 SyntaxError
在 eval()
函數之外的語法錯誤,會導致 JavaScript 立即停止執行,所以不會拋出這個錯誤!
1.2.6 TypeError
如果變量中保存著意外的類型,或者訪問不存在的方式時,就會拋出 TypeError。這個錯誤比較常見:
var o = new 10;//拋出 TypeError alert("name" in true);//拋出 TypeError Function.prototype.toString.call("name");//拋出 TypeError
如果傳遞給函數的參數類型與預期類型不符,也會拋出這個錯誤。
1.2.7 URIError
使用 encodeURI()
或者 decodeURI()
時,URI 的格式不正確,就會拋出 URIError 錯誤。一般很少發生,因為這兩個函數有著非常高的容錯性O(∩_∩)O~
可以針對這些錯誤類型進行恰當的處理:
try{ someFunction(); } catch (error){ if (error instanceof TypeError){ //處理類型錯誤 } ... }
因為包含在 message 中的消息會因瀏覽器而異,所以在跨瀏覽器編程中,最好直接檢查這些錯誤類型。
try-catch 最適合用于那些我們無法控制的錯誤,比如使用了一個開源庫中的函數,而我們無法修改源代碼的情況。
而對于自定義的函數,驗證函數參數類型是否合法的情況,就不應該使用 try-catch,因為這個函數是我們可以修改的,在使用參數前先進行驗證才是正途。
throw 操作符可以拋出自定義的錯誤,必須要指定一個值,這個值可以是任意類型。代碼在遇到 throw 操作符時,會立即停止執行。只有在 try-catch 語句捕獲到被拋出的值時,才會繼續執行。
通過使用之前說過的內置錯誤類型,可以模擬瀏覽器錯誤。這些錯誤類型的構造函數都接收一個參數,即實際的錯誤消息:
throw new Error("Something bad happened.");
最常使用這些錯誤類型來創建自定義的錯誤消息:Error、RangeError、ReferenceError 和 TypeError。
也可以利用原型鏈,通過繼承 Error 來創建自定義消息。比如,這里為新創建的錯誤類型指定了 name 和 message 屬性:
<script type="text/javascript"> function CustomError(message) { this.name = "CustomError"; this.message = message; } CustomError.prototype = new Error(); throw new CustomError("My message"); </script>
這樣創建的自定義錯誤與瀏覽器錯誤并不同,所以可是很有用的哦O(∩_∩)O~
注意: IE 只有在拋出 Error 對象時才會顯示自定義的錯誤消息!其他錯誤對象,它只會顯示 “exception thrown and not caught”。
應該在已知的、某種特定錯誤條件下(會導致函數無法正常執行),拋出自定義的錯誤:
<script type="text/javascript"> 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; } process("hi"); </script>
如果給上面的函數傳入一個字符串參數,那么 sort() 就會拋錯,所以我們在這里加入了帶有適當消息的自定義錯誤。這對于一個有著幾千行腳本代碼的項目來說,可以顯著地提升代碼的可維護性O(∩_∩)O~
錯誤消息時包含了函數名稱以及為什么會發生錯誤的明確描述,是不是很清晰呀O(∩_∩)O~
在開發時,要注意函數可能失敗的因素,把這些因素都加上自定義錯誤吧!良好的錯誤處理機制是確保代碼只發生我們定義的錯誤。
建議在拋出錯誤時盡量提供詳盡的信息,因為我們拋出錯誤不就是為了在維護時,能夠知道錯誤發生的具體位置和具體原因的嗎?
任何沒有通過 try-catch 處理的錯誤都會觸發 window 對象的 error 事件(IE、Firfox 和 chrome 支持)。它接收 3 個參數:錯誤消息、錯誤所在的 URL 和行號。一般只有錯誤消息有用。只能通過 DOM0 級技術來指定 onerror 事件處理程序,如果返回 false,就可以阻止瀏覽器報告錯誤的默認行為:
<script type="text/javascript"> window.onerror= function (message,url,line) { console.log(message); return false; } </script>
這個函數其實就是整個文檔的 try-catch 語句,它可以捕獲所有沒有被處理的運行時錯誤。理想情況下,錯誤都被包含在 try-catch 語句中,所以不會使用到它。
注意: 不同的瀏覽器下,這個函數的處理方式不同。在 IE 中,發生了 onerror 事件,代碼仍會執行,所有的變量和數據都會保留。但在 Firefox 中,代碼會停止執行,而且之前所有的變量和數據都會被銷毀!
圖像也支持 error 事件。如果圖像的 src 屬性中的 URL 無法返回被識別的圖像格式時,就會觸發持 error 事件。這時的 error 事件會返回一個以圖像為目標的 event 對象:
<script type="text/javascript"> var image = new Image(); EventUtil.addHandler(image, "load", function (event) { console.log("Image loaded!"); }); EventUtil.addHandler(image, "error", function (event) { console.log("Image not loaded!"); }); image.src = "smilex.gif";//實際并不存在 </script>
注意,如果發生了 error 事件,那么這個圖像的下載過程就已經結束咯。
因為 JavaScript 是松散類型的語言,所以錯誤只會在代碼運行期間發生。一般情況下,我們需要重點關注以下三種錯誤:
① 類型轉換錯誤
② 數據類型錯誤
③ 通信錯誤
在使用相等(==)或不相等(!==),或者在 if、for 或 while 中使用了非布爾值時,最常發生類型轉換錯誤。
所以建議使用全等(===)和不全等(!==)來避免類型轉換操作。
if 等語句會自動把任何值都轉換為布爾值:
function concat(str1, str2, str3){ var result = str1 + str2; if (str3){//不要這樣!!! result +=str3; } return result; }
這個函數是想拼接兩個或三個字符串,然后返回結果。所以這里的第三個參數是可選的,,所以必須要檢查。如果我們在調用這個函數時,只用到前兩個參數,這意味著第三個參數因為是未使用過的命名變量,所以被自動賦值給 undefine,而 undefine 在 if 中會被自動轉換為 false,這樣可以。但是,如果第三個參數傳入數值 0,在 if 中會被自動轉換為 false,那么就不會被加到 result 中!所以我們要進行檢查:
function concat(str1, str2, str3){ var result = str1 + str2; if (typeof str3 == "string"){ result +=str3; } return result; }
function getQueryString(url){ var pos = url.indexOf("?"); if (pos > -1){ return url.substring(pos + 1); } return ""; }
這個函數打算返回給定 URL 中的查詢字符串。但如果傳入非字符串類型的參數,就會導致錯誤。所以要加上類型判斷:
function getQueryString(url){ if(typeof url == "string"){ var pos = url.indexOf("?"); if (pos > -1){ return url.substring(pos + 1); } } return ""; }
還有,如果在流控制語句中使用非布爾值也會導致數據類型錯誤:
function reverseSort(values){ if (values){//非數組值都會報錯 values.sort(); values.reverse(); } }
另一種錯誤是將參數與 null 進行比較,這只能確保參數不是 null 和 undefined,也不建議將參數與 undefined 進行比較。
還有一種錯誤是,只針對某一特性進行檢測:
function reverseSort(values){ if (typeof values.sort == "function"){ values.sort(); values.reverse(); } }
上面的函數,如果傳入帶有 sort()
方法的對象,就會通過檢測,但會在調用 reverse()
方法時報錯!所以這里最好是使用 instanceof 來檢測:
function reverseSort(values){ if (values instanceof Array){ values.sort(); values.reverse(); } }
總的來說,基本類型的值使用 typeof
檢測,而對象的值使用 instanceof
來檢測。特別是面向公眾的 API,一定要執行類型檢查,以確保函數始終能夠正常執行。
JavaScript 與服務器之間的任何一次通信,就有可能會產生錯誤。
一種通信錯誤是發送了不正確的 URL 格式數據。一般是沒有使用 encodeURIComponent()
對數據進行編碼,可以使用這里的函數來處理查詢字符串:
/** * 添加查詢字符串 * @param url URL * @param name 參數名 * @param value 參數值 * @returns {*} */ function addQueryStringArg(url, name, value) { if (url.indexOf("?") == -1) { url += "?"; } else { url += "&"; } url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url; }
盡量使用這個函數,就可以確保編碼正確。
非致命錯誤可以根據以下列出的一個或多個條件來確定:
而致命錯誤也可以根據以下列出的一個或多個條件來確定:
如果發生了致命錯誤,要立即發送消息通知用戶,告訴他們無法再繼續操作咯。如果必須刷新頁面才會恢復,也必須通知用戶,并提供了可刷新頁面的按鈕。
比如,在大型網站中,可能有多個互不依賴的模塊,它們是類似這樣初始化的:
for (var i=0, len=mods.length; i<len; i++){ mods[i].init(); }
這樣做的問題是,如果有一個模塊發生錯誤,那么就會導致后續的其它模塊無法被初始化,從而導致致命的錯誤!我們這樣改造下,讓致命的錯誤變成非致命的錯誤:
for (var i=0, len=mods.length; i<len; i++){ try{ mods[i].init(); } catch (ex){ ... } }
建議集中保存錯誤日志,這樣可以方便后續查找錯誤的原因。所以我們可以把 JavaScript 錯誤發送給服務器,讓服務器保存起來。這樣把前后端的錯誤集中起來管理,就可以很方便地對數據進行分析咯O(∩_∩)O~
首先先在服務器上創建一個接口,用于接收頁面發送的錯誤數據:
/** * 記錄 JavaScript 錯誤 * @param sev 嚴重程度,比如:nonfatal * @param msg 錯誤消息 */ function logError(sev,msg){ var img=new Image(); img.src="log.action?sev="+encodeURIComponent(sev)+"&msg="+encodeURIComponent(msg); }
使用 Image 對象來發送請求,有這些好處:
只要是使用了 try-catch 語句,就要把錯誤記錄到日志中:
for (var i=0, len=mods.length; i<len; i++){ try{ mods[i].init(); } catch (ex){ logError("nonfatal","模塊初始化失敗:"+ex.message); } }
第二個參數是上下文信息以及 JavaScript 的錯誤消息,帶上上下文信息可以方便分析導致錯誤的真正原因。
更多關于JavaScript相關內容感興趣的讀者可查看本站專題:《JavaScript錯誤與調試技巧總結》、《JavaScript傳值操作技巧總結》、《javascript編碼操作技巧總結》、《JavaScript中json操作技巧總結》、《JavaScript切換特效與技巧總結》、《JavaScript查找算法技巧總結》、《JavaScript動畫特效與技巧匯總》、《JavaScript數據結構與算法技巧總結》、《JavaScript遍歷算法與技巧總結》及《JavaScript數學運算用法總結》
希望本文所述對大家JavaScript程序設計有所幫助。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。