调试JavaScript确实是一件痛苦的事,但现在有很多工具方便调试工作(比如:Firefox的Firebug),更方便准确的查看错误信息。然而,最新的ECMAScript添加了导演处理机制,采用了从Java中移植过来的模型。ECMAScritp中一些保留字实现了try……catch……finally结构及throw操作符。好的错误处理技术可以让脚本的开发、调试和部署更流畅。
(一)错误和异常
谈论起编程中的错误时,需要关心两类主要错误:语法错误和运行时错误。语法错误,也称为解析错误,发生在传统编程语言的编译时,在JavaScript中发生在解释时。这些错误是由代码中的意外字符直接造成的,然后就不能完全编译/解释。发生语法错误时,就不能继续执行代码。在JavaScript中,只有在同一个线程中的代码会受语法错误的影响。在其他线程中的代码和其他外部引用的文件中的代码,如果 不依赖于包含错误的代码 ,则可以继续执行。
运行时错误,也称为异常(在编译期/解释期后)。此时,问题并不出在代码的语法上,而是,尝试完成的一个操作,在某些情况下是非法的。例如,访问window对象一个没有的方法。异常只影响它们发生的线程,其他JavaScript线程则可继续正常的执行。
(二)错误报告
因为每个浏览器都有自己的内置JavaScript解释程序(包含它自己的错误跟踪机制),所以每种浏览器报告错误的方式都不同:有些是弹出错误信息,有些是仅把信息记录在Javascript控制台中。
(三)处理错误
JavaScript提供了两种特别的处理错误的方法。BOM包含一个onerror事件处理函数,这在window对象和图像对象上都有,同时ECMAScript定义了另一个从Java中借过来的try……catch……结构来处理异常。
1、onerror事件处理函数
onerror事件处理函数是第一个用来协助JavaScript处理错误的机制,页面上出现异常时,
error事件便在window对象上触发。onerror事件处理函数提供了三种信息来确定错误确切的性质:错误信息——对于给定错误,浏览器会显示同样的信息;URL——在哪个文件中发生了错误;行号——给定URL中发生错误的行号,这三个信息将作为三个参数传递给onerror事件处理函数。
2、图像载入错误
当一个图像由于某种原因未能成功载入时(例如,文件不存在),error事件便在这个图像上触发。如果要通过脚本来分配事件处理函数,在图像的src特性前,必须等待页面完全载入。与window对象的onerror事件处理函数不同,image的onerror事件处理函数没有任何关于额外信息的参数。
3、处理语法错误
onerror事件处理函数不仅可以处理异常,它还能处理语法错误,也只有它才能处理。
事件处理函数必须是页面中第一个出现的代码,因为如果错误出现在设置事件处理函数之前,事件处理函数就没用了。例如:
<html>
<title>错误处理例子</title>
<script type=”text/javascript”>
alert(“语法错误:”;
window.onerror=function(sMessage,sUrl,sLine){
alert(“错误发生在:\n”+sMessage+”\n文件名:”+sUrl+”\n行号:”+sLine);
}
</script>
<body onload=”nonExistentFunction()”>
</body>
</html>
在JS代码中,第一行代码(里面有语法错误)在分配onerror事件处理函数之前就出现了,所有浏览器直接报告这个错误。在错误之后的所有代码就不再被解释(因为这个线程已经退出了),所有onload事件触发时调用nonExistentFunction(),浏览器也报告这个错误。 使用onerror事件处理函数的主要问题是:它是BOM的一部分,所以,没有任何标准能控制它的行为。因此,不同的浏览器使用这个事件处理函数处理错误的方式明显的不同。例如,在IE中发生error事件时,正常的代码会继续执行,所有的变量和数据都保留下来,并可通过onerro事件处理函数访问。然而,在其他浏览器中,正常的代码执行都会结束,同时,所有的错误发生之前的变量和数据都被销毁。
4、try……catch语句
try{
//执行代码
[break;]
}catch([exception]){
//如果一个异常发生并且匹配
[break;]
}[finally{
//无论是否有异常都会执行的代码,这个对关闭打开的链接和释放资源很有用
}]
运行try……catch语句时,解释程序首先进入try关键词后的代码块,如果产生错误,解释程序立刻跳出try子句中,进入catch子句。与Java不同,ECMAScript标准在try……catch语句中指定只能有一个cathc子句。因为JavaScript是弱类型的语言,没办法指明catch子句中异常的特定类型,不管错误是什么类型,都由一个catch子句处理。 1)嵌套的try……catch语句
在try……catch语句中的catch子句中,也有可能会发生错误,此时,就可以使用嵌套的try……catch语句。
5、Error对象
那么catch语句捕获的到底是什么呢?类似于JavaScript有个可用于抛出的基类Exception ,JavaScript有个Erro基类用于抛出,Error对象有以下特性:name——表示错误类型的字符串;message——实际的错误信息。Error对象的名称对应于它的类(因为Error只是一个基类),可以是以下值之一:
类 | 发生原因 |
EvalError | 错误发生在eval()函数中 |
RangeError | 数字的值超出JavaScript可表示的范围(Number.MIN_VALUE和Number.MAX_VALUE) |
ReferenceError | 使用了非法的引用 |
SyntaxError | 在eval()函数调用中发生了语法错误,其他的语法错误由浏览器报告,无法通过try……catch语句处理 |
TypeError | 变量的类型不是预期所需的 |
URLError | 在encodeURI或者decodeURI函数中发生了错误 |
6、判断错误类型
第一种方法使用Error对象的name特性:
try{
eval(“a ++ b”)
}catch(oException){
if(oException.name == “SyntaxError”){
alert(“语法错误:”+oException.message);
}else{
alert(“异常发生在:” +oException.message);
}
}
第二种方法使用instanceof操作符,并使用不同错误的类名,,其必须是if语句中的最后一个条件,因为所有其他的错误类都继承于它。
try{
eval(“a ++ b”)
}catch(oException){
if(oException instanceof SyntaxError”){
alert(“语法错误:”+oException.message);
}else{
alert(“异常发生在:” +oException.message);
}
}
7、抛出异常
ECMAScript第三版还引入了throw语句,用于有目的地抛出异常。语法如下:
throw error_object;
error_object可以是字符串、数字、布尔值或者是实际的对象,也可以抛出一个Error对象。Error对象的构造函数只有一个参数,错误信息,其他的Error子类也可以使用,如下: throw “一个异常发生”;
throw 5210;
throw true;
throw new Object();
throw Error(“类型错误”);
throw new RangeError(“数据超出范围”);