學(xué)習(xí)要點:
1.瀏覽器錯誤報告
2.錯誤處理
3.錯誤事件
4.錯誤處理策略
5.調(diào)試技術(shù)
6.調(diào)試工具
JavaScript 在錯誤處理調(diào)試上一直是它的軟肋数冬,如果腳本出錯堡妒,給出的提示經(jīng)常也讓人
摸不著頭腦。ECMAScript 第 3 版為了解決這個問題引入了 try...catch 和 throw 語句以及一些
錯誤類型按脚,讓開發(fā)人員更加適時的處理錯誤于毙。
一.瀏覽器錯誤報告
隨著瀏覽器的不斷升級,JavaScript 代碼的調(diào)試能力也逐漸變強(qiáng)辅搬。IE唯沮、Firefox脖旱、Safari、
Chrome 和 Opera 等瀏覽器介蛉,都具備報告 JavaScript 錯誤的機(jī)制萌庆。只不過,瀏覽器一般面向
的是普通用戶币旧,默認(rèn)情況下會隱藏此類信息践险。
IE:在默認(rèn)情況下,左下角會出現(xiàn)錯誤報告吹菱,雙擊這個圖標(biāo)巍虫,可以看到錯誤消息對話框。
如果開啟禁止腳本調(diào)試鳍刷,那么出錯的時候占遥,會彈出錯誤調(diào)試框。設(shè)置方法為:工具->Internet
Options 選項->高級->禁用腳本調(diào)試倾剿,取消勾選即可筷频。
Firefox:在默認(rèn)情況下,錯誤不會通過瀏覽器給出提示前痘。但在后臺的錯誤控制臺可以查
看凛捏。查看方法為:工具->[Web 開發(fā)者]->Web 控制臺|錯誤控制臺。除了瀏覽器自帶的芹缔,開發(fā)
人員為 Firefox 提供了一個強(qiáng)大的插件:Firebug坯癣。它不但可以提示錯誤,還可以調(diào)試 JavaScript
和 CSS最欠、DOM示罗、網(wǎng)絡(luò)鏈接錯誤等。
Safari:在默認(rèn)情況下芝硬,錯誤不會通過瀏覽器給出提示蚜点。所以,我們需要開啟它拌阴。查看
方法為:顯示菜單欄->編輯->偏好設(shè)置->高級->在菜單欄中顯示開發(fā)->顯示 Web 檢查器|顯示
錯誤控制器绍绘。
Opera:在默認(rèn)情況下,錯誤會被隱藏起來迟赃。打開錯誤記錄的方式為:顯示菜單欄->查
看->開發(fā)者工具->錯誤控制臺陪拘。
Chrome:在默認(rèn)情況下,錯誤會被隱藏起來纤壁。打開錯誤記錄的方法為:工具->JavaScript
控制臺左刽。
二.錯誤處理
良好的錯誤處理機(jī)制可以及時的提醒用戶,知道發(fā)生了什么事酌媒,而不會驚慌失措欠痴。為此迄靠,
作為開發(fā)人員,我們必須理解在處理 JavaScript 錯誤的時候斋否,都有哪些手段和工具可以利用梨水。
try-catch 語句
ECMA262 第 3 版引入了 try-catch 語句,作為 JavaScript 中處理異常的一種標(biāo)準(zhǔn)方式茵臭。
try { //嘗試著執(zhí)行 try 包含的代碼
window.abcdefg(); //不存在的方法
} catch (e) { //如果有錯誤疫诽,執(zhí)行 catch,e 是異常對象
alert('發(fā)生錯誤啦旦委,錯誤信息為:' + e); //直接打印調(diào)用 toString()方法
}
在 e 對象中奇徒,ECMA-262 還規(guī)定了兩個屬性:message 和 name,分別打印出信息和名稱缨硝。
alert('錯誤名稱:' + e.name);
alert('錯誤名稱:' + e.message);
PS:Opera9 之前的版本不支持這個屬性摩钙。并且 IE 提供了和 message 完全相同的
description 屬性、還添加了 number 屬性提示內(nèi)部錯誤數(shù)量查辩。Firefox 提供了 fileName(文件名)胖笛、
lineNumber(錯誤行號)和 stack(棧跟蹤信息)。Safari 添加了 line(行號)宜岛、sourceId(內(nèi)部錯誤代
碼)和 sourceURL(內(nèi)部錯誤 URL)长踊。所以,要跨瀏覽器使用萍倡,那么最好只使用通用的 message身弊。
finally 子句
finally 語句作為 try-catch 的可選語句,不管是否發(fā)生異常處理列敲,都會執(zhí)行阱佛。并且不管 try
或是 catch 里包含 return 語句,也不會阻止 finally 執(zhí)行戴而。
try {
window.abcdefg();
} catch (e) {
alert('發(fā)生錯誤啦凑术,錯誤信息為:' + e.stack);
} finally { //總是會被執(zhí)行
alert('我都會執(zhí)行!');
}
PS:finally 的作用一般是為了防止出現(xiàn)異常后所意,無法往下再執(zhí)行的備用淮逊。也就是說,如
果有一些清理操作扁眯,那么出現(xiàn)異常后,就執(zhí)行不到清理操作翅帜,那么可以把這些清理操作放到
finally 里即可姻檀。
錯誤類型
執(zhí)行代碼時可能會發(fā)生的錯誤有很多種。每種錯誤都有對應(yīng)的錯誤類型涝滴,ECMA-262
定義了 7 種錯誤類型:
1.Error
2.EvalError
3.RangeError
4.ReferenceError
5.SyntaxError
6.TypeError
7.URIError
其中绣版,Error 是基類型(其他六種類型的父類型)胶台,其他類型繼承自它。Error 類型很少見杂抽,
一般由瀏覽器拋出的诈唬。這個基類型主要用于開發(fā)人員拋出自定義錯誤。
PS:拋出的意思缩麸,就是當(dāng)前錯誤無法處理铸磅,丟給另外一個人,比如丟給一個錯誤對象杭朱。
new Array(-5); //拋出 RangeError(范圍)
錯誤信息為:RangeError: invalid array length(無效的數(shù)組的長度)
PS:RangeError 錯誤一般在數(shù)值超出相應(yīng)范圍時觸發(fā)
var box = a; //拋出 ReferenceError(引用)
錯誤信息為:ReferenceError: a is not defined(a 是沒有定義的)
PS:ReferenceError 通常訪問不存在的變量產(chǎn)生這種錯誤
a $ b; //拋出 SyntaxError(語法)
錯誤信息為:SyntaxError: missing ; before statement(失蹤;語句之前)
PS:SyntaxError 通常是語法錯誤導(dǎo)致的
new 10; //拋出 TypeError(類型 )
錯誤信息為:TypeError: 10 is not a constructor(10 不是一個構(gòu)造函數(shù))
PS:TypeError 通常是類型不匹配導(dǎo)致的
PS:EvalError 類型表示全局函數(shù) eval()的使用方式與定義的不同時拋出阅仔,但實際上并不
能產(chǎn)生這個錯誤,所以實際上碰到的可能性不大弧械。
PS:在使用 encodeURI()和 decodeURI()時八酒,如果 URI 格式不正確時,會導(dǎo)致 URIError
錯誤刃唐。但因為 URI 的兼容性非常強(qiáng)羞迷,導(dǎo)致這種錯誤幾乎見不到。
alert(encodeURI('李炎恢'));
利用不同的錯誤類型画饥,可以更加恰當(dāng)?shù)慕o出錯誤信息或處理衔瓮。
try {
new 10;
} catch (e) {
if (e instanceof TypeError) { //如果是類型錯誤,那就執(zhí)行這里
alert('發(fā)生了類型錯誤荒澡,錯誤信息為:' + e.message);
} else {
alert('發(fā)生了未知錯誤报辱!');
}
}
善用 try-catch
在明明知道某個地方會產(chǎn)生錯誤,可以通過修改代碼來解決的地方单山,是不適合用
try-catch 的碍现。或者是那種不同瀏覽器兼容性錯誤導(dǎo)致錯誤的也不太適合米奸,因為可以通過判斷
瀏覽器或者判斷這款瀏覽器是否存在此屬性和方法來解決昼接。
try {
var box = document.getElementbyid('box'); //單詞大小寫錯誤,導(dǎo)致類型錯誤
} catch (e) { //這種情況沒必要 try-catch
alert(e);
}
try {
alert(innerWidth); //W3C 支持悴晰,IE 報錯
} catch (e) {
alert(document.documentElement.clientWidth); //兼容 IE
}
PS:常規(guī)錯誤和這種瀏覽器兼容錯誤慢睡,我們都不建議使用 try-catch。因為常規(guī)錯誤可以
修改代碼即可解決铡溪,瀏覽器兼容錯誤漂辐,可以通過普通 if 判斷即可。并且 try-catch 比一般語
句消耗資源更多棕硫,負(fù)擔(dān)更大髓涯。所以,在萬不得已哈扮,無法修改代碼纬纪,不能通過普通判斷的情況
下才去使用 try-catch蚓再,比如后面的 Ajax 技術(shù)。
拋出錯誤
使用 catch 來處理錯誤信息包各,如果處理不了摘仅,我們就把它拋出丟掉。拋出錯誤问畅,其實就
是在瀏覽器顯示一個錯誤信息娃属,只不過,錯誤信息可以自定義按声,更加精確和具體膳犹。
try {
new 10;
} catch (e) {
if (e instanceof TypeError) {
throw new TypeError('實例化的類型導(dǎo)致錯誤!'); //直接中文解釋錯誤信息
} else {
throw new Error('拋出未知錯誤签则!');
}
}
PS:IE 瀏覽器只支持 Error 拋出的錯誤须床,其他錯誤類型不支持。
三.錯誤事件
error 事件是當(dāng)某個 DOM 對象產(chǎn)生錯誤的時候觸發(fā)渐裂。
addEvent(window, 'error', function () {
alert('發(fā)生錯誤啦豺旬!')
});
new 10; //寫在后面
<img src="123.jpg" onerror="alert('圖像加載錯誤!')" />
四.錯誤處理策略
由于 JavaScript 錯誤都可能導(dǎo)致網(wǎng)頁無法使用,所以何時搞清楚及為什么發(fā)生錯誤至關(guān)
重要柒凉。這樣族阅,我們才能對此采取正確的應(yīng)對方案。
常見的錯誤類型
因為 JavaScript 是松散弱類型語言膝捞,很多錯誤的產(chǎn)生是在運(yùn)行期間的坦刀。一般來說,需要
關(guān)注 3 種錯誤:
1.類型轉(zhuǎn)換錯誤蔬咬;2.數(shù)據(jù)類型錯誤鲤遥;3.通信錯誤,這三種錯誤一般會在特定的模式下或
者沒有對值進(jìn)行充分檢查的情況下發(fā)生林艘。
類型轉(zhuǎn)換錯誤
在一些判斷比較的時候盖奈,比如數(shù)組比較,有相等和全等兩種:
alert(1 == '1'); //true
alert(1 === '1'); //false
alert(1 == true); //true
alert(1 === true); //false
PS:由于這個特性狐援,我們建議在這種會類型轉(zhuǎn)換的判斷钢坦,強(qiáng)烈推薦使用全等,以保證
判斷的正確性啥酱。
var box = 10; //可以試試 0
if (box) { //10 自動轉(zhuǎn)換為布爾值為 true
alert(box);
}
PS:因為 0 會自動轉(zhuǎn)換為 false爹凹,其實 0 也是數(shù)值,也是有值的镶殷,不應(yīng)該認(rèn)為是 false禾酱,
所以我們要判斷 box 是不是數(shù)值再去打印。
var box = 0;
if (typeof box == 'number') { //判斷 box 是 number 類型即可
alert(box);
}
PS:typeof box == 'number'這里也是用的相等,沒有用全等呀宇植?原因是 typeof box 本身
返回的就是類型的字符串,右邊也是字符串埋心,那沒必要驗證類型指郁,所以相等就夠了。
數(shù)據(jù)類型錯誤
由于 JavaScript 是弱類型語言拷呆,在使用變量和傳遞參數(shù)之前闲坎,不會對它們進(jìn)行比較來確
保數(shù)據(jù)類型的正確。所以茬斧,這樣開發(fā)人員必須需要靠自己去檢測腰懂。
function getQueryString(url) { //傳遞了非字符串,導(dǎo)致錯誤
var pos = url.indexOf('?');
return pos;
}
alert(getQueryString(1));
PS:為了避免這種錯誤的出現(xiàn)项秉,我們應(yīng)該使用類型比較绣溜。
function getQueryString(url) {
if (typeof url == 'string') { //判斷了指定類型,就不會出錯了
var pos = url.indexOf('?');
return pos;
}
}
alert(getQueryString(1));
對于傳遞參數(shù)除了限制數(shù)字娄蔼、字符串之外怖喻,我們對數(shù)組也要進(jìn)行限制。
function sortArray(arr) {
if (arr) { //只判斷布爾值遠(yuǎn)遠(yuǎn)不夠
alert(arr.sort());
}
}
var box = [3,5,1];
sortArray(box);
PS:只用 if (arr)判斷布爾值岁诉,那么數(shù)值锚沸、字符串、對象等都會自動轉(zhuǎn)換為 true涕癣,而這些
類型調(diào)用 sort()方法比如會產(chǎn)生錯誤哗蜈,這里提一下:空數(shù)組會自動轉(zhuǎn)換為 true 而非 false。
function sortArray(arr) {
if (typeof arr.sort == 'function') { //判斷傳遞過來 arr 是否有 sort 方法
alert(arr.sort()); //就算這個繞過去了
alert(arr.reverse()); //這個就又繞不過去了
}
}
var box = { //創(chuàng)建一個自定義對象坠韩,添加 sort 方法
sort : function () {}
};
sortArray(box);
PS:這斷代碼本意是判斷 arr 是否有 sort 方法距潘,因為只有數(shù)組有 sort 方法,從而判斷 arr
是數(shù)組同眯。但忘記了绽昼,自定義對象添加了 sort 方法就可以繞過這個判斷,且 arr 還不是數(shù)組须蜗。
function sortArray(arr) {
if (arr instanceof Array) { //使用 instanceof 判斷是 Array 最為合適
alert(arr.sort());
}
}
var box = [3,5,1];
sortArray(box);
通信錯誤
在使用 url 進(jìn)行參數(shù)傳遞時硅确,經(jīng)常會傳遞一些中文名的參數(shù)或 URL 地址,在后臺處理
時會發(fā)生轉(zhuǎn)換亂碼或錯誤明肮,因為不同的瀏覽器對傳遞的參數(shù)解釋是不同的菱农,所以有必要使用
編碼進(jìn)行統(tǒng)一傳遞。
比如:?user=李炎恢&age=100
var url = '?user=' + encodeURIComponent('李炎恢') + '&age=100'; //編碼
PS:在 AJAX 章節(jié)中我們會繼續(xù)探討通信錯誤和編碼問題柿估。
五.調(diào)試技術(shù)
在 JavaScript 初期循未,瀏覽器并沒有針對 JavaScript 提供調(diào)試工具,所以開發(fā)人員就想出
了一套自己的調(diào)試方法,比如 alert()的妖。這個方法可以打印你懷疑的是否得到相應(yīng)的值绣檬,或者
放在程序的某處來看看是否能執(zhí)行,得知之前的代碼無誤嫂粟。
var num1 = 1;
var num2 = b; //在這段前后加上 alert('')調(diào)試錯誤
var result = num1 + num2;
alert(result);
PS:使用 alert('')來調(diào)試錯誤比較麻煩娇未,重要裁剪和粘貼 alert(''),如果遺忘掉沒有刪掉
用于調(diào)試的 alert('')將特別頭疼星虹。所以零抬,我們現(xiàn)在需要更好的調(diào)試方法。
將消息記錄到控制臺
IE8宽涌、Firefox平夜、Opera、Chrome 和 Safari 都有 JavaScript 控制臺卸亮,可以用來查看 JavaScript
錯誤忽妒。對于 Firefox,需要安裝 Firebug兼贸,其他瀏覽器直接使用 console 對象寫入消息即可锰扶。
console.error('錯誤!'); //紅色帶叉
console.info('信息寝受!'); //白色帶信息號
console.log('日志坷牛!'); //白色
console.warn('警告!'); //黃色帶感嘆號
PS:這里以 Firefox 為標(biāo)準(zhǔn)很澄,其他瀏覽器會稍有差異京闰。
var num1 = 1;
console.log(typeof num1); //得到 num1 的類型
var num2 = 'b';
console.log(typeof num2); //得到 num2 的類型
var result = num1 + num2;
alert(result); //結(jié)果是 1b,匪夷所思
PS:我們誤把 num2 賦值成字符串了甩苛,其實應(yīng)該是數(shù)值蹂楣,導(dǎo)致最后的結(jié)果是 1b。那么
傳統(tǒng)調(diào)試就必須使用 alert(typeo num1)來看看是不是數(shù)值類型讯蒲,比較麻煩痊土,因為 alert()會阻
斷后面的執(zhí)行,看過之后還要刪墨林,刪完估計一會兒又忘了赁酝,然后又要 alert(typeof num1)來加
深印象。如果用了 console.log 的話旭等,所有要調(diào)試的變量一目了然酌呆,也不需要刪除,放著也
沒事搔耕。
將錯誤拋出
之前已經(jīng)將結(jié)果錯誤的拋出隙袁,這里不在贅述。
if (typeof num2 != 'number') throw new Error('變量必須是數(shù)值!');
六.調(diào)試工具
IE8菩收、Firefox梨睁、Chrome、Opera娜饵、Safari 都自帶了自己的調(diào)試工具而姐,而開發(fā)人員只習(xí)慣了
Firefox 一種,所以很多情況下划咐,在 Firefox 開發(fā)調(diào)試,然后去其他瀏覽器做兼容钧萍。其實 Firebug
工具提供了一種 Web 版的調(diào)試工具:Firebug lite褐缠。
以下是網(wǎng)頁版直接調(diào)用調(diào)試工具的代碼:直接復(fù)制到瀏覽器網(wǎng)址即可。
javascript:(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&&F.doc
umentElement.namespaceURI;E=E?F[i+'NS'](E,'script'):F[i]('script');E[r]('id',b);E[r]('src',I+g+T);
E[r](b,u);(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);E=new%20Image;E[r]('src',I+L);})(doc
ument,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','rele
ases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');
還有一種離線版风瘦,把 firebug-lite 下載好队魏,載入工具即可,導(dǎo)致最終工具無法運(yùn)行万搔,其他
瀏覽器運(yùn)行完好胡桨。雖然 Web 版本的 Firebug Lite 可以跨瀏覽器使用 Firebug,但除了 Firefox
原生的之外瞬雹,都不支持?jǐn)帱c昧谊、單步調(diào)試、監(jiān)視酗捌、控制臺等功能呢诬。好在,其他瀏覽器自己的調(diào)
試器都有胖缤。
PS:Chrome 瀏覽器必須在服務(wù)器端方可有效尚镰。測試也發(fā)現(xiàn),只能簡單調(diào)試哪廓,如果遇到
錯誤狗唉,系統(tǒng)不能自動拋出錯誤給 firebug-lite。
1.設(shè)置斷點
我們可以選擇 Script(腳本)涡真,點擊要設(shè)置斷點的 JS 腳本處分俯,即可設(shè)置斷點。當(dāng)我們需要
調(diào)試的時候哆料,從斷點初開始模擬運(yùn)行澳迫,發(fā)現(xiàn)代碼執(zhí)行的流程和變化。
2.單步調(diào)試
設(shè)置完斷點后剧劝,可以點擊單步調(diào)試橄登,一步步看代碼執(zhí)行的步驟和流程。上面有五個按鈕:
重新運(yùn)行:重新單步調(diào)試
斷繼:正常執(zhí)行代碼
單步進(jìn)入:一步一步執(zhí)行流程
單步跳過:跳到下一個函數(shù)塊
單步退出:跳出執(zhí)行到內(nèi)部的函數(shù)
3.監(jiān)控
單擊“監(jiān)控”選項卡上,可以查看在單步進(jìn)入是拢锹,所有變量值的變化谣妻。你也可以新建監(jiān)
控表達(dá)式來重點查看自己所關(guān)心的變量。
4.控制臺
顯示各種信息卒稳。之前已了解過蹋半。
PS:其他瀏覽器除 IE8 以上均可實現(xiàn)以上的調(diào)試功能,大家可以自己常識下充坑。而我們
主要采用 Firebug 進(jìn)行調(diào)試然后兼容到其他瀏覽器的做法以提高開發(fā)效率减江。