
1 Error及其派生对象
1.1 Error对象
JavaScript在解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript原生提供了Error构造函数,所抛出的错误都是Error构造函数的实例。
var err=new Error('出错了');
err.message
以上示例中,参数为message 属性,这个参数是必须的。除此之外,还提供了name (错误名称)属性和stack (错误的堆栈)属性,但这两个属性是非标准的,不是每种实现都有。
1.2 Error派生对象
Error实例对象是最一般的错误类型,在此基础上JavaScript还定义了6种错误类型:
-
SyntaxError :解析代码时的语法错误。 -
ReferenceError :引用一个不存在的变量时发生的错误。 -
RangeError :一个值超出有效范围时发生的错误。 -
TypeError :变量或参数不是预期类型时发生的错误。 -
URIError :URI 相关函数的参数不正确时抛出的错误。主要涉及encodeURI() 、decodeURI() 、encodeURIComponent() 、decodeURIComponent() 、escape() 和unescape() 这六个函数。 -
EvalError :eval 函数没有被正确执行时抛出的错误。
针对以上6种派生对象,我们都可以通过new 关键字手动生成错误对象的实例。同样地,message 也是必要参数。
2 自定义错误
除了以上的原生提供的错误对象,我们还可以自定义错误对象。代码实现如下:
function MyError(message){
this.message="...";
this.name="...";
}
MyError.prototype=new Error();
MyError.prototype.constructor=MyError;
然后我们就可以通过new 关键字来新建自定错误对象了。
3 错误处理
-
throw 语句:手动中断程序执行,抛出一个错误(自定义错误也可以)。 -
try...catch 结构:try 代码块中的错误会被catch 代码块捕获处理。如果不确定某些代码是否会报错,就可以把它们放在try...catch 代码块之中。 举个例子:
注:catch 代码块之中,还可以再抛出错误,甚至使用嵌套的try...catch 结构。
try {
throw "出错了";
} catch (e) {
console.log(111);
}
console.log(222);
输出结果为: 111
222
分析:从运行结果看,程序没有中断执行,并且继续向下执行完毕。 另外为了捕获不同类型的错误,从而进行不同的处理,也可以在catch 块中加入判断语句: try {
} 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 结构允许在最后添加一个finally 代码块,表示不管是否出现错误,都必需在最后运行的语句。
-
来看一个典型的应用场景:首先打开一个文件,然后在try 代码块中写入文件,如果没有发生错误,则运行finally 代码块关闭文件;一旦发生错误,则先使用catch 代码块处理错误,再使用finally 代码块关闭文件。 openFile();
try {
writeFile(Data);
} catch(e) {
handleError(e);
} finally {
closeFile();
}
-
再举个例子:没有catch 块,try 块中有抛出错误。 function cleansUp() {
try {
throw new Error('出错了……');
console.log('此行不会执行');
} finally {
console.log('完成清理工作');
}
}
cleansUp()
运行结果如下:显然,在中断执行前首先执行了finally 块,然后再抛出的错误信息。 完成清理工作
Uncaught Error: 出错了……
at cleansUp (<anonymous>:3:11)
at <anonymous>:10:1
-
再来看一个例子:分析一下return 语句与finally 块的执行顺序。 var count = 0;
function countUp() {
try {
return count;
} finally {
++count;
}
}
countUp()
count
分析:虽然try 块中有return 语句,但还是运行了finally 代码块,而且return 语句执行是在finally 块之前的,只是等finally 块执行完毕后才返回的。 -
try...catch...finally 结构:
-
直接举个例子来看这三者之间的执行顺序: function f() {
try {
console.log(0);
throw 'bug';
} catch(e) {
console.log(1);
return true;
console.log(2);
} finally {
console.log(3);
return false;
console.log(4);
}
console.log(5);
}
var result=f();
result
从运行结果看:catch 代码块结束执行之前,一遇到return 语句,就会先执行finally 代码块,由于return false 语句,因此就直接返回了,不再会回去执行catch 代码块剩下的部分了。 -
再举个例子:catch 块中有throw 语句,如下例子所示: function f() {
try {
throw '出错了!';
} catch(e) {
console.log('捕捉到内部错误');
throw e;
} finally {
return false;
}
}
f()
运行结果为: 捕捉到内部错误
分析:进入catch 代码块之后,一遇到throw 语句,就会去执行finally 代码块,其中有return false 语句,因此就直接返回了,不再会回去执行catch 代码块剩下的部分了。
总结:throw 语句和return 语句都会触发finally 块的执行。
|