【前言】
本文主要介紹下JS的Error name相關屬性.
當 JS 引擎執行 JS代碼時,會發生各種錯誤。
①語法錯誤,通常是程序員造成的編碼錯誤或錯別字;
②拼寫錯誤或語言中缺少的功能(可能由於瀏覽器差異);
③來自服務器或用戶的錯誤輸出而導致的錯誤;
④由於許多其他不可預知的因素;
當發生錯誤時,JS通常會停止並產生錯誤消息。技術術語是這樣描述的:JavaScript 將拋出異常(拋出錯誤)。JS實際上會創建一個Error對象,該對象帶有兩個屬性name和message。
【概念】
error指程序中的非正常運行狀態,在其他編程語言中稱為“異常”或“錯誤”。解釋器會為每個錯誤情形創建並拋出一個Error對象,其中包含錯誤的描述信息。
ECMAScript定義了六種類型的錯誤。除此之外,還可以使用Error構造方法創建自定義的Error對象,並使用throw語句拋出該對象。
ReferenceError(參考錯誤):找不到對象時
TypeError(類型錯誤):錯誤的使用了類型或對象的方法時
RangeError(范圍錯誤):使用內置對象的方法時,參數超范圍
SyntaxError(語法錯誤):語法寫錯了
EvalError(評估錯誤):錯誤的使用了Eval
URIError(url錯誤):URI錯誤
【錯誤處理】
即使程序發生錯誤,也保證不異常中斷的機制。
try{ 可能發生錯誤的代碼 }catch(err){ 只有發生錯誤時才執行的代碼 }finally{ 無論是否出錯,肯定都要執行的代碼 }
使用要點
- 使用try包裹的代碼,即使不出錯,效率也比不用try包裹的代碼低;
- 在try中,盡量少的包含可能出錯的代碼;
- 無法提前預知錯誤類型的錯誤,必須用try catch捕獲;
- finally可以省略;
【主體】
(1)Error對象
JS擁有當錯誤發生時提供錯誤信息的內置 error 對象,error 對象提供兩個有用的屬性:name 和 message。
(2)Error的name屬性值
(3)try 和 catch
try 用於定義在執行時進行錯誤測試的代碼塊,catch 語句定義當 try 代碼塊發生錯誤時,所執行的代碼塊。
catch 塊會捕捉到 try 塊中的錯誤,並執行代碼來處理它
注意:JS語句 try 和 catch 是成對出現的,否則會出現報錯。
翻譯為未捕獲的語法錯誤:缺少捕獲或最后嘗試
try與catch捕獲異常可以用於表單驗證,具體案例參見文章底部---→案例1
除此之外,日常面試也常遇到此類問題,具體參見文章底部---→案例練習2
(4)throw
拋出(throw)錯誤:當錯誤發生時,當事情出問題時,JavaScript 引擎通常會停止,並生成一個錯誤消息。描述這種情況的技術術語是:JavaScript 將拋出一個錯誤。
throw 語句允許創建自定義錯誤,從技術上講能夠拋出異常(拋出錯誤),異常可以是 JavaScript 字符串、數字、布爾或對象
throw "Too big"; // 拋出文本 throw 500; //拋出數字
如果把 throw 與 try 和 catch 一同使用,就可以控制程序流並生成自定義錯誤消息。
(5)通俗理解
①try
結果
try里面的代碼錯誤的時候會報錯,但是不會拋出錯誤,他不會執行錯誤的console.log(b);而是跳過,而且這個console.log(“c”);依然執行不出來,但是,后續的代碼還是會執行。在try里面發生錯誤,不會執行錯誤后的try里面的代碼。那catch什么意思呢?
②catch
結果
接下來對上面代碼稍作修改
結果
當try里面的代碼沒有錯誤的時候,catch里面的代碼是不會被執行的;當try里面的代碼沒有錯誤的時候,catch就負責把錯的給捕捉到,有一堆錯誤信息error(error是對象),系統會把錯誤信息(error.message error.name)封裝到一個error對象里面,然后把error對象傳到e里面,供拋出異常使用。
結果
接下來再稍作修改,再在catch外面加上一條錯誤的代碼
效果
catch就是負責捕捉錯誤的,捕捉錯誤到程序里面,就不會拋出到控制台里面,也就不會讓程序去終止。
如果try里面有兩個錯誤呢?
結果
這是因為到錯誤b他就停了,所以也就不會到c了。
(6)finally
finally 語句不論之前的 try 和 catch 中是否產生異常都會執行該代碼塊。
try { 供測試的代碼塊 } catch(err) { 處理錯誤的代碼塊 } finally { 無論 try / catch 結果如何都執行的代碼塊 }
(7)Error的name屬性值
接下來依次分析下各個屬性取值
①RefereError
非法引用錯誤,即引用未定義的變量或函數。
如果一個變量未經聲明就使用的話,就會RefereError;當一個函數未經聲明就調用,也會RefereError。
結果
②SyntaxError
語法錯誤,即標點符號使用錯誤
結果
翻譯為:未捕獲的語法錯誤:無效或意外的令牌
③EvalError
指示 eval() 函數中的錯誤。更新版本的 JavaScript 不會拋出任何 EvalError,利用SyntaxError 代替。
④RangeError
一般這種錯誤也是在遞歸函數當中出現,接下來先看一個簡單的,就可以明白這個問題出現的函數:
只要一運行這個函數,就會直接報上面的那個錯誤。原因:這就是因為一個函數一直遞歸調用自己,無法停止,只有在內存被塞滿(內存溢出)的時候,報錯才能夠停止。所以,有這個報錯,先檢查一下,是不是條件判斷有錯誤。
⑤TypeError
使用的值不在期望值的范圍之內,則拋出TypeError錯誤
⑥URIError
如果在 URI 函數中使用非法字符,則拋出URIError錯誤
(8)非標准的 Error 對象屬性
Mozilla 火狐和 Microsoft 微軟定義了非標准的 error 對象屬性:
- fileName (Mozilla)
- lineNumber (Mozilla)
- columnNumber (Mozilla)
- stack (Mozilla)
- description (Microsoft)
- number (Microsoft)
注意:它們並不會在所有瀏覽器中工作,所以要避免在公共網站使用這些非標准的Error對象屬性。
案例1:
<!DOCTYPE html> <html> <head> <title>es6</title> <style type="text/css"> *{ margin: 0;padding: 0; } .login_box{ width: 600px; height: auto; margin: 100px auto; border: 1px solid black; } .user_info{ width: 100%; height: auto; padding: 10px; box-sizing: border-box; } .user_info i{ font-size: 14px; color: red; margin-left: 10px; } .user_info>input{ width: 360px; height: 30px; text-align: left; padding-left: 10px; } .login_box>input{ width: 30%; height: 30px; display: block; margin: 10px auto; } </style> </head> <body> <form class="login_box"> <div class="user_info"> 賬號:<input type="text" name="user_name" placeholder="請輸入賬號"><i></i> </div> <div class="user_info"> 密碼:<input type="password" name="user_pwd" placeholder="請輸入密碼"><i></i> </div> <input type="submit" value="登錄"></submit> </form> <script type="text/javascript"> var user_name = document.querySelector('input[name="user_name"]'); var user_pwd = document.querySelector('input[name="user_pwd"]'); var user_submit = document.querySelector('input[type="submit"]'); var login_box = document.querySelector('.login_box'); /* 賬號驗證 */ user_name.addEventListener('blur',user_name_test,false); function user_name_test(){ user_name.nextElementSibling.innerHTML = ''; try { const name = user_name.value.replace(/ /g,'');/*g表示過濾全部空格*/ if(name == ''){ throw '賬號為空'; return false; }else if(name.length >= 11){ throw '最大長度為11'; return false; }else{ return true; } }catch(error){ user_name.nextElementSibling.innerHTML = error; } } /* 密碼驗證 */ user_pwd.addEventListener('blur',user_name_pwd,false); function user_name_pwd(){ user_pwd.nextElementSibling.innerHTML = ''; try { const pwd = user_pwd.value.replace(/ /g,'');/*g表示過濾全部空格*/ if(pwd == ''){ throw '密碼為空';return false; }else if(pwd.length < 6){ throw '最短為6位';return false; }else if(pwd.length >= 10){ throw '最長為10位';return false; }else{ return true; } }catch(error){ user_pwd.nextElementSibling.innerHTML = error; } } /* 表單提交 */ user_submit.addEventListener('click',function(event){ const user_name = user_name_test(); const user_pwd = user_name_pwd(); if(user_name&&user_pwd){ login_box.submit(function(event) { /* Act on the event */ }); }else{ event.preventDefault();/*禁止表單提交*/ } },false); </script> </body> </html>
效果:
案例2:
案例練習2:
面試題1: var n = 1; function fun(){ try{ n++; return n; }catch(err){ // 沒錯誤,catch不執行 n++; return n; }finally{ n++; return n; } } console.log(fun());// 3 return為finally的 console.log(n);// 3 面試題2: var n = 1; function fun(){ try{ n++; return n; }catch(err){ // 沒錯誤,catch不執行 n++; return n; }finally{ n++; } } console.log(fun()); // 2 return為try的 console.log(n); // 3 面試題3: var n = 1; function fun(){ try{ n++; n += m; //出錯 return n; }catch(err){ n++; return n; }finally{ n++; } } console.log(fun()); // 3 return為catch的 console.log(n); // 4
.