《JavaScript精粹(修订版)》——1.10 脚本调试

本节书摘来自异步社区《JavaScript精粹(修订版)》一书中的第1章,第1.10节,作者:【英】Edwards, J. , 【澳】Adams, C.著,更多章节内容可以访问云栖社区“异步社区”公众号查看

1.10 脚本调试

调试是一个查错改错的过程。绝大多数浏览器拥有内建的报告错误的功能,还有一些外部的调试工具也值得关注。

1.10.1 理解浏览器内建的错误报告
Opera、Mozilla浏览器(例如FireFox)以及Internet Explorer都拥有很好的内建的错误报告功能,不过Opera和Mozilla的调试工具最为有用。

(1)Opera。 通过菜单Tools→Advanced→JavaScript console可以打开JavaScript控制台。也可以把它设置为遇到错误的时候自动打开,方法是依次选择Tools→Preferences→Advanced→Content菜单项,单击JavaScript选项按钮,打开一个对话框,然后选中Open JavaScript console on error选项。

(2)FireFox和其他的Mozilla浏览器。通过菜单Tools→JavaScript console打开JavaScript控制台。

(3)Internet Explorer for Windows。依次选择Tools→Internet Options→Advanced,然后取消Disable script debugging选项,再选中Display a notification about every script error选项。这样,每次发生错误就会弹出一个对话框。

(4)Internet Explorer for Mac。 依次选择Explorer→Preference→Web Browser→Web Content菜单项,然后选中Show scripting error alerts选项。

Safari在默认情况下是不包括错误报告的,不过新版本有了一个“隐藏”的调试菜单,包括一个JavaScript控制台,可以通过如下的终端命令来激活1:

$ defaults write com.apple.safari IncludeDebugMenu -bool true
也可以使用一种叫做Safari Enhancer2的扩展,这种扩展包含了一个选项,可以将JavaScript错误信息输出到Mac OS的控制台;但是,这些信息常常都没太大用处。

理解不同浏览器报告的错误信息需要一点练习,因为每种浏览器给出的信息都不相同。这里给出一个例子——一个错误类型的函数调用:

function saySomething(message)
{
  ┆
  alert(message);
}
saySometing('Hello world');

FireFox给出了非常简要但却很准确的报告,包括了发生错误的行号以及具体描述,如图1.1所示。

如图1.2所示,Opera给出了一个非常详细的报告,包括产生错误的回溯信息和发生错误的行号,以及具体描述。

《JavaScript精粹(修订版)》——1.10 脚本调试

回溯信息有助于定位由别的代码引发的错误,例如,事件处理者调用一个函数,该函数再调用第二个函数,在这个位置发生了错误。Opera的控制台能够回溯出调用过程并找到错误最初发生时的函数调用或事件处理。

Internet Explorer给出了非常基本的信息,如图1.3所示。它提供了发生错误的行号(不过可能与真实的错误位置有偏差)3,还有一个很概括的错误类型描述,但是却没有指出具体的错误。

《JavaScript精粹(修订版)》——1.10 脚本调试

我对Internet Explorer给出的很简略的错误报告并没有太多的抱怨,至少比没有好,起码我知道有错误发生了。

1.10.2 使用alert
分析错误的时候,使用alert函数是一种非常有用的方法,可以在任何位置用它来显示对象或者变量的值,看是否是您所期望的值。例如,如果有一个有很多条件分支的函数,可以在每个分支使用alert,看看到底哪条分支被执行了:

文件:debugging-dialogs.js

function checkAge(years)
{
   if (years < 13)
   {
      alert('less than 13');
        ┆ 其他脚本
   }
   else if (years >= 13 && years <= 21)
   {
      alert('13 to 21');
        ┆ 其他脚本
   }
   else
   {
      alert('older');
        ┆ 其他脚本
   }
}

也许传入的years根本就不是一个数字,不像函数期望的那样。可以在这段代码的开头加入一个alert,看看究竟什么类型的变量被传了进来:

function checkAge(years)
{
  alert(typeof years);
    ┆
}

从理论上说,可以用alert对话框显示任意多的信息,虽然一个非常长的串会使得弹出的对话框非常宽,以至于超出了屏幕窗口的限制而被截断。可以给输出的信息加上换行符“n”来避免这种情况。

1.10.3 使用try-catch
try-catch具有令人难以置信的力量,可以做某种尝试,然后就能够处理可能发生的任何错误了。最基本的形式如下:

文件:debugging-trycatch.js (excerpt)

try
{
  ┆ 一些代码
}
catch (err)
{
  ┆ 如果try{}块中发生了错误,这部分代码将会运行
}

如果无法确定哪里发生了错误,可以用一个try-catch将一大块代码包起来,并且处理最可能的错误,然后一点点缩小包围圈。例如,可以将一个函数的部分包在try语句中,然后看看哪里发生了错误。然后将嫌疑代码再分割,在适当的位置使用try,这个过程持续下去,直到锁定出问题的那一行。

catch有一个参数(在这个例子中将它命名为err)是用来接收错误对象的,我们可以通过检查这个对象的属性,例如名字和信息,来得到这个错误的具体细节。

通常,我会用一个for-in语句来遍历整个对象,看看它究竟包含了什么信息:

文件:debugging-trycatch.js (excerpt)

for (var i in err)
{
  alert(i + ': ' + err[i]);
}

1.10.4 向页面和窗口中写入数据
如果在调试的时候需要检查很多数据,或者正在处理的数据有着很复杂的格式,则最好直接把数据写入一个页面或者一个弹出的窗口中,而不需要用许多alert对话框。如果检查的是循环中的数据,这样也避免了产生无数个对话框,要知道,这些对话框最后还得一个一个手工去关闭,这是非常麻烦的。

针对这些情况,可以使用元素的innerHTML属性,将数据写入页面中。下面的例子是通过使用一个数组的内容创建一个列表,然后将它写入test div中:

文件:debugging-writing.js (excerpt)

var test = document.getElementById('testdiv');
test.innerHTML += '<ul>';
for (var i = 0; i < data.length; i++)
{
  test.innerHTML += '<li>' + i + '=' + data[i] + '</li>';
}
test.innerHTML += '</ul>';

如果在页面中没有足够的和方便的地方来显示数据,也可以将数据写入弹出对话框中:

文件:debugging-writing.js (excerpt)

var win = window.open('', win, 'width=320,height=240');
win.document.open();
win.document.write('<ul>');
for (var i = 0; i < data.length; i++)
{
  win.document.write('<li>' + i + '=' + data[i] + '</li>')
}
win.document.write('</ul>');
win.document.close();

您可以以任何自己喜欢的格式输出数据,只要那种输出格式便于找到程序中的错误即可。

如果需要检查的数据比较少,可以用一种更简单的办法来输出数据,即把数据直接写入标题元素中:

文件:debugging-writing.js (excerpt)

document.title = '0 = ' + data[0];
最后在用这种方法检查那种持续和快速变化的数据的时候,特别有用。例如,由setInterval函数(这是一个异步的计时器,将在第14章详细介绍)处理的值。

1.10.5 使用外部调试器
下面推荐两个调试器:

 Venkman for Mozilla and FireFox4;

 Microsoft Script Debugger for Windows Internet Explorer5。

外部调试器在分析代码的时候能够提供更多的细节,比浏览器中内建的调试器的能力要强大许多。外部调试器可以在特定的点停止运行,也可以观察属性的值,这样就可以弄清楚属性的变化情况。它们还提供单步执行代码的能力,这样,那些难于分离检查的错误或者提示信息比较模糊的错误就可以更加容易定位。

外部调试器是比较复杂的软件,开发者们要想正确地使用这些软件,还需要花一些时间学习。它们对于寻找逻辑错误非常有用,作为学习JavaScript的工具也有其价值,不过它们对于浏览器的兼容性问题无能为力,只有浏览器的调试器支持的bug,用它们来调试才有意义。

上一篇:Javascript高级程序设计第二版第四章--变量,作用域及内存问题--笔记


下一篇:0018 c/c++语言 数的阶乘