博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Javascript基础 错误调试
阅读量:7080 次
发布时间:2019-06-28

本文共 10995 字,大约阅读时间需要 36 分钟。

hot3.png

一旦你发现一个错误,就可以清除它。不幸的是,发现它们的 

出处并不总是很容易 - 你的大部分调试时间只是花在指出错 
误的位置。 
最可靠的方法之一是在你的代码中加入一些简单的语句打印出 
正在发生什么。假如你在下面的两段程序中发现一个问题: 
function getName() 
{
 
    var first_name = prompt("what's your first name?",""); 
    var last_name = prompt("what's your last name?",""); 
    var the_name = first_name + " " + last_name; 
function theGreeting() 
{
 
    var the_name = ""; 
    the_name = getName(); 
    if (the_name == "Dave Thau") 
    {
 
alert("Hello, oh greatest one!"); 
    } else {
 
alert("Ahoy palloi!"); 
    } 
运行这段程序,看看你是否能发现出了什么问题(Netscape 3.x 
的用户可能会遇到一些错误检查的问题,这是由于Netscape 3.x 
本身的原因,以下的Javascript例子与此相同)。如果你在警告 
对话框中随意输入一些名字,你会得到问候:“Ahoy palloi!”。 
但是,如果你在第一个提示对话框中输入“Dave”,在第二个中 
输入“Thau”,你应该得到“Hello,oh greatest one!”这条 
信息。然而,你还是只得到“Ahoy palloi!”这条信息。很明显, 
函数中出了错误。在这个简单的例子程序中,你或许只是查看 
JavaScript代码就能发现错误。然而,当你的代码变得越来越复 
杂时,只靠目测来发现错误会变得愈加困难。 
如果JavaScript没能捕获你的错误,你也没有通过查看代码发现 
错误,有时打印出变量会对你有所帮助。最简单的方法是象下面 
这样使用一个alert(): 
// theGreeting gets a name using getName, then presents  
// one or two alert boxes depending on what the name is 
//function getName() 
{
 
    var first_name = prompt("what's your first name?",""); 
    var last_name = prompt("what's your last name?",""); 
    var the_name = first_name + " " + last_name;  
    alert("in getName, the_name is: " + the_name); 
// theGreeting gets a name using getName, then presents  
// one of two alert boxes depending on what the name is 
// function theGreeting() 
{
 
   var the_name = ""; 
   the_name = getName(); 
   alert("after getName, the_name = " + the_name); 
   if (the_name == "Dave Thau") 
   {
 
       alert("hello, oh greatest one!"); 
   }else{  
       alert("ahoy palloi!");  
   } 
请注意我们已经在所有重要的地方加入警告语句。现在试着运行 
这段程序。如果你输入名称“Dave”和“Thau”,你会注意到第 
一个警告显示“in getName, the_name is: Dave Thau,”,但 
是第二个警告显示“after getName, the_name = undefined,”, 
这就告诉你在getName()的最后一行事情变得糟糕起来。不知何 
故,the_name只在函数存在前正确,但是theGreeting没有给变 
量the_name正确赋值。当你写的函数能正确运行,但返回值出现 
问题时,你最先要做的就是检查你是否的确让其返回了一个值。 
很明显,问题就出在这儿。getName()函数指出了名称,但没有 
返回它。所以我们应把语句“return the_name;”加到函数末尾。 
把一些警告对话框加入你的代码中是很有帮助的。不幸的是,每 
隔一行就按一次“OK”也是一种痛苦。 
不用警告对话框也能调试代码。一种选择是把调试信息写到窗体 
的一个文本区内。另一种可能是把调试信息写在另一个窗口上。 
这儿有一个把调试信息写在下面文本区的调试代码的例子。 
使你的调试经历更舒适的第三个诀窍是这样的:创建不同的调试 
等级,然后设置“调试”变量。下面就是在此页上运行的 
JavaScript代码: 

// debug can be either none, alert, or textarea  
//  depending on the kind of debugging I want to do 
// var debug = "none"; 
// function getName gets a first and last name,  
// concatenates them with a space in between,  
// and returns the name function getName() 
{  
    var first_name = prompt("what's your first name?",""); 
    var last_name = prompt("what's your last name?",""); 
    var the_name = first_name + " " + last_name;  
    var error_message = "in getName, the_name is: " + the_name;  
    doError("in getName, the_name is: " + the_name); 
// theGreeting gets a name using getName, then presents  
// one of two alert boxes depending on what the name is 
// function theGreeting() 
{
 
   var the_name = ""; 
   the_name = getName();  
   doError("after getName, the_name = " + the_name); 
   if (the_name == "Dave Thau") 
   {
 
        alert("hello, oh greatest one!"); 
   } else {  
        alert("ahoy palloi!"); 
   } 
// doError is the error handling routine 
// depending on the type of debug message 
// it presents either no debug message, an alert 
// or puts the message in a textarea 
// 
function doError(the_message) 
{
 
    if (debug == "alert")  
    {
 
        alert(the_message); 
    } else if (debug == "textarea") 
    {  
        window.document.the_form.the_text.value +=    the_message + "<br>\n";  
    } 
    请注意我已经定义了一个叫“debug”的变量,它可以是 
“none”,“alert”或“textarea”。于是当我想产生一个错 
误信息时,我把它送给函数doError(),此函数可能什么也不做, 
或者显示一个消息对话框,或者把消息粘贴到一个文本区中,这 
取决于我怎样设置调试变量。当你想同时看到多条错误信息时, 
你可以设置调试变量为“textarea”。当你准备把你的代码显示 
给全世界时,你只需要把调试变量设为“none”,于是错误信息 
将不再出现,这样可以省去发现和清除所有调试语句的麻烦。 
通常,程序员可以创建不同的调试等级,如“none”,“brief” 
和“extreme”。“brief”将打印一些调试信息,“extreme” 
将打印大量调试信息,“none”当然不会打印任何信息。 
如果你按此方法建立你的调试系统,你可以在编码时把调试等级 
设为“brief”,在准备公布你的JavaScript时把调试变量设为 
“none”。如果有不可思议的事情发生,并且你不知道去哪儿发 
现问题,你可以把调试等级设为“extreme”,然后流览所有的 
调试信息直到发现可疑的地方。 
好了,调试系统就讨论到这儿。现在让我们看看JavaScript编码 
器产生的一般性错误。>> 

多数错误只是无聊的语法错误。记住关闭那些引号,大括号和 

小括号会花费很长时间,不过幸运的是JavaScript自动错误检 
测器能捕获大部分此类错误。虽然JavaScript错误检测器随着 
日渐复杂的流览器而不断完善,但是一些错误仍会溜走。下面 
是一些需要留意的常见错误: 
混淆变量名或函数名 
大写和复数变量和函数名产生的错误令人烦恼地经 
常出现,有时JavaScript错误检测器不能捕获它们。 
通过建立和坚持使用一种对变量和函数的命名协定, 
会大大减少这些麻烦的数量。例如,我全部用小写 
字母定义变量,并用下划线代替空格 (my_variable, 
the_data, an_example_variable),用内置符号表 
示函数 (addThreeNumbers(), writeError()等)。 
我避免使用任何复数,因为我总是忘记那些变量是 
不是复数。 
偶然地使用了保留字 
一些字不能作为变量名,因为它们已经被JavaScript 
使用。例如,不能定义一个叫“if”的变量,因为 
它实际上是JavaScript的一部分 - 如果使用“if”, 
你会遇到各种麻烦。当你因为使用命名为“if”的 
变量而变得疯狂时,一个叫做“document”的变量 
是很诱人的。不幸的是,“document”是一个 
JavaScript对象。另一个经常遇到的问题是把变量 
命名为“name”(窗体元素有“names”属性)。把 
变量命名为“name”不会总出问题,只是有时 -  
这会更使人迷惑 - 这就是避免使用“name”变量的 
原因。 
不幸的是,不同的流览器有不同的保留字,所以没 
有办法知道该回避哪些字。最安全的办法是避免使 
用已经成为JavaScript一部分的字和HTML使用的字。 
如果你因为变量遇到问题,并且不能发现哪儿错了, 
试着把变量改个名字。如果成功了,你或许就避开 
了保留字。 
记住在逻辑判断时应该用两个等号 
一些流览器能捕获这种错误,有些却不能。这是一 
种非常常见的错误,但是如果流览器不能替你指 
出来,你就很难发现。下面是一个这种错误的例子: 
var the_name = prompt("what's your name?", ""); 
if (the_name = "the monkey") 
{
 
 alert("hello monkey!"); 
} else {
 
 alert("hello stranger."); 
这段代码将产生“hello monkey!”警告对话框 -  
不管你在提示里敲的是什么 - 这不是我们希望的。 
原因是在if-then语句中只有一个等号,这句话告 
诉JavaScript你想让一件事等于另一件。假设你在 
提示中敲的是“robbie the robot”。最开始,变 
量the_name的值是“robbie the robot”,但是随 
后if语句告诉JavaScript你想把the_name设为 
“the monkey.”。于是JavaScript很高兴地执行你 
的命令,送一个“true”消息给if-then语句,结果 
警告对话框每次都出现“hello monkey!”。 
这种阴险的错误会使你发疯,所以注意使用两个 
等号。 
偶然给变量加上了引号,或忘了给字符串加引号 
我不时遇到这个问题。JavaScript区分变量和字符 
串的唯一方法是:字符串有引号,变量没有。下面 
有一个明显的错误: 
var the_name = 'koko the gorilla'; 
alert("the_name is very happy"); 
虽然the_name是一个变量,但是程序还会产生一个 
提示“the_name is very happy,”的警告对话框。 
这是因为一旦JavaScript看见引号包围着某些东西 
就不再考虑它,所以当你把the_name放在引号里, 
你就阻止了JavaScript从内存中查找它。 
下面是一个不太明显的此类错误的扩展(我们已经 
在第三天的课程里见过): 
function wakeMeIn3() 
{
 
 var the_message = "Wake up! Hey! Hey! WAKE UP!!!!"; 
 setTimeout("alert(the_message);", 3000); 
这里的问题是你告诉JavaScript三秒后执行alert 
(the_message)。但是,三秒后the_message将不再 
存在,因为你已经退出了函数。这个问题可以这样 
解决: 
function wakeMeIn3() 
{
 
 var the_message = "Wake up!"; 
 setTimeout("alert('" + the_message+ "');", 3000); 
把the_message放在引号外面,命令“alert('Wake 
up!');”由setTimeout预定好,就可以得到你想 
要的。 
这只是一些可能在你的代码中作祟的很难调试的 
错误。一旦发现了它们,就有不同的或好或差的方 
法来改正错误。你很幸运,因为你能从我的经验和 
错误中获益

第页:修正错误  
找到错误,有时侯虽然很难,却只是第一步。然后你必须清除 
错误。下面是一些在清除错误时应该做的一些事: 
首先拷贝你的程序 
有些错误很难清除。实际上,有时在根除错误时, 
你会破坏整个程序 - 一个小错误使你疯狂。在开始 
调试前保存你的程序是确保错误不会利用你的最好 
方法。 
一次修正一个错误 
如果你知道有好几个错误,应该修正一个,检验其 
结果,再开始下一个。一次修正许多错误而不检验 
你的工作只会招致更多的错误。 
警惕迷惑性错误 
有时你知道存在一个错误,但不真正知道为什么。 
假设有一个变量“index”,由于某种原因“index” 
总比你期望的小1。你可以做下面两件事中的一件: 
在那儿坐一会儿,解决它为什么变小了,或只是耸 
耸肩;在使用“index”之前加1,然后继续进行。后 
一种方法称为迷惑编程。当你开始思考“究竟是怎 
么了 - 为什么index是2而不是3呢?好吧...我现在 
先让它正常工作,以后再修改错误。”时,你正在 
把一块护创膏布贴到一处潜在的硬伤上。 
迷惑编程可能在短期内有用,但是你可以看到长期 
的厄运 - 如果你没有完全理解你的代码到可以真正 
清除错误的程度,那个错误将会回来困扰你。它或 
者以另一种你不能解决的怪异错误的方式回来,或 
者当下一个可怜的被诅咒的灵魂读你的代码时,他 
会发现你的代码非常难以理解。 
寻找小错误 
有时侯,对程序员来说,剪切和粘贴代码的能力是 
一种很坏的事。通常,你会在一个函数中写一些 
JavaScript代码,然后把它们剪切和粘贴到另一个 
函数中。如果第一个函数有问题,那么现在两个函 
数都有问题。我并不是说你不应该剪切和粘贴代码。 
但是错误会以某种方式繁殖,如果你发现了一个 
错误,你就应该寻找与其相似的其它错误。(或者 
在制作它的若干版本之前确切知道会发生什么。) 
变量名拼写错误在一段JavaScript代码中会突然多 
次出现 - 在一个地方把the_name错拼成teh_name, 
你就有机会在其它地方发现这个错误。 
如果所有其它的方法都失败了 
如果你正坐在那儿盯着一个错误,并且不能指出是 
怎么回事(或者根本没有发现错误,但是因为程序 
不能正确运行,你知道存在错误),你最好从计算 
机前走开。去读一本书,在角落散散步,或者拿一 
杯可口的饮料 - 做些事,任何事,但不要去想程序 
或问题。这种技术在某种情况下叫做“酝酿”,效 
果非常好。在你稍做休息和放松后,再试着找出 
错误。你会得到一幅比较清晰的景象。“酝酿”起 
作用是因为它使你从思维混乱中解脱出来。如果沿 
着一条错路走太远,你有时会发现无法转身。这种 
情况下最好开辟一条新路。我知道这会令人发火, 
但确实有效。真的! 
如果上面的方法还不成功... 
请求别人的帮助。有时你的思想会形成定式,只有 
换一种眼光才能洞察问题之所在。在结构化编程环 
境中,程序员们定期地互相复查别人的代码。这可 
以适当地叫做“代码复查”,不仅可以帮助消除 
错误,还可以得到更好的代码。不要怕把你的 
JavaScript代码给别人看,它会使你成为更好的 
JavaScript程序员。 
但是消除错误的绝对最好的办法是... 
一开始就创建没有错误的代码。>>

编好程序的关键是程序是写给人的,不是写给计算机的。如 

果你能明白其他人或许会阅读你的JavaScript,你就会写更 
清晰的代码。代码越清晰,你就越不容易犯错误。机灵的代 
码是可爱的,但就是这种机灵的代码会产生错误。最好的经 
验法则是KISS,即Keep It Simple,Sweetie(保持简单,可爱)。 
另一个有帮助的技术是在写代码之前作注释。这迫使你在动 
手之前先想好。一旦写好了注释,你就可以在其下面写代码。 
下面是一个用这种方法写函数的例子: 
第一步:写注释 
//function beSassy() 
// beSassy asks for a user's name, chooses a random  
// insult and returns an alert box with the user's name and the 
// insult. 
function beSassy() 
{
 
// first write a list of insults 
// 
// next get the user's name 
// 
// then choose a random insult  
// 
// finally, return the personalized sass 
// 
第二步:填充代码 
//function beSassy() 
// beSassy asks for a user's name, chooses a random  
// insult and returns an alert box with the user's name and the 
// insult. 
function beSassy() 
{
 
// first write a list of insults 
// 
var the_insult_list = new Array; 
the_insult_list[0] = "your shoe lace is untied"; 
the_insult_list[1] = "your mama!"; 
the_insult_list[2] = "it's hard to be insulting"; 
// next get the user's name 
// 
var the_name = prompt("What's your name?", ""); 
// then choose a random insult  
// 
var the_number = Math.random() * 5; 
var insult_number = parseInt(the_number); 
var the_insult = the_insult_list[insult_number]; 
// finally, return the personalized sass 
// 
alert("Hey " + the_name + " " + the_insult); 
这种先写注释的策略不仅迫使你在写代码前思考,而且 
使编码的过程看起来容易些 - 通过把任务分成小的, 
易于编码的各个部分,你的问题看起来就不太象珠穆朗 
玛峰,而象一群令人愉悦的起伏的小山。 
最后... 
总以分号结束你的每一条语句。 
虽然并不是严格必需,你应该养成以分号结束每一条语 
句的习惯,这样可以避免这行后面再有代码。忘了加 
分号,下一行好的代码会突然产生错误。 
把变量初始化为“var”,除非你有更好的理由不这样做。 
用“var”把变量局域化可以减少一个函数与另一个不相 
关函数相混淆的机会。 
好了,既然你已经知道了如何编码,下面就让我们学习怎样使 
你的JavaScript快速运行。>>

一旦你的JavaScript能运行,你就会想到使其运行得更快。 

在讲解加速代码的方法之前,让我先讲讲“80/20规则”: 
百分之八十的优化是由最初百分之二十的工作所完成的。竭 
力实现剩余百分之二十的速度优化是一种巨大的痛苦,而且 
经常导致完全不能读和难以管理的代码。简言之,如果你的 
JavaScript运行得很慢,你可以用很多简单的方法来加速它, 
但是除非你的代码确实运行得很慢,我不会对它进行再优化。 
下面是一些使你的代码轻松运行的方法。 
限制循环内的工作量 
程序运行慢的最常见原因是循环内的重复工作。如果一 
条命令只需要执行一次,就没有必要把它放在循环内。 
例如: 
var index = 0; 
while (index <10) 
{
 
 var the_date = new Date(); 
 var the_day = the_date.getDay(); 
 var the_name = prompt("what's the kid's name? " ,""); 
 alert("On " + the_day + " " + the_name + " is a very special person."); 
 index++; 
此程序循环执行10次。每次得到当天的日期,询问小孩 
的名字,然后打印出“On Monday,so-and-so is a  
very special person.”。 
但是日期是不会改变的,总是今天。所以没有必要把前 
两行放在循环中。把它们从循环中拿出来,让其只执行 
一次而不是10次,这样会节省时间: 
var index = 0; 
var the_date = new Date(); 
var the_day = the_date.getDay(); 
while (index <10) 
{
 
var the_name = prompt("what's the kid's name? " ,""); 
alert("On " + the_day + " " + the_name + " is a very special person."); 
index++; 
定制if-then-else语句,按最可能到最不可能的顺序 
因为if-then-else语句在遇到条件为真时结束,你可以 
通过把最有可能的条件放到最开始来减少需要判断的语 
句的数量。例如: 
var pet = prompt("what kind of pet do you have?", ""); 
if (pet == "cat")  
{
 
 doCatStuff(); 
} else if (pet == "dog")  
{
 
 doDogStuff(); 
} else if (pet == "bird") 
{
 
 doBirdStuff(); 
} else if (pet == "lizard") 
{
 
 doLizardStuff(); 
一般来说,程序中的if子句比从lizard到dog需要执行的 
逻辑判断要少。 
最小化重复执行的表达式 
如果你发现需要重复计算一个特定的表达式,如 
var pi=22/7,只计算一次并把它放在一个全局变量中或 
许是个好主意。例如,不象下面程序这样: 
function theArea(radius) 
{
 
var pi = 22/7; 
var area = pi * radius * radius; 
return area; 
function theCircumference(radius) 
{
 
var pi = 22/7; 
var circumference = 2 * pi * radius; 
return circumference; 
而是这样做: 
var pi = 22/7; 
function theArea(radius) 
{
 
 var area = pi * radius * radius; 
 return area; 
function theCircumference(radius) 
{
 
 var circumference = 2 * pi * radius; 
 return circumference; 
我知道我在用一个全局变量,我也说过这不是一个好主意。 
然而,一些数字,如pi,其值在程序中永远不会改变,是 
此规则的特例。通过只计算pi一次,可以省去额外的计算。 
或许时间上的一些小的节省,累加起来会很管用。 
如果你发现代码运行很慢,你只要注意一些事情。这些都 
很明显,但是当你发现你经常忽略象这样简单的优化技巧 
时,你会很吃惊。 
还有,我的朋友,让我们结束今天的课程,这也是整个 
JavaScript高级教程的结束。如果你已经进行到这儿, 
并且你至少读过过去五天课程中的一半,那么你已经看 
过很多JavaScript代码了。实际上,如果你能理解跨越 
第一部分和第二部分的10课的大部分内容,你就可以很 
安全地把自己称为“JavaScript助手”。通往神秘真知 
的路就在你的脚下

转载于:https://my.oschina.net/u/1403096/blog/184493

你可能感兴趣的文章
Shell脚本添加用户
查看>>
MySQL到CSV几种方法
查看>>
JDK:Integer.getChars(int i, int index, char[] buf
查看>>
zook 报错 Unable to read additional data from server sessionid 0x0
查看>>
很多企业网站为什么都将站点做成矩形的样子的呢
查看>>
在Javascript中 声明时用"var"与不用"var"的区别,== 和 ===的区别
查看>>
Vim + Gdb 程序的完美集合
查看>>
Ceph:一个 Linux PB 级分布式文件系统
查看>>
HA高可用特殊概念仲裁机制介绍
查看>>
《Java从小白到大牛》之第10章 面向对象基础(上)
查看>>
我的友情链接
查看>>
14. 复习_小练习
查看>>
Linux系统mongodb主从模式配置
查看>>
MongoDB导入导出以及数据库备份
查看>>
请问怎样把 Real Player11录制的ivr格式音频转化为其他格式呢?
查看>>
对象和类,日历
查看>>
我的友情链接
查看>>
机器学习 - 回归分析
查看>>
MySQL(七)之多表查询
查看>>
File创建文件
查看>>