錯誤處理機制
一皆看、Error實例對象
- JavaScript 解析或運行時悯辙,一旦發(fā)生錯誤帆阳,引擎就會拋出一個錯誤對象。JavaScript 原生提供Error構造函數(shù)氨距,所有拋出的錯誤都是這個構造函數(shù)的實例桑逝。
-
Error
實例對象必須有message
屬性,表示出錯時的提示信息俏让。Error
實例還提供name
和stack
屬性楞遏,分別表示錯誤的名稱和錯誤的堆棧。但它們是非標準的首昔,不是每種實現(xiàn)都有寡喝。
message
:錯誤提示信息
name
:錯誤名稱(非標準屬性)
stack
:錯誤的堆棧(非標準屬性)
Error的六個派生對象:
SyntaxError
對象(語法錯誤)
SyntaxError
對象是解析代碼時發(fā)生的語法錯誤。ReferenceError
對象(引用錯誤)
ReferenceError
對象是引用一個不存在的變量時發(fā)生的錯誤勒奇。
例如:將一個值分配給無法分配的對象预鬓,比如對函數(shù)的運行結果或者this
賦值。RangeError
對象(引用錯誤)
RangeError
對象是一個值超出有效范圍時發(fā)生的錯誤
主要有幾種情況赊颠,一是數(shù)組長度為負數(shù)格二,二是Number
對象的方法參數(shù)超出范圍,以及函數(shù)堆棧超過最大值竣蹦。TypeError
對象(類型錯誤)
TypeError
對象是變量或參數(shù)不是預期類型時發(fā)生的錯誤
例如: 對字符串顶猜、布爾值、數(shù)值等原始類型的值使用new命令URIError
對象(編碼錯誤)
URIError
對象是URI
相關函數(shù)的參數(shù)不正確時拋出的錯誤EvalError
對象(全局錯誤)
eval函數(shù)沒有被正確執(zhí)行時草添,會拋出EvalError錯誤驶兜。該錯誤類型已經(jīng)不再使用了,只是為了保證與以前代碼兼容远寸,才繼續(xù)保留抄淑。
以上這6種派生錯誤,連同原始的Error對象驰后,都是構造函數(shù)肆资。開發(fā)者可以使用它們,手動生成錯誤對象的實例灶芝。這些構造函數(shù)都接受一個參數(shù)郑原,代表錯誤提示信息(message)。
二夜涕、throw 語句
throw
語句的作用是手動中斷程序執(zhí)行犯犁,拋出一個錯誤。
if (x <= 0) {
throw new Error('x 必須為正數(shù)');
}
// Uncaught ReferenceError: x is not defined
throw
拋出的錯誤就是它的參數(shù)女器,這里是一個Error實例酸役。
throw
可以拋出任何類型的值。也就是說,它的參數(shù)可以是任何值涣澡。
// 拋出一個字符串
throw 'Error贱呐!';
// Uncaught Error!
// 拋出一個數(shù)值
throw 42;
// Uncaught 42
// 拋出一個布爾值
throw true;
// Uncaught true
// 拋出一個對象
throw {
toString: function () {
return 'Error!';
}
};
// Uncaught {toString: ?}
對于 JavaScript 引擎來說入桂,遇到throw語句奄薇,程序就中止了
三、try...catch結構
- 一旦發(fā)生錯誤抗愁,程序就中止執(zhí)行了馁蒂。JavaScript 提供了
try...catch
結構,允許對錯誤進行處理驹愚,選擇是否往下執(zhí)行远搪。 - try語句包含了由一個或者多個語句組成的try塊, 和至少一個
catch
子句或者一個finally
子句的其中一個,或者兩個兼有逢捺。 - 三種形式的
try
聲明:
1.try...catch
try...finally
try...catch...finally
try {
throw new Error('出錯了!');
} catch (e) {
console.log(e.name + ": " + e.message);
console.log(e.stack);
}
// Error: 出錯了!
// at <anonymous>:3:9
// ...
-
catch
子句包含try
塊中拋出異常時要執(zhí)行的語句谁鳍。即:想讓try
語句中的內(nèi)容成功, 如果沒成功劫瞳,想控制接下來發(fā)生的事情倘潜,這時可以在catch
語句中實現(xiàn)。 如果在try
塊中有任何一個語句(或者從try
塊中調(diào)用的函數(shù))拋出異常志于,控制立即轉向catch
子句涮因。如果在try
塊中沒有異常拋出,會跳過catch
子句伺绽。 -
catch
代碼塊捕獲錯誤之后养泡,程序不會中斷,會按照正常流程繼續(xù)執(zhí)行下去奈应。 -
catch
代碼塊之中澜掩,還可以再拋出錯誤,甚至使用嵌套的try...catch
結構杖挣。
var n = 100;
try {
throw n;
} catch (e) {
if (e <= 50) {
// ...
} else {
throw e;
}
}
// Uncaught 100
-
catch
接受一個參數(shù)肩榕,表示try
代碼塊拋出的值。 -
catch
代碼塊之中可以加入判斷語句if...else
惩妇。用于判斷錯誤類型株汉,進行不同的處理。
try {
foo.bar();
} catch (e) {
if (e instanceof EvalError) {
console.log(e.name + ": " + e.message);
} else if (e instanceof RangeError) {
console.log(e.name + ": " + e.message);
}
// ...
}
-
finally
子句在try
塊和catch
塊之后執(zhí)行但是在下一個try
聲明之前執(zhí)行歌殃。無論是否有異常拋出或捕獲它總是執(zhí)行乔妈。
四、finally 代碼塊
-
ry...catch
結構允許在最后添加一個finally
代碼塊氓皱,表示不管是否出現(xiàn)錯誤褒翰,都必需在最后運行的語句贮懈。
function cleansUp() {
try {
throw new Error('出錯了……');
console.log('此行不會執(zhí)行');
} finally {
console.log('完成清理工作');
}
}
cleansUp()
// 完成清理工作
// Uncaught Error: 出錯了……
// at cleansUp (<anonymous>:3:11)
// at <anonymous>:10:1
上面代碼中,由于沒有catch
語句塊优训,一旦發(fā)生錯誤,代碼就會中斷執(zhí)行各聘。中斷執(zhí)行之前揣非,會先執(zhí)行finally
代碼塊,然后再向用戶提示報錯信息躲因。
function idle(x) {
try {
console.log(x);
return 'result';
} finally {
console.log('FINALLY');
}
}
idle('hello')
// hello
// FINALLY
上面代碼中早敬,try
代碼塊沒有發(fā)生錯誤,而且里面還包括return語句大脉,但是finally
代碼塊依然會執(zhí)行搞监。而且,這個函數(shù)的返回值還是result
镰矿。
-
return
語句的執(zhí)行是排在finally
代碼之前琐驴,只是等finally
代碼執(zhí)行完畢后才返回。 - 下面是finally代碼塊用法的典型場景秤标。
openFile();
try {
writeFile(Data);
} catch(e) {
handleError(e);
} finally {
closeFile();
}
上面代碼首先打開一個文件绝淡,然后在try
代碼塊中寫入文件,如果沒有發(fā)生錯誤苍姜,則運行finally
代碼塊關閉文件牢酵;一旦發(fā)生錯誤,則先使用catch
代碼塊處理錯誤衙猪,再使用finally
代碼塊關閉文件馍乙。
-
try...catch...finally
這三者之間的執(zhí)行順序,例:
function f() {
try {
console.log(0);
throw 'bug';
} catch(e) {
console.log(1);
return true; // 這句原本會延遲到 finally 代碼塊結束再執(zhí)行
console.log(2); // 不會運行
} finally {
console.log(3);
return false; // 這句會覆蓋掉前面那句 return
console.log(4); // 不會運行
}
console.log(5); // 不會運行
}
var result = f();
// 0
// 1
// 3
result
// false
上面例子中catch
代碼塊結束執(zhí)行之前,會先執(zhí)行finally
代碼塊垫释。