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助手」。通往神祕真知 
的路就在你的腳下 安全

相關文章
相關標籤/搜索