新聞中心
本文實(shí)例講述了JavaScript錯(cuò)誤處理操作。分享給大家供大家參考,具體如下:
創(chuàng)新互聯(lián)成立于2013年,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目成都網(wǎng)站制作、做網(wǎng)站網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢(mèng)想脫穎而出為使命,1280元平潭做網(wǎng)站,已為上家服務(wù),為平潭各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:13518219792
良好的錯(cuò)誤處理機(jī)制可以讓用戶得到及時(shí)的提醒,所以讓我們來(lái)看看 JavaScript 提供了哪些針對(duì)錯(cuò)誤處理的工具和方法吧O(∩_∩)O~
1 try-catch 語(yǔ)句
ECMA-262 第 3 版引入了 try-catch 語(yǔ)句,這時(shí) JavaScript 處理異常的標(biāo)準(zhǔn)方式:
try{ //可能會(huì)導(dǎo)致錯(cuò)誤的代碼 } catch (error){ //錯(cuò)誤處理 }
如果 try 塊中的代碼發(fā)生了錯(cuò)誤,會(huì)立即執(zhí)行 catch 塊的代碼。 catch 塊有一個(gè)包含錯(cuò)誤信息的對(duì)象,它有一個(gè) message 屬性,表示的是瀏覽器給出的錯(cuò)誤消息:
message 屬性是所有的瀏覽器都支持的屬性,所以在跨瀏覽器編程中,最好只使用這個(gè)屬性。
1.1 finally 子句
finally 子句是可選的,如果使用了 finally 子句,里面包含的代碼是絕對(duì)會(huì)被執(zhí)行的!甚至連 return 語(yǔ)句都無(wú)法阻止它被執(zhí)行:
IE7 及更早的版本有一個(gè) bug:除非有 catch 子句,否則 finally 中的代碼永遠(yuǎn)不會(huì)被執(zhí)行!IE8 修復(fù)了這個(gè) bug。
注意:只要在代碼中使用了 finally 子句,那么不管 return 放在 try 還是 catch 語(yǔ)句中,都會(huì)被忽略!
1.2 錯(cuò)誤類型
當(dāng)錯(cuò)誤發(fā)生時(shí),會(huì)拋出相應(yīng)類型的錯(cuò)誤對(duì)象。ECMA-262 定義了 7 種錯(cuò)誤類型:
- Error
- EvalError
- RangeError
- ReferenceError
- SyntaxError
- TypeError
- URIError
1.2.1 Error
Error 是基類型,即其他的錯(cuò)誤類型都是從 Error 繼承來(lái)的。可以利用 Error 來(lái)自定義錯(cuò)誤類型。
1.2.2 EvalError
EvalError 是在使用 eval() 函數(shù)發(fā)生異常時(shí)被拋出。怎么才算是異常呢?如果沒(méi)有把 eval() 當(dāng)作函數(shù)來(lái)使用,就會(huì)拋出 EvalError:
new eval();//拋出 EvalError eval = foo;//拋出 EvalError
實(shí)際開(kāi)發(fā)中很少這樣使用 eval()
函數(shù)的(除非腦袋秀逗了O(∩_∩)O~),所以很少會(huì)遇到 EvalError。
1.2.3 RangeError
RangeError 會(huì)在數(shù)值超出規(guī)定范圍時(shí)被拋出。比如在定義數(shù)組時(shí),指定了數(shù)組不支持的數(shù)組項(xiàng)數(shù),就會(huì)拋出這個(gè)錯(cuò)誤:
var item1 = new Array(-20);//拋出 RangeError var item1 = new Array(Number.MAX_VALUE);//拋出 RangeError
1.2.4 ReferenceError
找不到對(duì)象時(shí),會(huì)拋出 ReferenceError(這就是瀏覽器的知名的 “object expected” 錯(cuò)誤)。一般在訪問(wèn)不存在的變量時(shí),會(huì)拋出這個(gè)錯(cuò)誤:
var obj = x;//x 還未被聲明,所以拋出 ReferenceError
1.2.5 SyntaxError
如果把帶著錯(cuò)誤語(yǔ)法的字符串傳入 eval()
函數(shù)時(shí),就會(huì)拋出 SyntaxError:
eval("a ++ b");//拋出 SyntaxError
在 eval()
函數(shù)之外的語(yǔ)法錯(cuò)誤,會(huì)導(dǎo)致 JavaScript 立即停止執(zhí)行,所以不會(huì)拋出這個(gè)錯(cuò)誤!
1.2.6 TypeError
如果變量中保存著意外的類型,或者訪問(wèn)不存在的方式時(shí),就會(huì)拋出 TypeError。這個(gè)錯(cuò)誤比較常見(jiàn):
var o = new 10;//拋出 TypeError alert("name" in true);//拋出 TypeError Function.prototype.toString.call("name");//拋出 TypeError
如果傳遞給函數(shù)的參數(shù)類型與預(yù)期類型不符,也會(huì)拋出這個(gè)錯(cuò)誤。
1.2.7 URIError
使用 encodeURI()
或者 decodeURI()
時(shí),URI 的格式不正確,就會(huì)拋出 URIError 錯(cuò)誤。一般很少發(fā)生,因?yàn)檫@兩個(gè)函數(shù)有著非常高的容錯(cuò)性O(shè)(∩_∩)O~
可以針對(duì)這些錯(cuò)誤類型進(jìn)行恰當(dāng)?shù)奶幚恚?/p>
try{ someFunction(); } catch (error){ if (error instanceof TypeError){ //處理類型錯(cuò)誤 } ... }
因?yàn)榘?message 中的消息會(huì)因?yàn)g覽器而異,所以在跨瀏覽器編程中,最好直接檢查這些錯(cuò)誤類型。
1.3 合理使用 try-catch
try-catch 最適合用于那些我們無(wú)法控制的錯(cuò)誤,比如使用了一個(gè)開(kāi)源庫(kù)中的函數(shù),而我們無(wú)法修改源代碼的情況。
而對(duì)于自定義的函數(shù),驗(yàn)證函數(shù)參數(shù)類型是否合法的情況,就不應(yīng)該使用 try-catch,因?yàn)檫@個(gè)函數(shù)是我們可以修改的,在使用參數(shù)前先進(jìn)行驗(yàn)證才是正途。
2 拋出錯(cuò)誤
throw 操作符可以拋出自定義的錯(cuò)誤,必須要指定一個(gè)值,這個(gè)值可以是任意類型。代碼在遇到 throw 操作符時(shí),會(huì)立即停止執(zhí)行。只有在 try-catch 語(yǔ)句捕獲到被拋出的值時(shí),才會(huì)繼續(xù)執(zhí)行。
通過(guò)使用之前說(shuō)過(guò)的內(nèi)置錯(cuò)誤類型,可以模擬瀏覽器錯(cuò)誤。這些錯(cuò)誤類型的構(gòu)造函數(shù)都接收一個(gè)參數(shù),即實(shí)際的錯(cuò)誤消息:
throw new Error("Something bad happened.");
最常使用這些錯(cuò)誤類型來(lái)創(chuàng)建自定義的錯(cuò)誤消息:Error、RangeError、ReferenceError和 TypeError。
也可以利用原型鏈,通過(guò)繼承 Error 來(lái)創(chuàng)建自定義消息。比如,這里為新創(chuàng)建的錯(cuò)誤類型指定了 name 和 message 屬性:
這樣創(chuàng)建的自定義錯(cuò)誤與瀏覽器錯(cuò)誤并不同,所以可是很有用的哦O(∩_∩)O~
注意:IE 只有在拋出 Error對(duì)象時(shí)才會(huì)顯示自定義的錯(cuò)誤消息!其他錯(cuò)誤對(duì)象,它只會(huì)顯示 “exception thrown and not caught”。
2.1 拋出錯(cuò)誤的時(shí)機(jī)
應(yīng)該在已知的、某種特定錯(cuò)誤條件下(會(huì)導(dǎo)致函數(shù)無(wú)法正常執(zhí)行),拋出自定義的錯(cuò)誤:
如果給上面的函數(shù)傳入一個(gè)字符串參數(shù),那么 sort() 就會(huì)拋錯(cuò),所以我們?cè)谶@里加入了帶有適當(dāng)消息的自定義錯(cuò)誤。這對(duì)于一個(gè)有著幾千行腳本代碼的項(xiàng)目來(lái)說(shuō),可以顯著地提升代碼的可維護(hù)性O(shè)(∩_∩)O~
錯(cuò)誤消息時(shí)包含了函數(shù)名稱以及為什么會(huì)發(fā)生錯(cuò)誤的明確描述,是不是很清晰呀O(∩_∩)O~
在開(kāi)發(fā)時(shí),要注意函數(shù)可能失敗的因素,把這些因素都加上自定義錯(cuò)誤吧!良好的錯(cuò)誤處理機(jī)制是確保代碼只發(fā)生我們定義的錯(cuò)誤。
2.2 拋出錯(cuò)誤與使用 try-catch
建議在拋出錯(cuò)誤時(shí)盡量提供詳盡的信息,因?yàn)槲覀儝伋鲥e(cuò)誤不就是為了在維護(hù)時(shí),能夠知道錯(cuò)誤發(fā)生的具體位置和具體原因的嗎?
3 錯(cuò)誤事件
任何沒(méi)有通過(guò) try-catch 處理的錯(cuò)誤都會(huì)觸發(fā) window 對(duì)象的 error事件(IE、Firfox 和 chrome 支持)。它接收 3 個(gè)參數(shù):錯(cuò)誤消息、錯(cuò)誤所在的 URL 和行號(hào)。一般只有錯(cuò)誤消息有用。只能通過(guò) DOM0 級(jí)技術(shù)來(lái)指定 onerror事件處理程序,如果返回 false,就可以阻止瀏覽器報(bào)告錯(cuò)誤的默認(rèn)行為:
這個(gè)函數(shù)其實(shí)就是整個(gè)文檔的 try-catch 語(yǔ)句,它可以捕獲所有沒(méi)有被處理的運(yùn)行時(shí)錯(cuò)誤。理想情況下,錯(cuò)誤都被包含在 try-catch 語(yǔ)句中,所以不會(huì)使用到它。
注意: 不同的瀏覽器下,這個(gè)函數(shù)的處理方式不同。在 IE 中,發(fā)生了 onerror 事件,代碼仍會(huì)執(zhí)行,所有的變量和數(shù)據(jù)都會(huì)保留。但在 Firefox 中,代碼會(huì)停止執(zhí)行,而且之前所有的變量和數(shù)據(jù)都會(huì)被銷毀!
圖像也支持 error事件。如果圖像的 src 屬性中的 URL 無(wú)法返回被識(shí)別的圖像格式時(shí),就會(huì)觸發(fā)持 error 事件。這時(shí)的 error 事件會(huì)返回一個(gè)以圖像為目標(biāo)的 event 對(duì)象:
注意,如果發(fā)生了 error事件,那么這個(gè)圖像的下載過(guò)程就已經(jīng)結(jié)束咯。
4 常見(jiàn)的錯(cuò)誤類型
因?yàn)?JavaScript 是松散類型的語(yǔ)言,所以錯(cuò)誤只會(huì)在代碼運(yùn)行期間發(fā)生。一般情況下,我們需要重點(diǎn)關(guān)注以下三種錯(cuò)誤:
① 類型轉(zhuǎn)換錯(cuò)誤
② 數(shù)據(jù)類型錯(cuò)誤
③ 通信錯(cuò)誤
4.1 類型轉(zhuǎn)換錯(cuò)誤
在使用相等(==)或不相等(!==),或者在 if、for 或 while 中使用了非布爾值時(shí),最常發(fā)生類型轉(zhuǎn)換錯(cuò)誤。
所以建議使用全等(===)和不全等(!==)來(lái)避免類型轉(zhuǎn)換操作。
if 等語(yǔ)句會(huì)自動(dòng)把任何值都轉(zhuǎn)換為布爾值:
function concat(str1, str2, str3){ var result = str1 + str2; if (str3){//不要這樣?。?! result +=str3; } return result; }
這個(gè)函數(shù)是想拼接兩個(gè)或三個(gè)字符串,然后返回結(jié)果。所以這里的第三個(gè)參數(shù)是可選的,,所以必須要檢查。如果我們?cè)谡{(diào)用這個(gè)函數(shù)時(shí),只用到前兩個(gè)參數(shù),這意味著第三個(gè)參數(shù)因?yàn)槭俏词褂眠^(guò)的命名變量,所以被自動(dòng)賦值給 undefine,而 undefine 在 if 中會(huì)被自動(dòng)轉(zhuǎn)換為 false,這樣可以。但是,如果第三個(gè)參數(shù)傳入數(shù)值 0,在 if 中會(huì)被自動(dòng)轉(zhuǎn)換為 false,那么就不會(huì)被加到 result 中!所以我們要進(jìn)行檢查:
function concat(str1, str2, str3){ var result = str1 + str2; if (typeof str3 == "string"){ result +=str3; } return result; }
4.2 數(shù)據(jù)類型錯(cuò)誤
function getQueryString(url){ var pos = url.indexOf("?"); if (pos > -1){ return url.substring(pos + 1); } return ""; }
這個(gè)函數(shù)打算返回給定 URL 中的查詢字符串。但如果傳入非字符串類型的參數(shù),就會(huì)導(dǎo)致錯(cuò)誤。所以要加上類型判斷:
function getQueryString(url){ if(typeof url == "string"){ var pos = url.indexOf("?"); if (pos > -1){ return url.substring(pos + 1); } } return ""; }
還有,如果在流控制語(yǔ)句中使用非布爾值也會(huì)導(dǎo)致數(shù)據(jù)類型錯(cuò)誤:
function reverseSort(values){ if (values){//非數(shù)組值都會(huì)報(bào)錯(cuò) values.sort(); values.reverse(); } }
另一種錯(cuò)誤是將參數(shù)與 null 進(jìn)行比較,這只能確保參數(shù)不是 null 和 undefined,也不建議將參數(shù)與 undefined 進(jìn)行比較。
還有一種錯(cuò)誤是,只針對(duì)某一特性進(jìn)行檢測(cè):
function reverseSort(values){ if (typeof values.sort == "function"){ values.sort(); values.reverse(); } }
上面的函數(shù),如果傳入帶有 sort()
方法的對(duì)象,就會(huì)通過(guò)檢測(cè),但會(huì)在調(diào)用 reverse()
方法時(shí)報(bào)錯(cuò)!所以這里最好是使用 instanceof 來(lái)檢測(cè):
function reverseSort(values){ if (values instanceof Array){ values.sort(); values.reverse(); } }
總的來(lái)說(shuō),基本類型的值使用 typeof
檢測(cè),而對(duì)象的值使用 instanceof
來(lái)檢測(cè)。特別是面向公眾的 API,一定要執(zhí)行類型檢查,以確保函數(shù)始終能夠正常執(zhí)行。
4.3 通信錯(cuò)誤
JavaScript 與服務(wù)器之間的任何一次通信,就有可能會(huì)產(chǎn)生錯(cuò)誤。
一種通信錯(cuò)誤是發(fā)送了不正確的 URL 格式數(shù)據(jù)。一般是沒(méi)有使用 encodeURIComponent()
對(duì)數(shù)據(jù)進(jìn)行編碼,可以使用這里的函數(shù)來(lái)處理查詢字符串:
/** * 添加查詢字符串 * @param url URL * @param name 參數(shù)名 * @param value 參數(shù)值 * @returns {*} */ function addQueryStringArg(url, name, value) { if (url.indexOf("?") == -1) { url += "?"; } else { url += "&"; } url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url; }
盡量使用這個(gè)函數(shù),就可以確保編碼正確。
5 區(qū)分致命錯(cuò)誤與非致命錯(cuò)誤
非致命錯(cuò)誤可以根據(jù)以下列出的一個(gè)或多個(gè)條件來(lái)確定:
- 不影響用戶的主要任務(wù);
- 只影響頁(yè)面的一部分;
- 可以恢復(fù);
- 重復(fù)操作可以消除錯(cuò)誤。
而致命錯(cuò)誤也可以根據(jù)以下列出的一個(gè)或多個(gè)條件來(lái)確定:
- 無(wú)法繼續(xù)執(zhí)行;
- 影響到了用戶的主要操作;
- 導(dǎo)致其他連帶的錯(cuò)誤。
如果發(fā)生了致命錯(cuò)誤,要立即發(fā)送消息通知用戶,告訴他們無(wú)法再繼續(xù)操作咯。如果必須刷新頁(yè)面才會(huì)恢復(fù),也必須通知用戶,并提供了可刷新頁(yè)面的按鈕。
比如,在大型網(wǎng)站中,可能有多個(gè)互不依賴的模塊,它們是類似這樣初始化的:
for (var i=0, len=mods.length; i
這樣做的問(wèn)題是,如果有一個(gè)模塊發(fā)生錯(cuò)誤,那么就會(huì)導(dǎo)致后續(xù)的其它模塊無(wú)法被初始化,從而導(dǎo)致致命的錯(cuò)誤!我們這樣改造下,讓致命的錯(cuò)誤變成非致命的錯(cuò)誤:
for (var i=0, len=mods.length; i
6 把錯(cuò)誤記錄到服務(wù)器
建議集中保存錯(cuò)誤日志,這樣可以方便后續(xù)查找錯(cuò)誤的原因。所以我們可以把 JavaScript 錯(cuò)誤發(fā)送給服務(wù)器,讓服務(wù)器保存起來(lái)。這樣把前后端的錯(cuò)誤集中起來(lái)管理,就可以很方便地對(duì)數(shù)據(jù)進(jìn)行分析咯O(∩_∩)O~
首先先在服務(wù)器上創(chuàng)建一個(gè)接口,用于接收頁(yè)面發(fā)送的錯(cuò)誤數(shù)據(jù):
/** * 記錄 JavaScript 錯(cuò)誤 * @param sev 嚴(yán)重程度,比如:nonfatal * @param msg 錯(cuò)誤消息 */ function logError(sev,msg){ var img=new Image(); img.src="log.action?sev="+encodeURIComponent(sev)+"&msg="+encodeURIComponent(msg); }
使用 Image 對(duì)象來(lái)發(fā)送請(qǐng)求,有這些好處:
- 所有的瀏覽器都支持 Image 對(duì)象,包含那些不支持 XMLHttpRequest 對(duì)象的瀏覽器。
- 可以避免跨域限制。比如可以使用一臺(tái)日志服務(wù)器專門接收多臺(tái) web 服務(wù)器拋出的錯(cuò)誤。
只要是使用了 try-catch 語(yǔ)句,就要把錯(cuò)誤記錄到日志中:
for (var i=0, len=mods.length; i
第二個(gè)參數(shù)是上下文信息以及 JavaScript 的錯(cuò)誤消息,帶上上下文信息可以方便分析導(dǎo)致錯(cuò)誤的真正原因。
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《JavaScript錯(cuò)誤與調(diào)試技巧總結(jié)》、《JavaScript傳值操作技巧總結(jié)》、《javascript編碼操作技巧總結(jié)》、《JavaScript中json操作技巧總結(jié)》、《JavaScript切換特效與技巧總結(jié)》、《JavaScript查找算法技巧總結(jié)》、《JavaScript動(dòng)畫特效與技巧匯總》、《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》及《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》
希望本文所述對(duì)大家JavaScript程序設(shè)計(jì)有所幫助。
當(dāng)前文章:JavaScript錯(cuò)誤處理操作實(shí)例詳解
瀏覽地址:http://www.dlmjj.cn/article/ihdioe.html