Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲网站视频,久久不卡一区二区三区,精品在线一区二区

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript異常錯誤處理指南

          JavaScript異常錯誤處理指南



          前端的 JavaScript 開發中,發現開發者對于錯誤異常的處理普遍都比較簡單粗暴,如果應用程序中缺少有效的錯誤處理和容錯機制,代碼的健壯性就無從談起。本文整理出了一些常見的錯誤異常處理的場景,旨在為前端的 JavaScript 錯誤異常處理提供一些基礎的指導。


          Error 對象

          先來簡單介紹一下 JavaScript 中的 Error 對象,通常 Error 對象由重要的兩部分組成,包含了 error.message 錯誤信息和 error.stack 錯誤追溯棧。

          產生一個錯誤很簡單,比如在 foo.js 中直接調用一個不存在的 callback 函數。

          // foo.js
          function foo () {
              callback();
          }
          
          foo();
          

          此時通過 Chrome 瀏覽器的控制臺會展示如下的信息。

          Uncaught ReferenceError: callback is not defined
              at foo (foo.js:2)
              at foo.js:5
          

          其中 Uncaught ReferenceError: callback is not defined 就是 error.message 錯誤信息,而剩下的 at xxx 就是具體的錯誤追溯棧,在 Chrome 的控制臺中,對錯誤的展示進行了優化。

          如果我們通過 window.onerror 來捕獲到該錯誤后將 Error 對象直接輸出到頁面中會展示出更原始的數據。

          <!-- 展示錯誤的容器 -->
          <textarea id="error"></textarea>
          
          // 輸出錯誤
          window.onerror=function (msg, url, line, col, err) {
              document.getElementById('error').textContent=err.message + '\n\n' + err.stack;
          };
          

          原始的錯誤數據中會展示出錯誤追溯棧中的 Source URL。

          callback is not defined
          
          ReferenceError: callback is not defined
              at foo (http://example.com/js-error/foo.js:2:5)
              at http://example.com/js-error/foo.js:5:1
          

          有了錯誤追溯棧,就能通過發生錯誤的文件 Source URL 和錯誤在代碼中的具體位置來快速定位到錯誤。

          看起來好像很簡單,但實際的開發中如何有效的捕獲錯誤,如何有效的拋出錯誤都有一些需要注意的點,下面逐個的來講解。


          window.onerror

          前端在捕獲錯誤時都會通過綁定 window.onerror 事件來捕獲全局的 JavaScript 執行錯誤,標準的瀏覽器在響應該事件時會依次提供 5 個參數。

          window.onerror=function(message, source, lineno, colno, error) { ... }
          
          1. message 錯誤信息
          2. source 錯誤發生時的頁面 URL
          3. lineno 錯誤發生時的 JS 文件行數
          4. colno 錯誤發生時的 JS 文件列數
          5. error 錯誤發生時拋出的標準 Error 對象

          使用 window.addEventListener 也能綁定 error 事件,但是該事件函數的參數是一個 ErrorEvent 對象。

          綁定 window.onerror 事件時,事件處理函數的第 5 個參數在低版本瀏覽中或 JS 資源跨域場景下可能不是 Error 對象。


          在 Chrome 瀏覽器中如果頁面加載的 JS 資源文件中存在跨域的 script 標簽,在發生錯誤時會提示 Script error 而缺乏錯誤追溯棧。

          window.onerror 在響應跨域 JavaScript 錯誤時缺乏錯誤追溯棧時的 arguments 對象如下:

          [
              'Script error.',
              '',
              0,
              0,
              null
          ]
          

          為了正常的捕獲到跨域 JS 資源文件的錯誤,需要具備兩個條件: 1. 為 JS 資源文件增加 CORS 響應頭。 2. 通過 script 引用該 JS 文件時增加 crossorigin="anonymous" 的屬性,如果是動態加載的 JS,可以寫作 script.crossOrigin=true 。

          window.onerror 能捕獲一些全局的 JavaScript 錯誤,但還有不少場景在全局是捕獲不到的。


          try/catch

          window.onerror 能捕獲全局場景下的錯誤,如果已知一些程序的場景中可能會出現錯誤,這個時候一般會使用 try/catch 來進行捕獲。

          但是在使用 try/catch 塊時無法捕獲異步錯誤,例如塊中使用了 setTimeout 。

          try {
              setTimeout(function () {
                  callTimeout();  // callTimeout 未定義,會拋錯
              }, 1000);
          }
          catch (err) {
              console.log('catch the error', err); // 不會被執行
          }
          

          try/catch 在處理 setTimeout 這類異步場景時是無效的,執行時仍會拋錯,catch 中的代碼不會被執行。

          雖然在 try/catch 中沒有捕獲到,此時如果有綁定 window.onerror 則會被全局捕獲。

          由此可見, try/catch 應該是只能捕獲 JS Event Loop 中同步的任務。

          如果想正確的捕獲 setTimeout 中的錯誤,需要將 try/catch 塊寫到 setTimeout 的函數中。

          setTimeout(function () {
              try {
                  callTimeout(); // callTimeout 未定義,不會拋錯
              }
              catch (err) {
                  console.log('catch the error', err); // 將會被執行
              }
          }, 1000);
          

          Promise

          Promise 有自己的錯誤處理機制,通常 Promise 函數中的錯誤無法被全局捕獲。

          var promise=new Promise(executor);
          promise.then(onFulfilled, onRejected);
          

          比較容易遺漏錯誤處理的地方有 executor 和 onFulfilled ,在這些函數中如果發生錯誤都不能被全局捕獲。

          正確的捕獲 Promise 的錯誤,應該使用 Promise.prototype.catch 方法,意外的錯誤和使用 reject 主動捕獲的錯誤都會觸發 catch 方法。


          catch 方法中通常會接收到一個 Error 對象,但是當調用 reject 函數時傳入的是一個非 Error 對象時,catch 方法也會接收到一個非 Error 對象,這里的 reject 和 throw 的表現是一樣的,所以在使用 reject 時,最好是傳入一個 Error 對象。

          reject(
              new Error('this is reject message')
          );
          

          值得注意的是,如果 Promise 的 executor 中存在 setTimeout 語句時, setTimeout 的報錯會被全局捕獲。


          Async Function

          Async Function 和 Promise 一樣,發生錯誤不會被全局的 window.onerror 捕獲,所以在使用時如果有報錯,需要手動增加 try/catch 語句。

          匿名函數

          匿名函數的使用在 JavaScript 中很常見,但是當出現匿名函數的報錯時,在錯誤追溯棧中會以 anonymous 來標識錯誤,為了排查錯誤方便,可以將函數進行命名,或者使用函數的 displayName 屬性。

          函數如果有 displayName 屬性,在錯誤棧中會展示該屬性值,如果用于命名重要的業務邏輯屬性,將有效幫助排查錯誤。


          throw error

          上面說了很多錯誤捕獲的注意點,如果要主動的拋錯,都會使用 throw 來拋錯,常見的幾種拋錯方法如下:

          throw new Error('Problem description.')  // 方法 1
          throw Error('Problem description.')      // 方法 2
          throw 'Problem description.'             // 方法 3
          throw null                               // 方法 4
          

          其中方法 1 和方法 2 的效果一樣,瀏覽器都能正確的展示錯誤追溯棧。方法 3 和方法 4 不推薦,雖然能拋錯,但是在拋錯的時候不能展示錯誤追溯棧。

          try/catch 和 throw ,一個用來捕獲錯誤,一個用來拋出錯誤,如果兩個結合起來用通常等于脫了褲子放屁多此一舉,唯一有點用的是可以對錯誤信息進行再加工。

          可以在 Chrome 控制臺中模擬出一個結合使用的實際場景。

          try {
              foo();
          }
          catch (err) {
              err.message='Catch the error: ' + err.message;
              throw Error(err);
          }
          

          由于在 catch 塊中又拋出了錯誤,所以該錯誤沒有被捕獲到,但此時錯誤信息經過了二次封裝。

          Uncaught Error: ReferenceError: Catch the error: foo is not defined
          

          通過對錯誤信息的二次封裝,可以增加一些有利于快速定位錯誤的額外信息。


          原作者:雨夜帶刀's Blog

          、Javascript的異常處理機制

          當javascript代碼中出現錯誤的時候,js引擎就會根據js的調用棧逐級尋找對應的catch,如果沒有找到相應的catch handler或catch handler本身又有error或者又拋出新的error,最后就會把這個error的處理交給瀏覽器,并顯示在錯誤控制臺中)顯示錯誤信息給訪問者。

          二、try/catch/finally

          是js提供的異常處理機制,用法如下:

          try {
          // 這段代碼從上往下運行,其中任何一個語句拋出異常該代碼塊就結束運行}
          catch (e) {
          // 如果try代碼塊中拋出了異常,catch代碼塊中的代碼就會被執行。
          // e是一個局部變量,用來指向Error對象或者其他拋出的對象
          }
          finally {
            //無論try中代碼是否有異常拋出(甚至是try代碼塊中有return語句),
                 //finally代碼塊中始終會被執行
          }

          三、常見錯誤

          3.1 syntaxError

          顧名思義,典型的語法錯誤。

          function foo{
          }
          if{}

          Js代碼是從上往下依次執行,但是js引擎先解析代碼是否語法出錯,如果語法都解析不通過,那么顯而易見:一行代碼也不會執行,從而會在控制臺中輸出語法報錯:


          syntaxError錯誤

          3.2 變量未定義

          變量未定義(也叫未聲明)指的是,當程序中使用了一個未定義的變量則會報錯。

          如下代碼:

          var foo=1
          var bar=foo + n1

          顯而易見,n1變量是未定義的就直接使用,從而會在控制臺中輸出如下錯誤:


          XXX is not defined 變量未定義

          3.3 TypeError錯誤

          TypeError錯誤指的是數據類型未正確使用。

          例如一:

          var foo=function(){
          	console.log('foo')
          }
          foo='hello world'
          foo()

          在某些邏輯下,foo本身存儲的是函數,但是誤把foo賦值了一個字符串或其它不是函數的數據類型,但是foo當作函數來調用了,則會報TypeError錯誤在控制臺中輸出:


          TypeError,xxx is not a function

          例如二:

          未正確獲取元素,導致得到一個null而不是DOM節點對象后,綁定事件而引發的TypeError錯誤。

          <script>
          var oBtn=document.getElementById('btn') 
          //因為代碼從上往下解析的原因,還未解析到button標簽,返回為null。
          //null是空對象,不能綁定任何屬性,onclick雖然是事件,
          //但也是對象中屬性的一部分,所以報TypeError錯誤。
          oBtn.onclick=function(){
          	console.log('bar')
          }
          </script>
          <button id="btn">foo</button>


          cannot set property 'onclick' of null

          正確錯誤是把選擇元素的js代碼放置html標簽之后,也就是緊鄰 </body>標簽,或放在windo.onload事件中。

          <script>
          	window.onload=function(){
          		var oBtn=document.getElementById('btn') 
              //因為代碼從上往下解析的原因,還未解析到button標簽,返回為null。
              //null是空對象,不能綁定任何屬性,onclick雖然是事件,
              //但也是對象中屬性的一部分,所以報TypeError錯誤。
              oBtn.onclick=function(){
                console.log('bar')
              }
          	}
          </script>
          <button id="btn">foo</button>

          3.4 JSON解析錯誤

          首先,我們需要了解JSON是什么 ?

          JSON(JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數據交換格式。它基于 ECMAScript (歐洲計算機協會制定的js規范)的一個子集,采用完全獨立于編程語言的文本格式來存儲和表示數據。簡潔和清晰的層次結構使得 JSON 成為理想的數據交換語言。

          而它的定義規則和js中字面量聲明對象很像,所以很多初學者以為json就是js對象,其實這是錯誤的。

          3.4.1 JSON 是 JS對象表示語法的子集。

          • 數據在名稱/值對中
          • 數據由逗號分隔
          • 大括號 {} 保存對象
          • 中括號 [] 保存數組,數組可以包含多個對象

          3.4.2 JSON 數據的書寫格式是

          key : value

          名稱/值包括字段名稱(在雙引號中),后面寫一個冒號,然后是值:

          "name" : "foo"

          3.4.3 JSON 值可以是:

          • 數字(整數或浮點數)
          • 字符串(在雙引號中)
          • 邏輯值(true 或 false)
          • 數組(在中括號中)
          • 對象(在大括號中)
          • null

          前方高能~~~

          談到這里,json數據從哪來呢?

          在請求Ajax的時候,會從后臺服務器中拿到json數據,往往會把json解析成js對象。則前端工程師會用到JSON.parse方法。有時候前端也會定義JSON數據,如果語法不正確當轉成js對象時,則會報錯。如下代碼:

          //var foo='{ name:"bar" }'//name未帶雙引號
          var foo='{ "name":bar }'//bar未帶雙引號
          
          var f=JSON.parse( foo )


          token n in JSON at position

          正確的JSON轉換js對象的方式如下:

          var foo='{ "name":"bar","age":20 }'//20無需帶,則理解為數值類型
          
          var f=JSON.parse( foo )
          console.log( f ) //{name: "bar", age: 20} ,此時可以正確的把json轉換成js對象,
          												//通過 點 語法,也就是f.name和f.age訪問到具體的數據

          以上是JavaScript中常見的錯誤,后期遇到會不斷更新,感謝小伙伴們的踴躍投稿和留言。

          內容是《Web前端開發之Javascript視頻》的課件,請配合大師哥《Javascript》視頻課程學習。

          錯誤處理對于web應用開發至關重要,任何javascript錯誤都有可能會導致網頁無法使用,因此作為開發人員,必須要及時處理有可能出現的錯誤;

          從IE4.0之后,幾乎所有的瀏覽器都包含了一些基本的錯誤處理功能,但并沒有統一,后來,由ECMAscript添加了異常處理機制,也就是try…catch…finally結構以及throw操作;

          錯誤處理的重要性: 好的錯誤處理技術可以讓腳本的開發、調試和部署更加流暢,能對代碼進行更好的控制;另外,JS缺乏標準的開發環境;

          錯誤類型:

          語法錯誤(syntax error):也稱為解析錯誤,發生在傳統編程語言的編譯解釋時;發生語法錯誤時,就會發生阻塞,也就是不能繼續執行代碼,但只是同一個線程中的代碼會受影響,其他線程中的代碼不受影響;

          // Uncaught SyntaxError: Invalid or unexpected token
          // 未捕獲的語法錯誤:無效或意外的標記
          document.write("zeronetwork;

          運行時錯誤(Runtime error):也稱為exception異常, 其發生在編譯期/解釋期后,此時,問題并不出現在代碼的語法上,而是在嘗試完成一個非法的操作;

          <input type="button" value="單擊" onclick="handleClick()" />
          <script>
          // Uncaught ReferenceError: openMy is not defined
          // 未捕獲的引用錯誤:未定義openMy
          function handleClick(){
              openMy();
          }
          </script>

          錯誤報告:

          因為每個瀏覽器都有自己的內置Javascript解釋程序,所以每種瀏覽器報告錯誤的方式都不同;有些是彈出錯誤信息,有些是把信息打印在控制臺中;

          IE(windows): 默認情況下,會彈出包含錯誤細節的對話框,并詢問是否繼續執行頁面上的腳本;如果瀏覽器有調試器(如:Microsoft Script Debugger) ,此對話框會提供一個是調試還是忽略的選項;如果在IE設置中取消了”顯示錯誤”,那么會在頁面左下角顯示一個黃色的圖標;

          注:如果JS代碼就在HTML里,顯示錯誤行是正確的,如果是外部的JS文件,則行號往往差一行,如第5行則為第4行;

          Mozilla(所有平臺): 在控制臺中打印錯誤信息,并發出警告;其會報告三種類型的消息:錯誤、嚴格警告和消息等的;

          Safari (MacOS):是對JavaScript錯誤和調試的支持最差,默認情況下,它對終端用戶不提供任何javascript錯誤報告;

          錯誤處理:

          Javascript提供了兩種處理錯誤的方式:

          • BOM包含一個onerror事件處理函數,該函數通常被綁定在window對象或image對象上;
          • ECMAscript定義了try…catch結構來處理異常;

          onerror事件處理函數:

          window對象的onerror屬性是一個事件處理程序,頁面上出現異常時,error事件便在window對象上觸發,并把錯誤消息輸出到Javascript控制臺上,這種方式也稱為全局錯誤捕獲;如:

          window.onload=function(){
              show(); // 在onload事件中調用了一個不存在的函數
          }
          window.onerror=function(){
              alert("出現錯誤");
              return true;
          }

          獲取錯誤信息:

          window.onerror事件處理程序在調用時可以傳5個參數,由這5個參數可以獲取詳細的錯誤信息;

          • message:錯誤信息,描述錯誤的一條消息;
          • URL:引發錯誤的Javascript所在的文檔的URL;
          • line:文檔中發生錯誤的行數;
          • column:發生錯誤的列數;
          • error:錯誤對象,這個error也稱為全局錯誤對象;
          window.onerror=function(sMessage, sUrl, sLine, sColumn, error){
          console.log("Error:" + sMessage + " URL:" + sUrl + " Line:" + sLine + " Column:" + sColumn);
          console.log(error);
              return true;
          }

          onerror處理程序的返回值:

          如果返回true,則阻止執行默認的事件處理程序,也就是將通知瀏覽器,事件處理程序已經處理了錯誤,不需要其他操作,反之會顯示錯誤消息;

          某些元素也支持onerror; 但其處理函數沒有任何關于error信息的參數,如:

          document.images[0].onerror=function(event){
          console.log(event);  // Event
          console.log(event.type);  // error
          }

          這里的event參數是一個類型為Event事件對象,其存儲的信息除了type返回了error,并沒有其他和錯誤相關的信息;

          全局錯誤處理window.onerror通常不能恢復腳本繼續執行,但會給開發者發送錯誤信息;

          window.onerror=function(error){
            console.log(error);
          }
          show();
          console.log("中止,不會被執行");
          window.onload=function(){
            console.log("也不會被執行");
          }

          可以是簡單的打印,也可以把錯誤保存到日志記錄里;

          window.onerror就是綁定在window對象的error事件,也可以使用標準的添加事件偵聽的方式window.addEventListener(eventtype, handler),其需要兩個參數,eventtype為事件類型,在此為error,handler是事件處理函數,其需要一個參數event,一個ErrorEvent類型的對象,其保存著有關事件和錯誤的所有信息,如:

          window.addEventListener("error", function(event){
            console.log(event);  // ErrorEvent
            console.log(event.error);  // Error對象
            console.log(event.error.name);
            console.log(event.error.message);
            console.log(event.error.stack);
            console.log(event.lineno);  // 行
            console.log(event.colno);  // 列
            console.log(event.filename);
          });

          在實際的開發中,這兩種方式都會被使用,只不過addEventListener有定的兼容必問題,所以要兼顧所有的瀏覽器且不太關注事件對象本身的話,就使用window.onerror;

          當加載自不同域的腳本中發生語法錯誤時,為避免信息泄露,語法錯誤的細節將不會報告,只會返回簡單的"Script error.";

          <script>
          window.onerror=function(msg, url, lineNo, columnNo, error){
            console.log(msg);  // Script error
            console.log(url);  // ""
            console.log(lineNo);  // 0
            console.log(columnNo);  // 0
            console.log(error);  // null
          }
          </script>
          <script src="https://www.zeronetwork.cn/demo/demo.js"></script>

          可以針對同域和不同域的錯誤分開處理,如:

          <script>
          window.onerror=function(msg, url, lineNo, columnNo, error){
            var str_error=msg.toLowerCase();
            var sub_string="script error";
            if(str_error.indexOf(sub_string) > -1)
              alert("腳本發生錯誤,詳情請在控制臺查看");
            else{
              var message=[
                '消息:' + msg,
                'URL:' + url,
                '行:' + lineNo,
                '列:' + columnNo,
                '錯誤對象:' + error
              ].join(" - ");
              alert(message);
            }
          }
          show();
          </script>
          <script src="https://www.zeronetwork.cn/demo/demo.js"></script>

          從上在的執行結果來看,error事件執行了兩次,原因是使用了兩個script,也就是當一個script有錯誤發生時,它只會阻止當前的script塊,而不會阻止其他的script塊;如:

          <script>
          show();  // 會捕獲
          console.log("不會被執行");
          myshow();  // 不會捕獲
          </script>
          <script src="https://www.zeronetwork.cn/demo/demo.js"></script>
          <script>
          console.log("執行了");
          demo();  // 會捕獲
          console.log("不會被執行");
          </script>

          body元素的onerror特性,也可以充當事件處理函數,如:

          <body onerror="alert('出現了錯誤');return true;">

          注意,先注釋掉window.onerror等代碼;

          此時,可以直接使用event、source、lineno、colno、error等屬性;

          <body onerror="alert(event + '\n' + source + '\n' + lineno + '\n' + colno + '\n' + error);return true;">

          當然了,也可以為body綁定error事件,此時各屬性,必須明確指定,如:

          document.body.onerror=function(msg, url,lineno,colno,error){
            alert(msg + '\n' + url + '\n' + lineno + '\n' + colno + '\n' + error);
            return true;
          }

          try-catch語句:

          try語句中為期待正常執行的代碼塊,當在try語句中發生錯誤,其余代碼會中止執行,catch語句就處理該錯誤,如果沒有錯誤,就跳過catch語句;try和catch必須成對出現;

          try{
              //code
              [break]
          }catch([exception]){
              //code
          }[finally]{
              //code
          }
          // 如
          try {
              show();
              alert("不能執行");
          } catch (error) {
              alert("出現一個錯誤:" + error);
          } finally{
              alert("管你呢");
          }

          try語句塊內的錯誤只會中止try語句塊中發生錯誤之后的邏輯代碼,并不會中止整個腳本的運行;執行try-catch語句,必須是運行時,運行時錯誤,也被稱為異常;try-catch語句中指定只能有一個catch子句;try-catch語句適合處理無法預知、無法控制的錯誤;finally常被用于無論結果是否有異常,都要執行的代碼,如:

          try{
            alert("try");
            show();
            alert("no exec");
          }catch(error){
            alert("catch");
          }finally{
            alert("finally");
          }
          alert("continute");

          代碼執行的兩條路徑:如果沒有異常,執行路徑為:try->finally,反之為:try的部分->catch->finally;

          一般用于關閉打開的鏈接和釋放資源;

          var connection={open: function(){},close: function(){},send: function(data){}}
          // var data="大師哥王唯"; // 注釋這一行,讓它產生異常
          connection.open();
          try{
              connection.send(data);
          }catch(exception){
              console.log("出現一個錯誤");
          }finally{
              connection.close();
              console.log("關閉了");
          }

          還有一個典型的應用,讀寫文件,如:

          function openFile(){};
          function writeFile(data){};
          function closeFile(){};
          openFile();
          try{
            writeFile();
          }catch(error){
            console.log(error);
          }finally{
            closeFile();
          }

          在try-catch-finally語句塊中的變量是全局變量:

          try{
            var name="王唯";
            show();
            var city="蚌埠";
          }catch(error){
            var age=18;
            console.log(name);
          }finally{
            var sex="男";
            console.log(name);
            console.log(age);
          }
          console.log(name);
          console.log(city);
          console.log(age);
          console.log(sex);

          try-catch-finally與return:

          如果直接在try-catch-finally語句塊中執行return,會拋出異常,如:

          try {
            console.log("try");
            // return;  // Illegal return statement 非法返回語句
            console.log("try agin");
          } catch (error) {
            console.log(error);
            // return;  // Illegal return statement
          }finally{
            console.log("finally");
            // return;  // Illegal return statement
          }

          如:

          function foo(){
            try {
              console.log("try");
              return 1;
              show();
              console.log("try agin");
            } catch (error) {
              console.log(error);
              return 2;
            }finally{
              console.log("finally");
              return 3;
            }
          }
          console.log(foo());  // 3

          try-finally:

          沒有catch從句,只有try-finally也可以,目的是,只確保執行開始和最終的過程,而不處理錯誤,如:

          try{
            console.log("try");
            show();
          }finally{
            console.log("finally"); // 會執行
          }
          console.log("over"); // 不會執行,已中止

          但此時,還是會拋出異常的,但此時,會在執行完finally后中止執行,并會查找外部的catch語句;

          嵌套try-catch語句:

          在catch子句中,也有可能會發生錯誤,所以就可以使用嵌套的try-catch語句,如:

          try {
              show();
              console.log("不能執行");
          } catch (error) {
              console.log("出現一個錯誤:" + error);
              try {
                  var arr=new Array(10000000000000000);
                  arr.push(error);
              } catch (error) {
                  console.log("又出現了一個錯誤:" + error);
              }
          } finally{
              console.log("管你呢");
          }

          也可以在try中嵌套try-catch-finally語句,如:

          try{
            try{
              console.log("try");
              show();
            }catch(error){
              console.log("error");
            }finally{
              console.log("finally");
            }
          }catch(error){
            console.log(error);
          }

          一個比較典型的應用,就是處理json數據,如:

          // var json='{"name":"wangwei", "age": 18, "sex": "男"}';
          var json='{bad json}';  // Uncaught SyntaxError
          var data=JSON.parse(json);
          console.log(data.name);
          console.log(data.age);
          console.log(data.sex);

          一量json數據發生錯誤,整個應用都會崩潰,所以應該使用try-catch,如:

          <div id="msg">您的信息:</div>
          <script>
          window.onload=function(){
            var msg=document.getElementById("msg");
            try{
              // var json='{"name":"王唯", "age": 18, "sex": "男"}';
              var json='{bad json}';  // Uncaught SyntaxError
              var data=JSON.parse(json);
              msg.innerHTML +="姓名:" + data.name + ",年齡:" + data.age + ",性別:" + data.sex;
            }catch(error){
              msg.innerHTML="開小差了,找不到你的信息";
            }
          }
          </script>

          當使用了try-catch語句,就不會將錯誤提交給瀏覽器,也就不會觸發error事件,如:

          window.onerror=function(error){
            console.log(error);  // 不會觸發
          }
          try{
            show();
          }catch(error){
            console.log(error);
          }

          Error錯誤對象:

          在catch中會捕獲一個Error錯誤對象;該對象在Javascript解析或運行時,一旦發生錯誤,引擎就會拋出這個對象;如果沒有相關聯的try-catch捕獲該對象,就由瀏覽器輸出這個對象;

          // ...
          console.log("錯誤:" + error + " name:" + error.name + " message:" + error.message);

          也可以通過Error的構造器創建一個錯誤對象,這個Error對象也可用于用戶自定義的異常;語法:new Error([message[, filename[, lineNumber]]]);

          • message:可選,錯誤描述信息;
          • fileName:可選,非標準,被創建的Error對象的fileName屬性值,默認是調用Error構造器代碼所在的文件的名字; 但大部分瀏覽器沒有實現;
          • lineNumber:可選,非標準,被創建的Error對象的lineNumber屬性值,默認是調用Error構造器代碼所在的文件的行號;但大部分瀏覽器沒有實現;

          實例化Error對象,也可以不使用new關鍵字,如:

          var error=new Error("自定義錯誤對象");
          var error=Error("不使用new");
          console.log(error);
          console.log(error.name);  // Error
          console.log(error.message);  // 自定義錯誤對象

          Error錯誤對象屬性:

          • name:表示錯誤類型的字符串;
          • message:實際的錯誤信息;

          Error類還有6個子類,其可以通過錯誤對象的name屬性返回具體異常類的名稱:

          • EvalError:錯誤發生在eval()函數中;
          • RangeError:數值超出javascript可表示的范圍;;
          • ReferenceError:使用了非法或不能識別的引用;
          • SyntaxError:發生了語法錯誤;
          • TypeError:操作數的類型不是預期所需的;
          • URIError:在encodeURI()或decodeURI()函數中發生了錯誤;
          // EvalError
          try{
            throw new EvalError("Eval異常");
          }catch(error){
            console.log(error);
            console.log(error instanceof EvalError);  // true
            console.log(error.name);  // EvalError
            console.log(error.message);  // Eval異常
          }
          // RangeError
          var num=1;
          try{
            num.toPrecision(500);  //  [pr??s??n] 精度
          }catch(error){
            console.log(error); 
          }
          // ReferenceError
          var x;
          try {
            x=y + 1;
          } catch (error) {
            console.log(error);
          }
          // SyntaxError
          try{
            eval("alert('wangwei)");
          }catch(error){
            console.log(error);
          }
          // TypeError
          var num=1;
          try{
            num.toUpperCase(); // 無法將數字轉為大寫
          }catch(error){
            console.log(error);
          }
          // URIError (malformed [?m?l?f??md]格式不正確,畸形的)
          try{
            decodeURI("%%%"); // 使用了非法字符
          }catch(error){
            console.log(error);
          }

          Error對象的message屬性是瀏覽器生成的用于表示錯誤描述的信息,因為這個屬性是特定于瀏覽器的,所以不同的瀏覽器上可能產生不同的錯誤信息,如:

          try {
              eval("a ++ b");
              show();
              console.log("執行了嗎?");
          } catch (error) {
              // SyntaxError:Unexpected identifier或
              // SyntaxError:unexpected token: identifier
              console.log(error.name + ":" + error.message);
          }

          使用name屬性判斷錯誤類型:

          try {
              eval("a++b");
          } catch (error) {
              console.log(error instanceof SyntaxError); // true
              if(error.name=="SyntaxError")
                  console.log(error.name + ":" + error.message);
              else
                  console.log("未知錯誤:" + error.message);
          }

          拋出異常:

          throw語句的作用是手動中斷程序執行,拋出一個錯誤,一般用于有目的的拋出異常,也就是允許開發者可以創建自定義錯誤;

          throw可以拋出任何類型的值,也就是說,它的參數可以是任何值;語法:throw error_object;error_object可以是字符串、數字、布爾或對象;

          throw "出現一個錯誤";
          throw 50666;
          throw true;
          throw new Object();
          throw {
              toString:function(){
                  return 'Error!';
              }
          }
          function getRectArea(width, height){
            if(isNaN(width) || isNaN(height))
              throw '參數應該是number類型';
            return width * height;
          }
          getRectArea("wangwei",10);

          對于Javascript引擎來說,只要遇到throw語句,程序就會終止;

          也可以拋出一個Error錯誤對象;Error對象的構造函數只有一個參數,

          throw new Error("請再次嘗試");

          其他Error子類對象也可以拋出:

          throw new SyntaxError("...");
          throw new TypeError("...");
          throw new RangeError("...");
          throw new EvalError("...");
          throw new URIError("...");
          throw new ReferenceError("...");

          對于Error類和其子類來說,錯誤對象的name就是其構造函數的名稱,message是其構造函數的參數;

          當拋出異常后,throw之后的語句將不會執行,并跳到相關聯的catch語句中進行處理,如:

          <h1>請輸入18-99之間的數字</h1>
          <input id="txtInput" type="text" />
          <button id="btn">確定</button>
          <p id="msg"></p>
          <script>
          function myFun(){
            var msg,x;
            msg=document.getElementById("msg");
            msg.innerHTML="";
            x=document.getElementById("txtInput").value;
            try{
              if(x=="") throw "空的";
              if(isNaN(x)) throw "不是數字";
              x=Number(x);
              if(x < 18) throw "太小";
              if(x > 99) throw "太大";
              msg.innerHTML="輸入的值正確:" + String(x);
            }
            catch(error){
              msg.innerHTML="輸入的值不正確:" + error; 
            }
          }
          var btn=document.getElementById("btn");
          btn.onclick=myFun;
          </script>

          也可以在某個語句塊的外部捕獲throw異常,如:

          function sum(a,b){
              if(arguments.length < 2)
                  throw new Error("需要兩個參數");
              else
                  return a + b;
          }
          try{
              console.log(sum(18));
          }catch(error){
              // Error:需要兩個參數
              console.log(error.name + ":" + error.message);
          }

          可以通過instanceof判斷異常的類型來特定處理某一類的異常,例如可以區分瀏覽器拋出的異常和開發人員拋出的異常,如:

          function sum(a,b){
              if(arguments.length < 2)
                throw new Error("需要兩個參數");
              if(isNaN(a) || isNaN(b))
                throw "參數是不是Number類型";
              return a + b;
          }
          try{
              console.log(sum(18,12));
          }catch(error){
            if(error instanceof SyntaxError)
              console.log("語法錯誤:" + error.name + ":" + error.message);
            else if(error instanceof Error)
              console.log(error.name + ":" + error.message);
            else
                console.log(error);
          }

          注:判斷Error類型要放到if的最后一個條件;

          即使在catch語句中,還可以根據實際情況,再次拋出異常,此時,其可以被外部的try-catch語句塊捕獲(如果存在的話);

          當發生異常時,代碼會立即停止,僅當有try-catch語句捕獲到異常時,代碼才會繼續執行;其背后運行的原理是,當發生異常,JavaScript解釋器會立即停止執行的邏輯,并跳轉到就近的try-catch異常處理程序,如果發生異常的代碼塊中沒有相關聯的catch從句,解釋器會檢查更高層的閉合代碼塊,看它是否有相關聯的異常處理程序,以此類推,直到找到一個異常處理程序為止;如果發生異常的函數中沒有處理它的try-catch語句,異常將向上傳播到調用該函數的代碼,如此,異常就會沿著Javascript的語法結構或調用棧向上傳播;如果沒有找到任何異常處理程序,JavaScript將把異常當成程序錯誤來處理,并通過瀏覽器報告給用戶;

          自定義錯誤類型:

          可以基于Error類來創建自定義的錯誤類型,此時可以使用throw拋出自定義的異常類,或通過instanceof來檢查這個異常類的類型,新類型需要實現name和message屬性;

          function CustomError(message){
            this.name="CustomError";
            this.message=message || 'Default Message';
            this.stack=(new Error()).stack;
          }
          // CustomError.prototype=new Error();
          // 或者
          CustomError.prototype=Object.create(Error.prototype);
          CustomError.prototype.constructor=CustomError;
          try{
            var name="jingjing";
            if(name !=="wangwei")
              throw new CustomError("自定義的錯誤類型");
          }catch(error){
            console.log(error.message);
          }

          小示例:

          function UserException(message){
            this.name="UserException";
            this.message=message;
          }
          function getMothName(m){
            m=m - 1;  // 調整月份數字到數組索引(1=Jan,12=Dec)
            var months=['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
            if(months[m] !=undefined)
              return months[m];
            else
              throw new UserException("Invalid Month No");
          }
          try{
            var myMonth=15;
            var monthName=getMothName(myMonth);
          }catch(error){
            var monthName="未知";
            console.log(error.name + ":" + error.message);
          }

          小示例:驗證電話號碼,如:

          function Telephone(num){
            num=String(num);
            var pattern=/^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/;
            if(pattern.test(num)){
              this.value=num.match(pattern)[0];
              this.valueOf=function(){
                return this.value;
              };
              this.toString=function(){
                return String(this.value);
              }
            }else{
              throw new TelephoneFormatException(num);
            }
          }
          function TelephoneFormatException(value){
            this.name="TelephoneFormatException";
            this.message="電話號碼格式不正確";
            this.value=value;
            this.toString=function(){
              return this.value + ":" + this.message;
            }
          }
          // 應用
          var TELEPHONE_INVALID=-1;
          var TELEPHONE_UNKNOWN_ERROR=-2;
          function verifyTelephone(num){
            try{
              num=new Telephone(num);
            }catch(error){
              if(error instanceof TelephoneFormatException)
                return TELEPHONE_INVALID;
              else
                return TELEPHONE_UNKNOWN_ERROR;
            }
            return num.toString();
          }
          console.log(verifyTelephone("010-66668888"));
          console.log(verifyTelephone("13812345678"));
          console.log(verifyTelephone("138123456")); // -1
          console.log(verifyTelephone("wangwei")); // -1

          常見錯誤:

          由于javaScript是松散類型的,也不會驗證函數的參數,因此錯誤只會在運行時出現;一般來說,需要關注三種錯誤:類型轉換錯誤、數據類型錯誤、通信錯誤;

          類型轉換錯誤:

          一般發生在使用某個操作符,或者使用其他可能自動轉換值的數據類型的語言結構時;

          function output(str1,str2,str3){
            var result=str1 + str2;
            if(str3)
              result +=str3;
            return result;
          }
          console.log(output(1,2,3));
          console.log(output(1,2));
          console.log(output(1,2,0));
          console.log(output(1,2,"wangwei"));

          這就是一個非常典型的與期望不一致的方式;

          數據類型錯誤:

          在流控制語句中使用非布爾值,是極為常見的一個錯誤來源,為避免此類錯誤,就要做到在條件比較時確定傳入的是布爾值,例如,把if語句改成:if(typeof str3=='number');

          所以在使用某個變量或對象時,一定要適當地檢查它的數據類型,如:

          function reverseSort(values){
            // if(values){
            //   values.sort();
            //   values.reverse();
            // }
            if(arguments.length > 0){
              if(!Array.isArray(values))
                return [];
              else{
                values.sort();
                values.reverse();
                return values;
              }
            }
            return [];
          }
          var arr=[3,2,6,9,4];
          // var arr=100;  // Uncaught TypeError: values.sort is not a function
          console.log(reverseSort(arr));

          另一個常見的錯誤就是將參數與null值進行比較。與null進行比較只能確保相應的值不是null和undefined。要確保傳入的值有效,僅檢測null值是不夠的;

          function reverseSort(values){
            // if(values !=null){  // 任何非數組值都會導致錯誤
            if(values instanceof Array) // 非數組值被忽略
              values.sort();
              values.reverse();
            }
            return values;
          }
          var arr=[3,2,6,9,4];
          // var arr=100;  // Uncaught TypeError: values.sort is not a function
          console.log(reverseSort(arr));
          // 或
          function reverseSort(values, fun){
            if(values instanceof Array){
              if(fun !=null && typeof fun==="function")
                values.sort(fun);
              else
                values.sort();
            }
            return values;
          }
          var arr=[3,2,6,9,4];
          console.log(reverseSort(arr, function(a,b){
            return a > b ? -1 : 1;
          }));

          通信錯誤:最典型的就是Ajax應用,用其可以動態加載信息,但是,javascript與服務器之間的任何一次通信,都有可能會產生錯誤;

          調試技巧:

          使用警告框: 這是最簡單、流行的方式,如:

          function test(){
              alert("函數內");
              var iNum1=5, iNum2=10;
              alert(iNum1);
              var iResult=iNum1 + iNum2;
              alert(iResult);
          }
          test();

          拋出自定義錯誤:

          function assert(bCondition, sErrorMessage){
              if(!bCondition)
                  throw new Error(sErrorMessage);
          }
          function divide(iNum1, iNum2){
              assert(arguments.length==2, "divide需要兩個參數");
              assert((!isNaN(iNum1) && !isNaN(iNum2)), "需要Number類型");
              return iNum1 / iNum2;
          }
          console.log(divide(10,2));
          console.log(divide(10,"c"));  // 異常
          // 或
          try{
            console.log(divide(10,"c"));
          }catch(error){
            console.log(error.name + ":" + error.message);
          }

          Javascript校驗器:

          jslint的主要目的是指出不合規范的js語法和可能的語法錯誤,包括一些不良代碼;官網:http://www.jslint.com/

          如以下,會給出警告:

          • 語句未使用塊標記;
          • 一行的結尾未以分號結束;
          • 用var聲明一個已在使用的變量;
          • with語句;

          調試器:

          Javascript自身不具備調試器,但目前所有的瀏覽器可以使用自身的調試器;

          IE調試:

          啟用IE的調試功能:

          菜單“工具”|“Internet選項”命令,打開“Internet選項”對話框,在“高級”選項卡中,找到兩個“禁用腳本調試”復選框并取消;開始調試,調試的主要工作是反復地跟蹤代碼,找出錯誤并修正;

          設置斷點:

          在調試程序窗口中,將光標移動到需要添加斷點的行上,按一次F9鍵或單擊,當前行的背景色變為紅色,并且在窗口左邊界上標上紅色的圓點,當程序運行到斷點時就會暫停;

          運行調試:

          單擊繼續或按F5進行逐步運行調試;F10步進、F11步入,都可以繼續向下執行;將鼠標移動到變量名上時,會顯示變量當前時刻的值;或者在右側的“監視”窗格中可以觀察該變量的值;點擊變量信息框中的變量值或右側“監視”空格中的變量值可以修改變量的當前值;更多的調試操作:查看調用關系、監視特定變量的值等;

          // 示例
          var balance=200.0;    //
          var willPay=20.0;
          function pay(_balance, _pay){
              return _balance - _pay;
          }
          function showBalance(){
              debugger;
              var blnc=pay(balance,willPay);
              alert("當前余額:" + blnc);
          }
          showBalance();

          日志輸出:

          程序運行時,有些中間數據需要記錄,以便檢查程序運行的狀態;對于JavaScript記錄中間數據通常是以日志的形式記錄需要記錄的數據,再發送到服務器上保存起來;日志記錄的內容可以是任意的信息,根據開發者的需要而定;


          主站蜘蛛池模板: 亚洲欧洲无码一区二区三区| 中文字幕久久久久一区| 日韩精品一区在线| 久久久91精品国产一区二区三区 | 久久久久成人精品一区二区| 蜜桃传媒一区二区亚洲AV| 亚洲一区免费观看| 日韩精品无码一区二区三区AV| 内射一区二区精品视频在线观看| 亚洲综合一区无码精品| 精品一区二区三区在线观看视频| 性无码一区二区三区在线观看| 久久精品无码一区二区app| 亚洲日韩中文字幕无码一区| 亚洲成AV人片一区二区| 国产一区二区精品尤物| 视频一区二区中文字幕| 波多野结衣中文字幕一区二区三区| 性色AV一区二区三区天美传媒| 69久久精品无码一区二区| 国产香蕉一区二区精品视频| 蜜桃AV抽搐高潮一区二区| 免费高清av一区二区三区| 国产在线观看91精品一区| 高清一区高清二区视频| 亚洲AⅤ无码一区二区三区在线| 波多野结衣中文一区| 精品日韩在线视频一区二区三区 | 无码人妻久久一区二区三区免费丨| 性色A码一区二区三区天美传媒| 日韩内射美女人妻一区二区三区| 久久久久一区二区三区| 久久亚洲日韩精品一区二区三区| 亚洲一区二区三区亚瑟| 国产微拍精品一区二区| 亚洲片一区二区三区| 中文字幕一区二区三区在线不卡| 免费一区二区三区| 亚洲一区二区三区高清在线观看| 国产一区韩国女主播| 国产午夜精品一区二区三区不卡|