JavaScript錯誤處理與調試javascript
學習要點:java
1.瀏覽器錯誤報告數組
2.錯誤處理瀏覽器
3.錯誤事件服務器
4.錯誤處理策略網絡
5.調試技術app
6.調試工具函數
JavaScript在錯誤處理調試上一直是它的軟肋,若是腳本出錯,給出的提示常常也讓人摸不着頭腦。ECMAScript第3版爲了解決這個問題引入了try...catch和throw語句以及一些錯誤類型,讓開發人員更加適時的處理錯誤。工具
一.瀏覽器錯誤報告學習
隨着瀏覽器的不斷升級,JavaScript代碼的調試能力也逐漸變強。IE、Firefox、Safari、Chrome和Opera等瀏覽器,都具有報告JavaScript錯誤的機制。只不過,瀏覽器通常面向的是普通用戶,默認狀況下會隱藏此類信息。
IE:在默認狀況下,左下角會出現錯誤報告,雙擊這個圖標,能夠看到錯誤消息對話框。若是開啓禁止腳本調試,那麼出錯的時候,會彈出錯誤調試框。設置方法爲:工具->Internet Options選項->高級->禁用腳本調試,取消勾選便可。
Firefox:在默認狀況下,錯誤不會經過瀏覽器給出提示。但在後臺的錯誤控制檯能夠查看。查看方法爲:工具->[Web開發者]->Web控制檯|錯誤控制檯。除了瀏覽器自帶的,開發人員爲Firefox提供了一個強大的插件:Firebug。它不但能夠提示錯誤,還能夠調試JavaScript和CSS、DOM、網絡連接錯誤等。
Safari:在默認狀況下,錯誤不會經過瀏覽器給出提示。因此,咱們須要開啓它。查看方法爲:顯示菜單欄->編輯->偏好設置->高級->在菜單欄中顯示開發->顯示Web檢查器|顯示錯誤控制器。
Opera:在默認狀況下,錯誤會被隱藏起來。打開錯誤記錄的方式爲:顯示菜單欄->查看->開發者工具->錯誤控制檯。
Chrome:在默認狀況下,錯誤會被隱藏起來。打開錯誤記錄的方法爲:工具->JavaScript控制檯。
二.錯誤處理
良好的錯誤處理機制能夠及時的提醒用戶,知道發生了什麼事,而不會惶恐不安。爲此,做爲開發人員,咱們必須理解在處理JavaScript錯誤的時候,都有哪些手段和工具能夠利用。
try-catch語句
ECMA262第3版引入了try-catch語句,做爲JavaScript中處理異常的一種標準方式。
try嘗試着執行try包含的代碼
catch若是有錯誤,執行catch,能夠接收一個參數e,e是異常對象包含異常錯誤信息
try { //嘗試着執行try包含的代碼 window.abcdefg(); //不存在的方法 } catch (e) { //若是有錯誤,執行catch,e是異常對象 alert('發生錯誤啦,錯誤信息爲:' + e); //直接打印調用toString()方法 }
ps:嘗試執行try裏面的代碼,若是出現錯誤,就執行catch裏面的代碼,catch()接收一個參數e裏面包含錯誤信息
try-catch特色
1.能夠獲取錯誤信息
2.能夠避免瀏覽器控制檯報錯
3.能夠屏蔽錯誤,繼續執行,可是繼續執行的語句若是和錯誤的語句有上下文關聯,那麼下面可能會繼續出錯
catch(e)接收的e錯誤信息對象裏,有兩個屬性message和name,分別打印出信息和名稱。
message錯誤信息,【推薦使用】通常使用這個就夠了,並且跨瀏覽器支持
name錯誤名稱,IE9如下不支持name屬性
使用方式:
catch(e)接收的e錯誤信息對象裏.message
catch(e)接收的e錯誤信息對象裏.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。
finally子句
finally語句做爲try-catch的可選語句,無論是否發生異常處理,都會執行。而且無論try或是catch裏包含return語句,也不會阻止finally執行。
try { //嘗試執行裏面的代碼 window.abcdefg(); } catch (e) { //若是發生錯誤就執行裏面的代碼 alert('發生錯誤啦,錯誤信息爲:' + e); } finally { //無論是否發生錯誤都執行裏面代碼 alert('我都會執行!'); }
PS:finally的做用通常是爲了防止出現異常後,沒法往下再執行的備用。也就是說,若是有一些清理操做,那麼出現異常後,就執行不到清理操做,那麼能夠把這些清理操做放到finally裏便可。
錯誤類型
執行代碼時可能會發生的錯誤有不少種。每種錯誤都有對應的錯誤類型,ECMA-262定義了7種錯誤類型:
1.Error
2.EvalError
3.RangeError
4.ReferenceError
5.SyntaxError
6.TypeError
7.URIError
其中,Error是基類型(其餘六種類型的父類型),其餘類型繼承自它。Error類型不多見,通常由瀏覽器拋出的。這個基類型主要用於開發人員拋出自定義錯誤。
PS:拋出的意思,就是當前錯誤沒法處理,丟給另一我的,好比丟給一個錯誤對象。如當代碼出現錯誤時,瀏覽器沒法處理錯誤,就在控制檯拋出一個錯誤信息
RangeError(範圍錯誤)
錯誤信息爲:RangeError: invalid array length(無效的數組的長度)
PS:RangeError錯誤通常在數值超出相應範圍時觸發
new Array(-5); //拋出RangeError(範圍)
ReferenceError(引用錯誤)
錯誤信息爲:ReferenceError: a is not defined(a是沒有定義的)
PS:ReferenceError一般訪問不存在的變量產生這種錯誤
var box = a; //拋出ReferenceError(引用)
SyntaxError(語法錯誤)
錯誤信息爲:SyntaxError: missing ; before statement(失蹤;語句以前)
PS:SyntaxError一般是語法錯誤致使的
a $ b; //拋出SyntaxError(語法)
TypeError(類型錯誤)
錯誤信息爲:TypeError: 10 is not a constructor(10不是一個構造函數)
PS:TypeError一般是類型不匹配致使的
new 10; //拋出TypeError(類型 )
EvalError
PS:EvalError類型表示全局函數eval()的使用方式與定義的不一樣時拋出,但實際上並不能產生這個錯誤,因此實際上碰到的可能性不大。
URIError錯誤。
PS:在使用encodeURI()和decodeURI()時,若是URI格式不正確時,會致使URIError錯誤。但由於URI的兼容性很是強,致使這種錯誤幾乎見不到。
利用不一樣的錯誤類型,能夠更加恰當的給出錯誤信息或處理。
try { new 10; } catch (e) { if (e instanceof TypeError) { //若是是類型錯誤,那就執行這裏 alert('發生了類型錯誤,錯誤信息爲:' + e.message); } else { alert('發生了未知錯誤!'); } }
善用try-catch
在明明知道某個地方會產生錯誤,能夠經過修改代碼來解決的地方,是不適合用try-catch的。或者是那種不一樣瀏覽器兼容性錯誤致使錯誤的也不太適合,由於能夠經過判斷瀏覽器或者判斷這款瀏覽器是否存在此屬性和方法來解決。
try { var box = document.getElementbyid('box'); //單詞大小寫錯誤,致使類型錯誤 } catch (e) { //這種狀況不必try-catch alert(e); }
try { alert(innerWidth); //W3C支持,IE報錯 } catch (e) { alert(document.documentElement.clientWidth); //兼容IE }
以上兩種狀況都不適合用try-catch
PS:常規錯誤和這種瀏覽器兼容錯誤,咱們都不建議使用try-catch。由於常規錯誤能夠修改代碼便可解決,瀏覽器兼容錯誤,能夠經過普通if判斷便可。而且try-catch比通常語句消耗資源更多,負擔更大。因此,在萬不得已,沒法修改代碼,不能經過普通判斷的狀況下才去使用try-catch,好比後面的Ajax技術。
拋出錯誤
使用catch來處理錯誤信息,若是處理不了,咱們就把它拋出丟掉。拋出錯誤,其實就是在瀏覽器顯示一個錯誤信息,只不過,錯誤信息能夠自定義,更加精確和具體。
throw實列化一個錯誤對象,拋出錯誤
try { new 10; } catch (e) { if (e instanceof TypeError) { //判斷若是錯誤類型是TypeError類型 throw new TypeError('實例化的類型致使錯誤!'); //實例化一個TypeError錯誤對象,向瀏覽器拋出錯誤 } else { throw new Error('拋出未知錯誤!'); //不然實例化一個Error錯誤對象,向瀏覽器拋出錯誤 } }
PS:IE瀏覽器只支持Error拋出的錯誤,其餘錯誤類型不支持。
三.錯誤事件
onerror事件是當某個DOM對象產生錯誤的時候觸發。
//添加一個錯誤事件,當發生錯誤時激發函數 addEvent(window, 'error', function () { alert('發生錯誤啦!') }); new 10; //寫在後面,寫在事件前面就執行不到事件了 //跨瀏覽器添加事件,添加事件兼容 function addEvent(obj, type, fn) { //添加事件函數,接收3個參數,1事件對象,2事件名稱,3事件函數 //判斷瀏覽器若是支持w3c if (obj.addEventListener) { //就用w3c的addEventListener方法添加對象,將事件名稱和事件函數傳入添加事件 obj.addEventListener(type, fn, false); } else if (obj.attachEvent) { //判斷若是瀏覽器是IE9如下,就用IE的方法attachEvent添加事件 //將事件名稱和事件函數傳入建立對象 obj.attachEvent('on' + type, fn); } }
在HTML直接使用onerror事件
<img src="123.jpg" onerror="alert('圖像加載錯誤!')" />
四.錯誤處理策略
因爲JavaScript錯誤均可能致使網頁沒法使用,因此什麼時候搞清楚及爲何發生錯誤相當重要。這樣,咱們才能對此採起正確的應對方案。
常見的錯誤類型
由於JavaScript是鬆散弱類型語言,不少錯誤的產生是在運行期間的。通常來講,須要關注3種錯誤:
1.類型轉換錯誤;2.數據類型錯誤;3.通訊錯誤,這三種錯誤通常會在特定的模式下或者沒有對值進行充分檢查的狀況下發生。
類型轉換錯誤
在一些判斷比較的時候,好比數組比較,有相等和全等兩種:
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 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自己返回的就是類型的字符串,右邊也是字符串,那不必驗證類型,因此相等就夠了。
數據類型錯誤
因爲JavaScript是弱類型語言,在使用變量和傳遞參數以前,不會對它們進行比較來確保數據類型的正確。因此,這樣開發人員必須須要靠本身去檢測。
//自定義函數接收一個url function getQueryString(url) { //判斷接收到的參數是不是字符串類型 if (typeof url == 'string') { //判斷了指定類型,就不會出錯了 var pos = url.indexOf('?'); //若是字符串類型,查找字符串中?在字符串中的索引位置 return pos; //返回索引位置 }else { return '數據類型錯誤'; //若是不是字符串,返回數據類型錯誤 } } alert(getQueryString(1)); //執行函數
對於傳遞參數除了限制數字、字符串以外,咱們對數組也要進行限制
//自定義函數,接收一個對象 function sortArray(arr) { if (typeof arr.sort == 'function') { //判斷對象裏面的sort是不是一個方法,也就是函數 alert(arr.sort()); //就算這個繞過去了 alert(arr.reverse()); //reverse逆向排序數組,這個就又繞不過去了,出錯 } } var box = { //建立一個自定義對象,添加sort方法 sort: function () { } }; sortArray(box); //執行函數
PS:這斷代碼本意是判斷arr是否有sort方法,由於只有數組有sort方法,從而判斷arr是數組。但忘記了,自定義對象添加了sort方法就能夠繞過這個判斷,且arr還不是數組。
//自定義函數,接收一個數組 function sortArray(arr) { //判斷接收到的是不是數組類型 if (arr instanceof Array) { //使用instanceof判斷是Array最爲合適 alert(arr.sort()); //若是是數組類型。從小到達排序 } } var box = [3,5,1]; //建立數組 sortArray(box); //執行函數
通訊錯誤
在使用url進行參數傳遞時,常常會傳遞一些中文名的參數或URL地址,在後臺處理時會發生轉換亂碼或錯誤,由於不一樣的瀏覽器對傳遞的參數解釋是不一樣的,因此有必要使用編碼進行統一傳遞。
好比:?user=李炎恢&age=100
var url = '?user=' + encodeURIComponent('李炎恢') + '&age=100'; //編碼
PS:在AJAX章節中咱們會繼續探討通訊錯誤和編碼問題。
五.調試技術
在JavaScript初期,瀏覽器並無針對JavaScript提供調試工具,因此開發人員就想出了一套本身的調試方法,好比alert()。這個方法能夠打印你懷疑的是否獲得相應的值,或者放在程序的某處來看看是否能執行,得知以前的代碼無誤。
var num1 = 1; var num2 = b; //在這段先後加上alert('')調試錯誤 var result = num1 + num2; alert(result); //打印不到,說明上面哪裏有錯誤
PS:使用alert('')來調試錯誤比較麻煩,重要裁剪和粘貼alert(''),若是遺忘掉沒有刪掉用於調試的alert('')將特別頭疼。因此,咱們如今須要更好的調試方法。
將消息記錄到控制檯
IE八、Firefox、Opera、Chrome和Safari都有JavaScript控制檯,能夠用來查看JavaScript錯誤。對於Firefox,須要安裝Firebug,其餘瀏覽器直接使用console對象寫入消息便可。
console對象的方法,將數據信息記錄到控制檯,有4個方法
方法名 |
說明 |
error(message) |
將錯誤消息記錄到控制檯 |
info(message) |
將信息性消息記錄到控制檯 |
log(message) |
將通常消息記錄到控制檯 |
warn(message) |
將警告消息記錄到控制檯 |
4個方法均可以接收一個數據類型,來打印數據,不一樣的方法用不一樣的標識來打印
console.error('錯誤!'); //紅色帶叉 console.info('信息!'); //白色帶信息號 console.log('日誌!'); //白色 console.warn('警告!'); //黃色帶感嘆號
PS:這裏以Firefox爲標準,其餘瀏覽器會稍有差別。
var num1 = 1; console.log(typeof num1); //獲得num1的類型 var num2 = 'b'; console.log(typeof num2); //獲得num2的類型 var result = num1 + num2; alert(result); //結果是1b,匪夷所思
PS:咱們誤把num2賦值成字符串了,其實應該是數值,致使最後的結果是1b。那麼傳統調試就必須使用alert(typeo num1)來看看是否是數值類型,比較麻煩,由於alert()會阻斷後面的執行,看過以後還要刪,刪完估計一下子又忘了,而後又要alert(typeof num1)來加深印象。若是用了console.log的話,全部要調試的變量一目瞭然,也不須要刪除,放着也沒事。
將錯誤拋出
以前已經將結果錯誤的拋出,這裏不在贅述。
var num1 = 1; if (typeof num1 != 'number') throw new Error('變量必須是數值!'); //判斷num1不是數值類型,建立一個錯誤對象 var num2 = 'b'; if (typeof num2 != 'number') throw new Error('變量必須是數值!'); //判斷num2不是數值類型,建立一個錯誤對象 var result = num1 + num2; alert(result);
六.調試工具
IE八、Firefox、Chrome、Opera、Safari都自帶了本身的調試工具,而開發人員只習慣了Firefox一種,因此不少狀況下,在Firefox開發調試,而後去其餘瀏覽器作兼容。其實Firebug工具提供了一種Web版的調試工具:Firebug lite。
如下是網頁版直接調用調試工具的代碼:直接複製到瀏覽器網址便可。要求必須有網絡,鏈接加載網絡版Firebug lite調試工具【不推薦】
javascript:(function(F,i,r,e,b,u,g,L,I,T,E){if(F.getElementById(b))return;E=F[i+'NS']&&F.documentElement.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);})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');
PS:Chrome瀏覽器必須在服務器端方可有效。測試也發現,只能簡單調試,若是遇到錯誤,系統不能自動拋出錯誤給firebug-lite。
離線版firebug-lite
還有一種離線版,把firebug-lite下載好,載入工具便可,致使最終工具沒法運行,其餘瀏覽器運行無缺。雖然Web版本的Firebug Lite能夠跨瀏覽器使用Firebug,但除了Firefox原生的以外,都不支持斷點、單步調試、監視、控制檯等功能。好在,其餘瀏覽器本身的調試器都有。
將下載好的firebug-lite文件夾放到工程根目錄下,引入js文件,如:
<script type="text/javascript" src="firebug-lite/build/firebug-lite-beta.js" charset="utf-8"></script>
會自動加載工具
調試步驟
1.設置斷點
咱們能夠選擇Script(腳本),點擊要設置斷點的JS腳本處,便可設置斷點。當咱們須要調試的時候,從斷點初開始模擬運行,發現代碼執行的流程和變化。
2.單步調試
設置完斷點後,能夠點擊單步調試,一步步看代碼執行的步驟和流程。上面有五個按鈕:
從新運行:從新單步調試
斷繼:正常執行代碼
單步進入:一步一步執行流程
單步跳過:跳到下一個函數塊
單步退出:跳出執行到內部的函數
3.監控
單擊「監控」選項卡上,能夠查看在單步進入是,全部變量值的變化。你也能夠新建監控表達式來重點查看本身所關心的變量。
4.控制檯
顯示各類信息。以前已瞭解過。
PS:其餘瀏覽器除IE8以上都可實現以上的調試功能,你們能夠本身常識下。而咱們主要採用Firebug進行調試而後兼容到其餘瀏覽器的作法以提升開發效率。