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