ECMAS:异常捕获处理
在JS中,一旦出现某个错误,接下来的JS代码都会停止执行,这样就显的代码非常的不健壮。如果对异常进行捕获处理,那么接下来的JS代码会继续执行。
JS 异常捕获机制
try catch
try {
console.log(app) // app 未定义
} catch (error) {
//
}
把不稳定代码放在 try 语句中。只要有一行代码出现问题,整个程序的执行流程就会立即调到 catch 语句中执行,而且这行出错代码后面的try中的其他语句都不会再执行。
在执行catch中的代码之前,JS引擎会首先根据错误类型自动创建一个错误,并通过catch后面的参数传递到catch中。不同的浏览器创建的error对象不一样,但是同创他们都包含一个message属性,值是这个错误的一些信息。
catch中的代码执行完毕之后,会继续执行后面的代码,程序不会停止下来。
finally
try {
console.log(app) // app 未定义
} catch (error) {
//
} finally {
//
}
在 try…catch 中,try 中一旦出现错误则其他语句不能执行,如果不出现错误则 catch 中的语句不会执行。JS参考其他编程语言,也提供了一种 finally 语句:不管 try 中的语句有没有错误,在最后都会执行 finally 中的语句。
需要注意的是:
在js中,如果添加了 finally 语句,则 catch 语句可以省略。但是没有 catch 语句,则一旦发生错误就无法捕获这个错误,所以在执行完 finally 中的语句后,程序就会立即停止了。 所以,在实际使用中,最好一直带着 catch 语句。
throw 语句
throw语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch块。如果调用者函数中没有catch块,程序将会终止。
语法
throw expression;
使用throw语句来抛出一个异常。当你抛出异常时,expression 指定了异常的内容。
抛出一个对象
你可以在抛出异常时指定一个对象。然后可以在catch块中引用对象的属性。以下示例创建一个类型为UserException的对象,并在throw语句中使用它。
function UserException(message) {
this.message = message;
this.name = "UserException";
}
function getMonthName(mo) {
mo = mo-1; // 调整月份数字到数组索引 (1=Jan, 12=Dec)
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
"Aug", "Sep", "Oct", "Nov", "Dec"];
if (months[mo] !== undefined) {
return months[mo];
} else {
throw new UserException("InvalidMonthNo");
}
}
try {
// statements to try
var myMonth = 15; // 15 超出边界并引发异常
var monthName = getMonthName(myMonth);
} catch (e) {
var monthName = "unknown";
console.log(e.message, e.name); // 传递异常对象到错误处理
}
在设计复杂程序时,需要对异常进行分类识别,这会变得非常有用。
重新抛出异常
你可以使用throw来抛出异常。下面的例子捕捉了一个异常值为数字的异常,并在其值大于50后重新抛出异常。重新抛出的异常传播到闭包函数或顶层,以便用户看到它。
try {
throw 100; // 抛出一个数值异常
} catch (e) {
if (e <= 50) {
// 异常在 1-50 之间时,直接处理
} else {
// 异常无法处理,重新抛出
throw e;
}
}
// Uncaught 100
Error 构造器
详细使用方法请参考 MDN Error 文档,这里不做赘述。
通过Error构造器可以创建一个错误对象,您可以抛出它并捕获,更牛逼的是您可以将它作为自定义异常的基础对象。
常用的属性
- Error.prototype.message 错误描述
- Error.prototype.name error类型的名称,初始值为"Error"
- Error.prototype.toString()
toString() 方法返回一个指定的错误对象(Error object)的字符串表示:
Error.prototype.toString = function()
{
"use strict";
var obj = Object(this);
if (obj !== this)
throw new TypeError();
var name = this.name;
name = (name === undefined) ? "Error" : String(name);
var msg = this.message;
msg = (msg === undefined) ? "" : String(msg);
if (name === "")
return msg;
if (msg === "")
return name;
return name + ": " + msg;
};
demo 演示
try {
var e = new Error("error msg");
e.name = "ParseError";
throw e;
} catch (e) {
console.log(typeof e); // object
console.log(e.name); // ParseError
console.log(e.message); // error msg
console.log(e); // Error: error msg \n at index.html:18
console.log(JSON.stringify(e)) // {"name":"ParseError"}, message 属性挂载在Error.prototype上的
}
var e = new Error("fatal error");
print(e.toString()); // "Error: fatal error"
e.name = undefined;
print(e.toString()); // "Error: fatal error"
e.name = "";
print(e.toString()); // "fatal error"
e.message = undefined;
print(e.toString()); // "Error"
e.name = "hello";
print(e.toString()); // "hello"
错误类型
所有的JS内置的错误类型都继承自 Error。
上图中 EvalError 继承了 Error,并且 EvalError.prototype.name = 'EvalError',其他错误类型也类似。
EvalError
创建一个error实例,表示错误的原因:与 eval() 有关。
InternalError
创建一个代表Javascript引擎内部错误的异常抛出的实例。 如: "递归太多".
RangeError
创建一个error实例,表示错误的原因:数值变量或参数超出其有效范围。
ReferenceError
创建一个error实例,表示错误的原因:无效引用。
SyntaxError
创建一个error实例,表示错误的原因:eval()在解析代码的过程中发生的语法错误。
TypeError
创建一个error实例,表示错误的原因:变量或参数不属于有效类型。
URIError
创建一个error实例,表示错误的原因:给 encodeURI()或 decodeURl()传递的参数无效。