第8章调试技巧理想的软件开发是不需要调试的,但在现实开发过程中,开发人员总是会因为不同的原因而犯各种各样的错误,以至于给所构建的系统带来不同程度的危害。有些错误浅显而低级,比如用错了大小写,或者写错了变量名等等;而有些错误是复杂的逻辑错误,这类错误往往隐藏较深,不容易找出错误的原因;另外一些错误可能是功能实现的方式有问题,导致程序有性能瓶颈等等。可以说,软件开发就是不断编码和调试的过程。使用好的调试工具并掌握好的调试技巧能够加快软件开发进程,提高产品质量。本章将向读者详细介绍使用Firebug和Aptana调试JavaScript程序的一些技巧。8.1深入解析Firebug的调试功能在本书的第五章中已经向读者介绍过了Firefox浏览器的优秀调试插件Firebug的界面和基本功能。本节将向读者深入讲解如何利用Firebug的控制台输出各种自定义的信息、查看错误提示,如何利用命令行工具在页面上执行JavaScript代码,以及如何使用脚本查看器进行脚本的调试。8.1.1检查常规错误当Firefox遇到一个JavaScript错误时,Firebug会在其控制台输出一个错误信息。这个错误信息包含了错误的描述、发生错误的代码片断、包含该代码片断的函数或者方法、以及事件对象信息。下面这个示例中,在测试按钮的事件处理函数中调用了一个不存在的函数,代码如下所示。!DOCTYPEhtmlPUBLIC-//W3C//DTDXHTML1.0Transitional//EN==Content-Typecontent=text/html;charset=utf-8/titleconsoledemo/titlescripttype=text/javascriptfunctionerrorTest(){notExistFunction();//不存在的函数}/script/headbodyinputtype=buttonvalue=testbuttononclick=errorTest();//body/html用Firefox打开页面,如图8.1所示。单击“testbutton”按钮,按钮的click事件处理函数errorTest会被调用,这时候errorTest会调用一个不存在的函数notExistFunction,从而引发一个错误。浏览器遇到·220·脚本错误时,右下角Firebug的绿色小图标会变成红色以提示当前页面存在脚本错误,如图8.2所示。图8.1示例程序界面图8.2错误提示红色图标后面的数字表示错误的个数。单击红色图标或者按F12打开Firebug界面,如图8.3所示。图8.3错误提示错误被控制台用红色的字体,配上红色的错误图标醒目的现实了出来。错误的标题是对错误的描述,这里“notExistFunctionisnotdefined”指notExistFunction没有被定义。标题下面是发生错误的那一行代码。标题右边是发生错误的文件名和错误代码所在的行号。单击标题后面的文件说明或者标题下面的错误行代码提示,都可以转到脚本查看器并完整的查看该文件的脚本代码,如图8.4所示。·221·图8.4查看错误代码标题前面有一个“+”号的小图标,表示标题可以被展开,单击图标展开标题,如图8.5所示。图8.5展开标题标题展开后,下面显示的分别是包含错误代码的函数或方法,以及当前事件的相关信息。单击函数或方法名,可以转到脚本查看器查看器代码,如图8.6所示。图8.6查看函数代码单击事件的描述信息,可以转到DOM查看器查看事件对象的详细信息,如图8.7所示。·222·图8.7查看事件对象当程序中出现错误时,通过查看Firebug控制台输出的错误信息可以让开发者快速定位分析并修复错误。8.1.2完善的log功能在调试程序时,经常需要让程序在运行过程中输出一些信息,使得开发者可以实时掌握到程序运行的情况。Firebug的控制台提供了完整的log功能,在第五章中读者已经见过console.log的使用,下面来向读者介绍所有的log语法。1.console.logconsole.log提供了在控制台中输出信息的基本方法,其语法如下所示。console.log(message1[,message2,...,messageN]);在代码被执行时,其参数会被连接在一起输出到Firebug的控制台中。console.log还支持5种占位符,见表8-1所示。表8-1console.log占位符占位符符说明%s字符串%d,%i整数%f浮点数%o对象占位符只能在console.log的第一个参数中使用。当第一个参数中包含占位符时,程序会根据占位符的数量,取从第二个参数开始的足够数量的参数替换到对应的占位符所在的位置,剩下的其他参数,则按照默认行为被连接到输出信息的末尾。下面的示例演示了console.log的用法,其代码如下所示。!DOCTYPEhtmlPUBLIC-//W3C//DTDXHTML1.0Transitional//EN==Content-Typecontent=text/html;charset=utf-8/titleconsole.logdemo/title·223·scripttype=text/javascriptconsole.log('messagestart');varnumber=123.22;varint=55;varstring='321';varobject={name:'rob',sex:'mail'};console.log('number=',number);console.log('number=%f',number);console.log('int=%d',int);console.log('string=%s',string);console.log('object=%o',object);console.log('number=%f,int=%d,string=%s,object=%o',number,int,string,object,',others...');console.log('messageend')/script/headbody/body/html使用Firefox访问该示例页面,可以看到在Firebug的控制台中输出了指定的信息,如图8.8所示。图8.8console.log示例2.console.debugconsole.debug与console.log一样可以接受多个参数,所不同的是通过console.debug输出的信息会被添加一个链接,单击链接时会根据参数的类型自动转换到其他视图。当参数为DOM对象或者JavaScript对象时,会转到DOM查看器显示对象的详细信息。当参数为HTML元素时,则会转到HTML查看器并定位到该元素节点上。如果参数为一个函数或者方法,则会转到脚本查看器并定位到函数或者方法的定义所在行。如果参数只是一个数字或者字符串等基本类型的值,则不会添加任何链接。比较特殊的是当参数为数组时,Firebug会分析其中每个元素的类型并添加相应的链接。下面的示例显示了console.debug的用法,代码如下所示。!DOCTYPEhtmlPUBLIC-//W3C//DTDXHTML1.0Transitional//EN==Content-Typecontent=text/html;charset=utf-8/titleconsole.debugdemo/title·224·scripttype=text/javascriptfunctionfunc(a,b){returna+b;}window.onload=function(){varobject={name:'rob',sex:'male'};varnumber=12;varstring='123';vararray=[1,2,3,object,number,string];varnode=document.getElementById('node');console.debug(object);console.debug(array);console.debug(number);console.debug(string);console.debug(func);console.debug(node);console.debug(window);console.debug(document);console.debug(screen);console.debug(navigator);}/script/headbodypid=nodeconsole.debugdemo/p/body/html程序运行后,在Firebug控制台输出的信息如图8.9所示。图8.9console.debug示例单击第一条信息的链接,Firebug转到DOM查看器视图并显示了对象的详细信息,如图8.10所示。·225·图8.10查看对象详细信息单击“func(a,b)”这条信息的链接,Firebug转到脚本查看器视图,并定位到该函数定义所在的行,如图8.11所示。图8.11查看函数定义单击“pid=”node””这条信息时,则会转到HTML查看器并定位到该元素节点上,如图8.12所示。图8.12查看HTML元素3.console.infoconsole.info的功能与console.debug一样,所不同的是其会在输出到Firebug控制台的信息前面加上一个表示注意信息的小图标。例如,将上面示例中的console.debug替换成console.info,如下所示。!DOCTYPEhtmlPUBLIC-//W3C//DTDXHTML1.0Transitional//EN==Content-Typecontent=text/html;charset=utf-8/titleconsole.infodemo/titlescripttype=text/javascript·226·functionfunc(a,b){returna+b;}window.onload=function(){varobject={name:'rob',sex:'male'};varnumber=12;varstring='123';vararray=[1,2,3,object,number,string];varnode=document.getElementById('node');console.info(object);console.info(array);console.info(number);console.info(string);console.info(func);console.info(node);c