第17章 错误处理与调试
- IE
唯一一个在浏览器的界面窗体(chrome)中显示JavaScript 错误信息的浏览器。在发生JavaScript
错误时,浏览器左下角会出现一个黄色的图标,图标旁边则显示着”Error on page”(页面中有错误)。
假如不是存心去看的话,你很可能不会注意这个图标。双击这个图标,就会看到一个包含错误消息的对
话框,其中还包含诸如行号、字符数、错误代码及文件名(其实就是你在查看的页面的URL)等相关信
息。 - Firefox
单击“Tools”(工具)菜单中的“Error Console”(错误控制台)可以显示错误控制台(见图17-4)。你会发现,错误控制台中实际上还包含与JavaScript、CSS 和HTML 相关的警告和信息,可以通过筛选找到错误。
最流行的Firefox 插件Firebug,已经成为开发人员必备的JavaScript 纠错工具。这个可以从www.getfirebug.com 下载到的插件,会在Firefox 状态栏的右下角区域添加一个图标。默认情况下,右下
角区域显示的是一个绿色对勾图标。在有JavaScript 错误发生时,图标会变成红叉,同时旁边显示错误的数量。单击这个红叉会打开Firebug 控制台,其中显示有错误消息、错误所在的代码行(不包含上下文)、错误所在的URL 以及行号 - Safari
启用“Develop”(开发)菜单。为此,需要单击“Edit”(编辑)菜单中的“Preferences”(偏
好设置),然后在“Advanced”(高级)选项卡中,选中“Show develop menu in menubar”(在菜单栏中显示“开发”菜单)。启用此项设置之后,就会在Safari 的菜单栏中看到一个“Develop”菜单 - Opera
默认情况下也会隐藏JavaScript 错误,所有错误都会被记录到错误控制台中。要打开错误控制台,需要单击“Tools”(工具)菜单,在“Advanced”(高级)子菜单项下面再单击“Error Console”(错误控制台)。与Firefox 一样,Opera 的错误控制台中也包含了除JavaScript 错误之外的很多来源(如HTML、CSS、XML、XSLT 等)的错误和警告信息。要分类查看不同来源的消息,可以使用左下角的下拉选择框 - Chrome
Chrome与Safari 和Opera 一样,Chrome 在默认情况下也会隐藏JavaScript 错误。所有错误都将被记录到
Web Inspector 控制台中。要查看错误消息,必须打开Web Inspector。为此,要单击位于地址栏右侧的
“Control this page”(控制当前页)按钮,选择“Developer”(开发人员)、“JavaScript console”(JavaScript控制台)
7 种错误类型:
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
要想知道错误的类型,可以像下面这样在try-catch 语句的catch 语句中使用instanceof 操作符。
try {
someFunction();
} catch (error){
if (error instanceof TypeError){
//处理类型错误
} else if (error instanceof ReferenceError){
//处理引用错误
} else {
//处理其他类型的错误
}
}与try-catch 语句相配的还有一个throw 操作符,用于随时抛出自定义错误。抛出错误时,必须
要给throw 操作符指定一个值,这个值是什么类型,没有要求。常见的错误类型
- 类型转换错误
类型转换错误发生在使用某个操作符,或者使用其他可能会自动转换值的数据类型的语言结构时。
在使用相等(==)和不相等(!=)操作符,或者在if、for 及while 等流控制语句中使用非布尔值时,
最常发生类型转换错误。
在流控制语句中使用非布尔值,是极为常见的一个错误来源。为避免此类错误,就要做到在条件比
较时切实传入布尔值。实际上,执行某种形式的比较就可以达到这个目的。例如,我们可以将前面的函
数重写如下。
function concat(str1, str2, str3){
var result = str1 + str2;
if (typeof str3 == “string”){ //恰当的比较
result += str3;
}
return result;
} 数据类型错误
基本类型的值应该使用typeof 来检测,而对象的值则应该使用instanceof 来检测。
根据使用函数的方式,有时候并不需要逐个检测所有参数的数据类型。
//安全,非数组值将被忽略
function reverseSort(values){
if (values instanceof Array){ //问题解决了
values.sort();
values.reverse();
}
}通信错误
对于查询字符串,应该记住必须要使用encodeURIComponent()方法。为了确保这一点,有时候
可以定义一个处理查询字符串的函数,例如:
function addQueryStringArg(url, name, value){
if (url.indexOf("?") == -1){
url += "?";
} else {
url += "&";
}
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
这个函数接收三个参数:要追加查询字符串的URL、参数名和参数值。如果传入的URL 不包含问
号,还要给它添加问号;否则,就要添加一个和号,因为有问号就意味着有其他查询字符串。然后,再
将经过编码的查询字符串的名和值添加到URL 后面。可以像下面这样使用这个函数:
var url = "http://www.somedomain.com";
var newUrl = addQueryStringArg(url, "redir",
"http://www.someotherdomain.com?a=b&c=d");
alert(newUrl);
使用这个函数而不是手工构建URL,可以确保编码正确并避免相关错误。
- 类型转换错误
调试技术
将消息记录到控制台
对IE8、Firefox、Chrome 和Safari 来说,
则可以通过console 对象向JavaScript 控制台中写入消息,这个对象具有下列方法。
error(message):将错误消息记录到控制台
info(message):将信息性消息记录到控制台
log(message):将一般消息记录到控制台
warn(message):将警告消息记录到控制台
function log(message){
if (typeof console == "object"){
console.log(message);
} else if (typeof opera == "object"){
opera.postError(message);
} else if (typeof java == "object" && typeof java.lang == "object"){
java.lang.System.out.println(message);
}
}
ConsoleLoggingExample01.htm
这个log()函数检测了哪个JavaScript 控制台接口可用,然后使用相应的接口。可以在任何浏览器
中安全地使用这个函数,不会导致任何错误,例如:
function sum(num1, num2){
log("Entering sum(), arguments are " + num1 + "," + num2);
log("Before calculation");
var result = num1 + num2;
log("After calculation");
log("Exiting sum()");
return result;
}
记录消息要比使用alert()函数更可取,因为警告框会阻断程序的执行,而在测定异步处理对时间的影响时,使用警告框会影响结果。对于大型应用程序来说,自定义的错误通常都使用assert()函数抛出。这个函数接受两个参数,
一个是求值结果应该为true 的条件,另一个是条件为false 时要抛出的错误。以下就是一个非常基本
的assert()函数。
function assert(condition, message){
if (!condition){
throw new Error(message);
}
}
可以用这个assert()函数代替某些函数中需要调试的if 语句,以便输出错误消息。下面是使用
这个函数的例子。
function divide(num1, num2){
assert(typeof num1 == “number” && typeof num2 == “number”,
“divide(): Both arguments must be numbers.”);
return num1 / num2;
}
常见的IE错误
- 操作终止
原因:当<script>
节点被包含在某个元素中,而且JavaScript 代码又要使用appendChild()、innerHTML 或其他DOM 方法修改该元素的父元素或祖先元素时,将会发生操作终止错误.
解决方法:可以等到目标元素加载完毕后再对它进行操作,或者使用其他操作方法。例如,
为document.body 添加一个绝对定位在页面上的覆盖层,就是一种非常常见的操作 - 无效字符
- 未找到成员
如果在对象被销毁之后,又给该对象赋值,就会导致未找到成员错误。而导致这个错误
的,一定是COM 对象。发生这个错误的最常见情形是使用event 对象的时候。IE 中的event 对象是
window 的属性,该对象在事件发生时创建,在最后一个事件处理程序执行完毕后销毁。假设你在一个
闭包中使用了event 对象,而该闭包不会立即执行,那么在将来调用它并给event 的属性赋值时,就
会导致未找到成员错误 - 未知运行时错误
当使用innerHTML 或outerHTML 以下列方式指定HTML 时,就会发生未知运行时错误(Unknown
runtime error):一是把块元素插入到行内元素时,二是访问表格任意部分(<table>、<tbody>等)的
任意属性时。例如,从技术角度说,<span>标签不能包含<div>之类的块级元素,因此下面的代码就会
导致未知运行时错误:
span.innerHTML = "<div>Hi</div>"; //这里,span 包含了<div>元素
在遇到把块级元素插入到不恰当位置的情况时,其他浏览器会尝试纠正并隐藏错误,而IE 在这一
点上反倒很较真儿。 - 语法错误
原因可能是代码中少了一个分号,或者花括号前后不对应。然而,还有一种原因不十分明显的情况需要格外
注意。如果你引用了外部的JavaScript 文件,而该文件最终并没有返回JavaScript 代码,IE 也会抛出语法
错误 - 系统无法找到指定资源
在使用JavaScript 请求某个资源URL,而该URL 的长度超过了IE 对URL最长不能超过2083 个字符的限制时,就会发生这个错误。IE 不仅限制JavaScript 中使用的URL 的长度,而且也限制用户在浏览器自身中使用的URL 长度
- 操作终止