JavaScript 異常(例外)處理
閱讀目錄
1. 錯誤VS異常
2. 術語:JS丟擲錯誤
3. JS異常型別
3.1 程式碼錯誤
3.2 執行錯誤
4. JS異常的載體
4.1 Error物件
4.2 Error的子類(6)
5. JS異常捕獲(監控)方法
5.1 window.onerror
5.2 try…catch…finally中的catch
5.3 二者區別
6. JS異常處理方法
6.1 定義
6.2 優點
6.3 try…catch…finally方法
1. 錯誤VS異常
錯誤(error):
A)非正常的系統級的嚴重錯誤,出現後程序直接終止的,為不可預見的;
B)程式執行時不滿足某些條件而出現非嚴重錯誤,即異常(exception)。
2. 術語:JS丟擲錯誤
JS丟擲錯誤:俗稱“報錯”,即當錯誤發生時,當事情出問題時,JavaScript 引擎通常會停止,並生成一個錯誤訊息。
3. JS異常型別
3.1 程式碼(編譯)錯誤
A)語法錯誤(SyntaxError):
eg:拼寫錯誤。
該錯誤下,瀏覽器會直接報錯,整個程式碼都不會執行。
B)範圍錯誤(RangeError):
該錯誤下,錯誤之前的程式碼會執行,之後程式碼不會執行。
C)引用錯誤(ReferenceError):
該錯誤下,錯誤之前的程式碼會執行,之後程式碼不會執行。
D)型別錯誤(TypeError):
該錯誤下,錯誤之前的程式碼會執行,之後程式碼不會執行。
3.2 執行錯誤:
A)執行錯誤(runtime error):
eg:系統資源不可用(記憶體分配失敗,檔案開啟失敗,資料庫開啟失敗等)
B)邏輯錯誤(bug):
eg:程式控制不當(除數為0;負數開方等)
4. JS異常的載體
4.1 Error物件
name屬性表示例外的型別;
message屬性表示例外的含義。
4.2 Error的子類(6)
A)Error:基型別。即:所有的錯誤都繼承該型別。提供這個基型別的主要目的是提供給開發人員丟擲自定義的錯誤。
eg:throw new Error(輸出錯誤資訊)。
B)SyntaxError:語法錯誤。即:解析錯誤。
eg:var 1a;
顯示:Uncaught SyntaxError: Unexpected number
C)RangeError: 範圍錯誤。即:數字超出有效範圍會丟擲該錯誤。
eg:var a= new Array(-1);
顯示:Uncaught RangeError: Invalid array length
D)ReferenceError:引用錯誤。即:在找不到物件會丟擲錯誤。
a)引用了一個不存在的變數
eg: console.log(a);
顯示:Uncaught ReferenceError: a is not defined
b)將變數賦值給一個無法被賦值的物件
eg:console.log()= 1;
顯示:Uncaught ReferenceError: Invalid left-hand side in assignment
E)TypeError:型別錯誤。通常在if控制流中和全等,相等的比較中存在型別轉換。
a)變數或引數不是預期型別,比如,對字串、布林值、數值等原始型別的值使用new命令,就會丟擲這種錯誤,因為new命令的引數應該是一個建構函式。
eg: var a= new 123;
顯示:Uncaught TypeError: 123 is not a function
b)呼叫物件不存在的方法
eg:var a;a.aa();
顯示:Uncaught TypeError: Cannot read property ‘aa’ of undefined
F)EvalError:eval錯誤。即:未恰當使用eval()函式會丟擲該錯誤。例如未將eval當作函式使用。
eg:new eval()。
G)URLError:url錯誤。即:使用與url相關函式引數不正確。
主要是encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()這六個函式。這種型別不常見。
eg: decodeURI(’%2’)
顯示:Uncaught URIError: URI malformed
5. JS異常捕獲(監控)方法
5.1 window.onerror
windowonerror = function(message, source, lineno, colno, error) { ... }
message: Uncaught ReferenceError: test is not defined //異常基本資訊
source: http://test.com/release/attach.js //發生異常Javascript檔案url
lineno: 16144 //發生錯誤的行號
colno: 6
error: ReferenceError: test is not defined
at http://test.com/release/attach.js:16144:6
at HTMLDocument.<anonymous> (http://test.com/release/vendor.js:654:71) // error.stack獲取異常的堆疊資訊
5.2 try…catch…finally中的“catch”
try{
... //異常的丟擲
}
catch(e){
... //異常的捕獲與處理
}
finally{
... //結束處理
}
5.3 二者區別
window.onerror
優點:全域性監控
缺點:相容性問題導致不一定拿到出錯資訊,有些瀏覽器出於安全方面的考慮,對於不同域的Javascript檔案,通過window.onError無法獲取有效的錯誤資訊。
eg:firefox的錯誤訊息只有Script error,而且無法獲得確切的行號,更沒有錯誤堆疊資訊。
try…catch…finally
優點:可拿到出錯資訊
缺點:區域性監控,無法監控語法錯誤,僅監控執行錯誤。
6. JS異常處理方法(例外處理)
6.1 定義
當JavaScript程式在執行中發生了諸如陣列索引越界、型別不匹配或者語法錯誤時,JavaScript直譯器就會引發例外處理(exception handlers)。
6.2 優點
通過運用例外處理技術,我們可以實現用結構化的方式來響應錯誤事件的發生,讓例外處理程式碼與正常指令碼程式碼科學分離,最終使我們能夠集中精力編寫完成主要功能的核心程式。
6.3 try…catch…finally方法
A)基本語法
try{
... //異常的丟擲
}
catch(e){
... //異常的捕獲與處理
}
finally{
... //結束處理
}
首先執行try塊中的語句,如果執行中發生了錯誤,控制就會轉移到位於catch塊中語句。
其中括號中的error引數被作為例外變數傳遞。
否則,catch塊的語句被跳過不執行。
無論是發生錯誤時catch塊中的語句執行完畢,或者沒有發生錯誤try塊中的語句執行完畢,最後將執行finally塊中的語句。
B)捕獲內容
a)js原生錯誤型別的例外(Error6子類)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>exception handlers-error</title>
<script>
var txt = "";
function message(){
try{
var x = document.getElementById("demo").value;
}
catch(e){
// \n\n表示換行 +=:=用於賦值,+用於加值。
//x+=y等價於x=x+y。
txt+= "Error description:"+ e.message + "\n\n";
//錯誤表述為
//Uncaught TypeError: 型別錯誤
//Cannot read property 'value' of null未能找到demo值
txt+= "Click OK to continue.\n\n";
//點選確認繼續
//alert()方法:顯示制定訊息與一個OK按鈕警告框。
alert(txt);
}
finally{
var z=document.getElementById("msg");
z.innerHTML="have fun.";
}
}
</script>
</head>
<body>
<input type="button" value="View message" onclick="message()">
<p id="msg"></p>
</body>
</html>
b)執行throw語句產生的例外(throw自定義錯誤)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>exception handlers-throw</title>
<script>
function myFunction(){
try{
var x=document.getElementById("demo").value;
if(x=="") throw "empty";
if(isNaN(x)) throw "not a number";
if(x>10) throw "too large";
if(x<5) throw "too small";
}
catch(err){
var y=document.getElementById("mess");
y.innerHTML="Error: " + err + ".";
}
finally{
var z=document.getElementById("msg");
z.innerHTML="have fun.";
}
}
</script>
</head>
<body>
<p>Please input a number between 5 and 10:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">Test Input</button>
<p id="mess"></p>
<p id="msg"></p>
</body>
</html>
C)捕獲方式
a)條件捕獲catch(e instanceof obj)
用 instanceof 判斷異常的物件型別,實現指定的異常處理方式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>條件捕獲</title>
<script>
var txt = "";
function myfunction(){
try{
// new Array(-1);
// decodeURI('%2');
var x = document.getElementById("demo").value;
//執行順序:要麼RangeError,要麼URIError,要麼TypeError,要麼else,4選1。
}
catch(e) {
if (e instanceof RangeError) {
alert(e.name + "是" + e.message);
}
else if (e instanceof URIError) {
alert(e.name + "為" + e.message);
}
else if (e instanceof TypeError) {
alert(e.name + ":" + e.message);
}
else{
txt += "All error:"+ e.message;
alert(txt);
}
}
}
</script>
</head>
<body>
<input type="button" value="View myfunction" onclick="myfunction()">
</body>
</html>
b)非條件捕獲catch(e)
當異常丟擲時,無論異常的型別都進行捕獲並處理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>非條件捕獲</title>
<script>
var txt = "";
function myfunction(){
try{
// new Array(-1);
// decodeURI('%2');
//無論哪種錯誤都會捕獲;
var x = document.getElementById("demo").value;
}
catch(e) {
txt += "All error:"+ e.message;
alert(txt);
}
}
</script>
</head>
<body>
<input type="button" value="View myfunction" onclick="myfunction()">
</body>
</html>
注:
- 如果條件捕獲和非條件捕獲共用,那麼非條件捕獲必須放在最後,因為它是無條件的捕獲型別,捕獲後會忽略後面的任意 catch 塊。
- 對異常的處理必須考慮周全,在 catch 裡要麼處理所有的異常,要麼再次丟擲異常(假定外層還有異常處理),否則在除錯過程中會非常困難,因為出現的異常被忽略了。
D)變形
a)try…catch結構
當沒有例外發生執行完畢try塊語句後或者發生例外執行完catch塊語句後,控制將轉移到整個try…catch結構後面的語句。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>try...catch</title>
<script>
try {
document.writeln("Beginnng the try block" + "<br>");
var x = document.getElementById("demo").value;
document.writeln("Finished the try block with no exceptions")
}
catch(err) {
document.writeln("錯誤: " + err.name + "<br>")
document.writeln("錯誤內容: " + err.message + "<br>")
}
document.writeln("Executing after the try-catch statement" + "<br>")
</script>
</head>
<body>
</body>
</html>
b)try…finally結構
當執行完畢try塊語句後無論有無例外,控制將轉移到finally語句,這種結構在實際應用中很少見。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>try...finally</title>
<script>
try {
document.writeln("Beginnng the try block" + "<br>");
var x = document.getElementById("demo").value;
document.writeln("Finished the try block with no exceptions")
}
finally{
document.writeln("Executing after the try-catch statement" + "<br>")
}
</script>
</head>
<body>
</body>
</html>
E)巢狀例外處理
JavaScript支援多層次的巢狀例外處理。一般情況下,我們可以在內部例外處理的catch程式碼塊中捕捉並處理錯誤,然後再次觸發例外,這樣就可進一步在外部例外處理的catch程式碼塊中做更加深入的處理。
優點:能夠很好地分階段處理錯誤,內部例外處理可以負責解決由錯誤引發的指令碼程式碼問題,外部例外處理則用於負責提供給使用者的反饋資訊或者對例外資訊進行日誌記錄。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>巢狀例外處理</title>
<script>
var inner;
var outer;
try {
document.writeln("Beginning outer try block, no exceptions yet" + "<br>");
try {
document.writeln("Beginning inner try block, no exceptions yet" + "<br>");
// 生成一個引用錯誤
document.writeln(undefinedVariable)
document.writeln("Finished inner try block with no exceptions" + "<br>");
}
catch(inner) {
// 內部例外處理
document.writeln("Exception caught, beginning inner catch block" + "<br>");
document.writeln("錯誤型別: " + inner.name + "<br>");
document.writeln("錯誤資訊: " + inner.message + "<br>");
throw inner;
document.writeln("No exceptions thrown in inner catch block" + "<br>");
}
finally {
document.writeln("Executing inner finally block" + "<br>");
}
document.writeln("Finished outer try block with no exceptions" + "<br>");
}
catch(outer) {
// 外部例外處理
document.writeln("Exception caught, beginning outer catch block" + "<br>");
document.writeln("Error type: " + outer.name + "<br>");
document.writeln("Error message: " + outer.message + "<br>");
}
finally {
document.writeln("Executing outer finally block" + "<br>");
}
</script>
</head>
<body>
</body>
</html>
歡迎各位JS大神指正。