背景:JavaScript在錯誤處理調試上一直是它的軟肋,如果腳本出錯,給出的提示經常也讓人摸不著頭腦。ECMAScript第3版為了解決這個問題引入了 try...catch和 throw語句以及一些錯誤類型,讓開發人員更加適時的處理錯誤。良好的錯誤處理機制可以及時的提醒用戶,知道發生了什么事,而不會驚慌失措。為此,作為開發人員,我們必須理解在處理 JavaScript錯誤的時候,都有哪些手段和工具可以利用。
### 一、錯誤處理
1、try...catch語句
~~~
try{ //嘗試著執行try包含的代碼
<span style="white-space:pre"> </span>window.abcdefg(); //不存在的方法
}catch(e){ //如果有錯誤, 執行catch, e是異常對象
alert('發生錯誤啦,錯誤信息為: '+e); //直接打印調用toString()方法
}
~~~

e對象中, ECMA-262還規定了兩個屬性: message和name,分別打印出信息和名稱。
~~~
try{ //嘗試著執行try包含的代碼
window.abcdefg(); //不存在的方法
}catch(e){ //如果有錯誤, 執行catch, e是異常對象
alert('錯誤名稱: '+e.name); //錯誤名稱
alert('錯誤信息: '+e.message); //錯誤信息
}
~~~


PS:Opera9之前的版本不支持這個屬性。并且IE提供了和message完全相同的description屬性、還添加了number屬性提示內部錯誤數量。Firefox提供了fileName(文件名)、lineNumber(錯誤行號)和stack(棧跟蹤信息)。 Safari添加了line(行號)、sourceId(內部錯誤代碼)和sourceURL(內部錯誤URL)。所以, 要跨瀏覽器使用,那么最好只使用通用的message。
2、finally子句
finally語句作為try-catch的可選語句,不管是否發生異常處理, 都會執行。并且不管try或是catch里包含return語句,也不會阻止finally執行。
~~~
try{
window.abcdefg();
}catch(e){
alert('發生錯誤啦,錯誤信息為: '+e.stack);
}finally{ //總是會被執行
alert('我都會執行! ');
}
~~~


PS:finally的作用一般是為了防止出現異常后,無法往下再執行的備用。也就是說,如果有一些清理操作, 那么出現異常后,就執行不到清理操作, 那么可以把這些清理操作放到finally里即可。
### 二、錯誤顯示類型
執行代碼時可能會發生的錯誤有很多種。每種錯誤都有對應的錯誤類型, ECMA-262定義了7種錯誤類型:
1)Error
2)valError
3)RangeError(范圍)
~~~
try{
<span style="white-space:pre"> </span>new Array(-5);
}catch(e){
<span style="white-space:pre"> </span>alert('發生錯誤啦,錯誤信息為: '+e);
}
~~~

4)ReferenceError(引用)
~~~
try{
var box = a;
}catch(e){
alert('發生錯誤啦,錯誤信息為: '+e);
}
~~~

5)SyntaxError(語法)
~~~
try{
a$b;
}catch(e){
alert('發生錯誤啦,錯誤信息為: '+e);
}
~~~

a$ b; //拋出 SyntaxError(語法)
錯誤信息為: SyntaxError: missing ; beforestatement(失蹤;語句之前)
PS: SyntaxError通常是語法錯誤導致的。
注意:視頻中的實例在我的火狐瀏覽器和IE瀏覽器中顯示是上圖的引用錯誤。這個有待研究一下……
6)TypeError(類型)
~~~
try{
new 10;
}catch(e){
alert('發生錯誤啦,錯誤信息為: '+e);
}
~~~

7)URIError
PS:Error是基類型(其他六種類型的父類型), 其他類型繼承自它。 Error類型很少見,一般由瀏覽器拋出的。這個基類型主要用于開發人員拋出自定義錯誤。
PS: TypeError通常是類型不匹配導致的。
PS: EvalError類型表示全局函數 eval()的使用方式與定義的不同時拋出, 但實際上并不能產生這個錯誤,所以實際上碰到的可能性不大。
PS:在使用 encodeURI()和 decodeURI()時,如果 URI格式不正確時,會導致 URIError錯誤。但因為 URI的兼容性非常強,導致這種錯誤幾乎見不到。
### 三、錯誤事件
error事件是當某個DOM對象產生錯誤的時候觸發。
demo.html:
~~~
<img src="123.jpg"onerror="alert('圖像加載錯誤! ')"/>
~~~
demo.js
~~~
addEvent(window,'error', function(){
alert('發生錯誤啦! ')
});
~~~

### 四.錯誤處理策略
因為JavaScript是松散弱類型語言,很多錯誤的產生是在運行期間的。一般來說,需要關注3種錯誤:
1.類型轉換錯誤
在一些判斷比較的時候,比如數組比較,有相等和全等兩種:
~~~
alert(1 == '1'); //true
alert(1 === '1'); //false
alert(1 == true); //true
alert(1 === true); //false
~~~
PS:由于這個特性,我們建議在這種會類型轉換的判斷,強烈推薦使用全等,以保證判斷的正確性。
~~~
var box = 10; //可以試試 0
if (box) { //10自動轉換為布爾值為 true
<span style="white-space:pre"> </span>alert(box);
}
~~~
PS:因為 0會自動轉換為 false,其實 0也是數值,也是有值的,不應該認為是 false,所以我們要判斷 box是不是數值再去打印。
~~~
var box = 0;
if (typeof box == 'number') { //判斷 box是 number類型即可
alert(box);
}
~~~
PS: typeof box == 'number'這里也是用的相等,沒有用全等呀?原因是 typeof box本身返回的就是類型的字符串,右邊也是字符串,那沒必要驗證類型,所以相等就夠了。
2.數據類型錯誤
由于 JavaScript是弱類型語言,在使用變量和傳遞參數之前,不會對它們進行比較來確保數據類型的正確。所以,這樣開發人員必須需要靠自己去檢測。
~~~
function getQueryString(url) { //傳遞了非字符串,導致錯誤
<span style="white-space:pre"> </span>var pos = url.indexOf('?');
<span style="white-space:pre"> </span>return pos;
}
alert(getQueryString(1));
~~~
PS:為了避免這種錯誤的出現,我們應該使用類型比較。
~~~
function getQueryString(url) {
<span style="white-space:pre"> </span>if (typeof url == 'string') { //判斷了指定類型,就不會出錯了
<span style="white-space:pre"> </span>var pos = url.indexOf('?');
<span style="white-space:pre"> </span>return pos;
<span style="white-space:pre"> </span>}
}
alert(getQueryString(1));
~~~
PS:對于傳遞參數除了限制數字、字符串之外,我們對數組也要進行限制。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (arr) { //只判斷布爾值遠遠不夠
<span style="white-space:pre"> </span>alert(arr.sort());
<span style="white-space:pre"> </span>}
}
var box = [3,5,1];
sortArray(box);
~~~
PS: 只用 if (arr)判斷布爾值,那么數值、字符串、對象等都會自動轉換為 true,而這些類型調用 sort()方法比如會產生錯誤,這里提一下:空數組會自動轉換為 true而非 false。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (typeof arr.sort == 'function') { //判斷傳遞過來 arr是否有 sort方法
<span style="white-space:pre"> </span>alert(arr.sort()); //就算這個繞過去了
<span style="white-space:pre"> </span>alert(arr.reverse()); //這個就又繞不過去了
<span style="white-space:pre"> </span>}
}
var box = { //創建一個自定義對象,添加 sort方法
<span style="white-space:pre"> </span>sort : function () {}
};
sortArray(box);
~~~
PS: 這斷代碼本意是判斷 arr是否有 sort方法, 因為只有數組有 sort方法, 從而判斷arr是數組。但忘記了,自定義對象添加了 sort方法就可以繞過這個判斷,且 arr還不是數組。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (arr instanceofArray) { //使用 instanceof判斷是 Array最為合適
<span style="white-space:pre"> </span>alert(arr.sort());
<span style="white-space:pre"> </span>}
}
var box = [3,5,1];
sortArray(box);
~~~
3.通信錯誤
在使用 url進行參數傳遞時,經常會傳遞一些中文名的參數或 URL地址,在后臺處理時會發生轉換亂碼或錯誤,因為不同的瀏覽器對傳遞的參數解釋是不同的,所以有必要使用編碼進行統一傳遞。
比如:??user=李炎恢&age=100
~~~
var url = '?user=' + encodeURIComponent('李炎恢') + '&age=100'; //編碼
~~~
這三種錯誤一般會在特定的模式下或者沒有對值進行充分檢查的情況下發生。
### 五、調試技術
1、設置斷點
我們可以選擇Script(腳本), 點擊要設置斷點的JS腳本處, 即可設置斷點。 當我們需要調試的時候,從斷點初開始模擬運行,發現代碼執行的流程和變化。
2、單步調試
設置完斷點后,可以點擊單步調試,一步步看代碼執行的步驟和流程。上面有五個按鈕:
重新運行:重新單步調試
斷繼:正常執行代碼
單步進入:一步一步執行流程
單步跳過:跳到下一個函數塊
單步退出:跳出執行到內部的函數**
3、監控
單擊“ 監控”選項卡上, 可以查看在單步進入是, 所有變量值的變化。 你也可以新建監控表達式來重點查看自己所關心的變量。
4、控制臺
顯示各種信息。
### 六、學習心得
1、錯誤處理在軟件開發中占著重要的地位,合理的處理錯誤,顯示人性化的界面,為用戶著想。
2、條條大路通羅馬,不同的調試方法,相同的調試結果,換個角度,看到的更多。
3、將錯誤拋出來的同時記得處理,一直拋不處理也是不正確的做法。**