Javascript基础 错误调试

一旦你发现一个错误,就能够清除它。不幸的是,发现它们的 
出处并不老是很容易 - 你的大部分调试时间只是花在指出错 
误的位置。 

最可靠的方法之一是在你的代码中加入一些简单的语句打印出 
正在发生什么。假如你在下面的两段程序中发现一个问题: 

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快速运行。>> sass

一旦你的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助手”。通往神秘真知 
的路就在你的脚下 安全

相关文章
相关标签/搜索