您好,登錄后才能下訂單哦!
第一頁:Javascript高級教程- 第5天
哇!- 今天是最后一天!真是好極了!作為對您這些天辛勤工作的獎勵,我把今天的課程安排得非常放松 -
沒有本質代碼縈繞在你腦中,也沒有多如牛毛的家庭作業,只是編碼理論和指向資源的連接。
今天討論以下話題:
幫你寫Javascript的工具
調試技術
使你的Javascript代碼快速運行的技巧
可得到的工具
說實話,就算稱我為老學究,我也只用字處理器來寫Javascript。 雖然有大量的可用來寫Javascript的工具,但是它們產生的代碼非常笨拙而且很難更改。如果你真想使用一種工具來創建Javascript代碼,我向你推薦Dreamweaver,它能在很短時間內產生一些令人驚異的Javascript代碼。但是,如果你打算隨后更改這些代碼,就要做好面對一些非常難看的代碼的準備。
你也能找到幫你調試Javascript的工具。我也不用這些工具。網景有一個,微軟也有一個,但我從未見過很成功地使用這些調試器的人。你可以試一試,或許可以證明我是錯的。但是在有人能使我確信某種產品值得買(暗示:送我一套那種免費軟件)之前,我寧愿用老方法調試我的代碼。
調試技術
隨著用Javascript編程的深入,你會開始理解那些Javascript給出的不透明錯誤信息。一旦你理解了你常犯的一般性錯誤,你就會很快知道怎樣避免它們,這樣你寫的代碼中的錯誤將越來越少。編程實際上是一種能隨著時間不斷飛快進步的技術。但是不管變得多么熟練,你仍然要花一些時間調試你的代碼。
如果你做過家庭作業,或有過Jacascript編程經驗,你會知道相當多的時間是花在調試上。這很正常 - 這只是編程者必須做的事之一。實際上,按照大量的研究,程序員平均百分之五十的時間花在解決代碼中的錯誤。
關鍵是學會怎樣有效地調試你的程序。我有一些技巧可以幫助你解決程序為什么沒有象應該的那樣運行,或者幫你首先避免寫有很多錯誤的代碼:
用不同方式打印出變量
注意一般性錯誤
編碼之前先想好
讓我們以打印出那些變量開始。
第二頁:打印變量
一旦你發現一個錯誤,就可以清除它。不幸的是,發現它們的出處并不總是很容易 - 你的大部分調試時間只是花在指出錯誤的位置。
最可靠的方法之一是在你的代碼中加入一些簡單的語句打印出正在發生什么。假如你在下面的兩段程序中發現一個問題:
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 + "
";
}
}
請注意我已經定義了一個叫“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代碼
一旦你的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助手”。通往神秘真知
的路就在你的腳下。
第七頁:下面講什么?
既然你已經對Javascript有了實際的理解,你就可以寫一些非
常認真的Javascript程序了。現在該是把目標轉移到Javascript
應用上的時候。Taylor的“動態HTML教程”是一個很好的開始。
學會動態HTML,你就可以實現更遠大的夢想。不論如何,總該
有一些夢想吧。
但是首先,你需要練習,練習,再練習。把已有的代碼拿過來,
使它變得面目全非。或者白手起家寫代碼。努力寫出無錯誤的
代碼,成為一個能修正各種無論如何也要溜走的錯誤的專家。
用眼睛盯著有趣的和新的Javascript應用程序,指出它們是如
何實現的。你的代碼運行得是否完美并不重要,因為它總能教
你些什么。你學得越多,你的代碼就會變得越好,越快,越容
易創建。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。