背景:JavaScript在错误处理调试上一直是它的软肋,如果脚本出错,给出的提示经常也让人摸不着头脑。ECMAScript第3版为了解决这个问题引入了 try...catch和 throw语句以及一些错误类型,让开发人员更加适时的处理错误。良好的错误处理机制可以及时的提醒用户,知道发生了什么事,而不会惊慌失措。为此,作为开发人员,我们必须理解在处理 JavaScript错误的时候,都有哪些手段和工具可以利用。
### 一、错误处理
1、try...catch语句
~~~
try{ //尝试着执行try包含的代码
<span style="white-space:pre"> </span>window.abcdefg(); //不存在的方法
}catch(e){ //如果有错误, 执行catch, e是异常对象
alert('发生错误啦,错误信息为: '+e); //直接打印调用toString()方法
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89e199b4.jpg)
e对象中, ECMA-262还规定了两个属性: message和name,分别打印出信息和名称。
~~~
try{ //尝试着执行try包含的代码
window.abcdefg(); //不存在的方法
}catch(e){ //如果有错误, 执行catch, e是异常对象
alert('错误名称: '+e.name); //错误名称
alert('错误信息: '+e.message); //错误信息
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89e2b211.jpg)
![](https://box.kancloud.cn/2016-03-28_56f8f89e4f0b2.jpg)
PS:Opera9之前的版本不支持这个属性。并且IE提供了和message完全相同的description属性、还添加了number属性提示内部错误数量。Firefox提供了fileName(文件名)、lineNumber(错误行号)和stack(栈跟踪信息)。 Safari添加了line(行号)、sourceId(内部错误代码)和sourceURL(内部错误URL)。所以, 要跨浏览器使用,那么最好只使用通用的message。
2、finally子句
finally语句作为try-catch的可选语句,不管是否发生异常处理, 都会执行。并且不管try或是catch里包含return语句,也不会阻止finally执行。
~~~
try{
window.abcdefg();
}catch(e){
alert('发生错误啦,错误信息为: '+e.stack);
}finally{ //总是会被执行
alert('我都会执行! ');
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89e5ebb6.jpg)
![](https://box.kancloud.cn/2016-03-28_56f8f89e6fea2.jpg)
PS:finally的作用一般是为了防止出现异常后,无法往下再执行的备用。也就是说,如果有一些清理操作, 那么出现异常后,就执行不到清理操作, 那么可以把这些清理操作放到finally里即可。
### 二、错误显示类型
执行代码时可能会发生的错误有很多种。每种错误都有对应的错误类型, ECMA-262定义了7种错误类型:
1)Error
2)valError
3)RangeError(范围)
~~~
try{
<span style="white-space:pre"> </span>new Array(-5);
}catch(e){
<span style="white-space:pre"> </span>alert('发生错误啦,错误信息为: '+e);
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89e7ded2.jpg)
4)ReferenceError(引用)
~~~
try{
var box = a;
}catch(e){
alert('发生错误啦,错误信息为: '+e);
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89e8e0cc.jpg)
5)SyntaxError(语法)
~~~
try{
a$b;
}catch(e){
alert('发生错误啦,错误信息为: '+e);
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89ea055d.jpg)
a$ b; //抛出 SyntaxError(语法)
错误信息为: SyntaxError: missing ; beforestatement(失踪;语句之前)
PS: SyntaxError通常是语法错误导致的。
注意:视频中的实例在我的火狐浏览器和IE浏览器中显示是上图的引用错误。这个有待研究一下……
6)TypeError(类型)
~~~
try{
new 10;
}catch(e){
alert('发生错误啦,错误信息为: '+e);
}
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89eb0e3e.jpg)
7)URIError
PS:Error是基类型(其他六种类型的父类型), 其他类型继承自它。 Error类型很少见,一般由浏览器抛出的。这个基类型主要用于开发人员抛出自定义错误。
PS: TypeError通常是类型不匹配导致的。
PS: EvalError类型表示全局函数 eval()的使用方式与定义的不同时抛出, 但实际上并不能产生这个错误,所以实际上碰到的可能性不大。
PS:在使用 encodeURI()和 decodeURI()时,如果 URI格式不正确时,会导致 URIError错误。但因为 URI的兼容性非常强,导致这种错误几乎见不到。
### 三、错误事件
error事件是当某个DOM对象产生错误的时候触发。
demo.html:
~~~
<img src="123.jpg"onerror="alert('图像加载错误! ')"/>
~~~
demo.js
~~~
addEvent(window,'error', function(){
alert('发生错误啦! ')
});
~~~
![](https://box.kancloud.cn/2016-03-28_56f8f89ec1fba.jpg)
### 四.错误处理策略
因为JavaScript是松散弱类型语言,很多错误的产生是在运行期间的。一般来说,需要关注3种错误:
1.类型转换错误
在一些判断比较的时候,比如数组比较,有相等和全等两种:
~~~
alert(1 == '1'); //true
alert(1 === '1'); //false
alert(1 == true); //true
alert(1 === true); //false
~~~
PS:由于这个特性,我们建议在这种会类型转换的判断,强烈推荐使用全等,以保证判断的正确性。
~~~
var box = 10; //可以试试 0
if (box) { //10自动转换为布尔值为 true
<span style="white-space:pre"> </span>alert(box);
}
~~~
PS:因为 0会自动转换为 false,其实 0也是数值,也是有值的,不应该认为是 false,所以我们要判断 box是不是数值再去打印。
~~~
var box = 0;
if (typeof box == 'number') { //判断 box是 number类型即可
alert(box);
}
~~~
PS: typeof box == 'number'这里也是用的相等,没有用全等呀?原因是 typeof box本身返回的就是类型的字符串,右边也是字符串,那没必要验证类型,所以相等就够了。
2.数据类型错误
由于 JavaScript是弱类型语言,在使用变量和传递参数之前,不会对它们进行比较来确保数据类型的正确。所以,这样开发人员必须需要靠自己去检测。
~~~
function getQueryString(url) { //传递了非字符串,导致错误
<span style="white-space:pre"> </span>var pos = url.indexOf('?');
<span style="white-space:pre"> </span>return pos;
}
alert(getQueryString(1));
~~~
PS:为了避免这种错误的出现,我们应该使用类型比较。
~~~
function getQueryString(url) {
<span style="white-space:pre"> </span>if (typeof url == 'string') { //判断了指定类型,就不会出错了
<span style="white-space:pre"> </span>var pos = url.indexOf('?');
<span style="white-space:pre"> </span>return pos;
<span style="white-space:pre"> </span>}
}
alert(getQueryString(1));
~~~
PS:对于传递参数除了限制数字、字符串之外,我们对数组也要进行限制。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (arr) { //只判断布尔值远远不够
<span style="white-space:pre"> </span>alert(arr.sort());
<span style="white-space:pre"> </span>}
}
var box = [3,5,1];
sortArray(box);
~~~
PS: 只用 if (arr)判断布尔值,那么数值、字符串、对象等都会自动转换为 true,而这些类型调用 sort()方法比如会产生错误,这里提一下:空数组会自动转换为 true而非 false。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (typeof arr.sort == 'function') { //判断传递过来 arr是否有 sort方法
<span style="white-space:pre"> </span>alert(arr.sort()); //就算这个绕过去了
<span style="white-space:pre"> </span>alert(arr.reverse()); //这个就又绕不过去了
<span style="white-space:pre"> </span>}
}
var box = { //创建一个自定义对象,添加 sort方法
<span style="white-space:pre"> </span>sort : function () {}
};
sortArray(box);
~~~
PS: 这断代码本意是判断 arr是否有 sort方法, 因为只有数组有 sort方法, 从而判断arr是数组。但忘记了,自定义对象添加了 sort方法就可以绕过这个判断,且 arr还不是数组。
~~~
function sortArray(arr) {
<span style="white-space:pre"> </span>if (arr instanceofArray) { //使用 instanceof判断是 Array最为合适
<span style="white-space:pre"> </span>alert(arr.sort());
<span style="white-space:pre"> </span>}
}
var box = [3,5,1];
sortArray(box);
~~~
3.通信错误
在使用 url进行参数传递时,经常会传递一些中文名的参数或 URL地址,在后台处理时会发生转换乱码或错误,因为不同的浏览器对传递的参数解释是不同的,所以有必要使用编码进行统一传递。
比如: ?user=李炎恢&age=100
~~~
var url = '?user=' + encodeURIComponent('李炎恢') + '&age=100'; //编码
~~~
这三种错误一般会在特定的模式下或者没有对值进行充分检查的情况下发生。
### 五、调试技术
1、设置断点
我们可以选择Script(脚本), 点击要设置断点的JS脚本处, 即可设置断点。 当我们需要调试的时候,从断点初开始模拟运行,发现代码执行的流程和变化。
2、单步调试
设置完断点后,可以点击单步调试,一步步看代码执行的步骤和流程。上面有五个按钮:
重新运行:重新单步调试
断继:正常执行代码
单步进入:一步一步执行流程
单步跳过:跳到下一个函数块
单步退出:跳出执行到内部的函数**
3、监控
单击“ 监控”选项卡上, 可以查看在单步进入是, 所有变量值的变化。 你也可以新建监控表达式来重点查看自己所关心的变量。
4、控制台
显示各种信息。
### 六、学习心得
1、错误处理在软件开发中占着重要的地位,合理的处理错误,显示人性化的界面,为用户着想。
2、条条大路通罗马,不同的调试方法,相同的调试结果,换个角度,看到的更多。
3、将错误抛出来的同时记得处理,一直抛不处理也是不正确的做法。**