分类: 系统运维
2006-07-14 13:52:01
經過前面的章節, 相信你對 JavaScript 有一定的認識了, 但是單學習 JavaScript 的語法而沒有程式基礎, 你只能將本書的例子套用到自己的網頁中。若要真正能創作自己的 JavaScript , 還要對程式的編寫理論有一些認識, 這處連續4章就是說這些理論。
JavaScript 與 C 語言極相似, 可說是 C 語言的簡化版本, 若你對 C 有認識, 就不用看這處 4 章了。
在 JavaScript, function 是我們設定的一些程式片段, 能使到瀏覽器進行一些工作, 通常這些片段會利用一些 statements 來設定一些條件, 使到瀏覽器遇一些情況就會執行一些 methods。
這書常提到 method 及 function , 兩者有什麼不同呢? 兩者都是使用瀏覽器進行一些工作, 不同之處主要有兩點:
1. Method 是瀏覽器預定的程序, 我們在網頁中放下一個 method 名稱, 瀏覽器就會執行這預定程序。
Function 則是我們自己編寫的程序, 一般是編定一些條件及 method, 使到瀏覽器因應環境來執行這些 method。
2. Function 是獨立操作, method 則一定要與一個 object 掛鉤 (global method例外), 即是以 object.method( ) 的方式來使用。
"Function" 這字在台灣及內地都譯成 "函數", 這是使用數學上 function 的中文釋名: "函數", 但程式上的 function (應譯作 "功能" ) 與數學上的 function (函數) 是完全兩回事。 "函數" 這字常誤導初學程式者, 以為與什麼數值有關, 本書為免讀者混淆, 所以一路都會使用英文 function 這名稱。為了讓讀者更清楚知道哪一個是 function 的名稱, 本書會使用粗斜體字來顯示, 及名稱後附有 ( ) 的符號, 例如本書前面就有 counter( )、confirmchoice( ) 等名稱。
Function 的名稱任我們自訂, 但要依一定的規格, 在 1.10-6 的一節已說過, 這處要特別留意大小寫, 例如你在網頁開頭處定了一個名為 openWindow( ) 的 function , 隨後使用這 function 時要依足大小寫, 例如不能用 OpenWindow( ) 或 openwindow( )。
Function 不能採用的名稱:
有一列名稱是 JavaScript 保留給自己使用, 我們不能用作 function (或 variable) 的名稱, 請參看本書 附錄-2 的資料。
我們自訂 function 名稱時, 若一時大意用了這些限制名稱, 就會引起錯誤, 其中一個安全辦法是將這些不能用的名稱印製一份, 放在案頭核對, 另一個更方便的辦法是在使用一些普遍名稱時, 例如 write( )、check( )、confirm( )、validate( )、send( ) 等等, 在後加上 It 這字, 例如 writeIt( )、checkIt( )、confirmIt( )、validateIt( )、sendIt( ) 等等, 這就一定不會與這些限制名稱相撞了。
一個 function 分為兩部份, "定義" (definition) 部份及 "叫用" (call) 部份, "call" 也有譯作呼叫或呼喚。請先看以下一個簡單的function例子。
練習-34 簡單的 function 例子
1. 請用瀏覽器開啟示範磁碟中的 , 這網頁有以下內容:
示範網頁
2. 網頁開啟後, 你會見到一個按鈕, 請按一下這按鈕, 就可啟動一串的反應, 請你看 simpleDemo( ) 所定義的反應如何逐項走出來。
A. 定義部份 (function definition):
我們要瀏覽器進行什麼程序, 這些程序就構成一個 function , 以下是今次例子中定義的部份:
1. 在定義的部份, 我們要做兩件事: (a) 給予這 function 一個自訂名稱, (b) 指定要這 function 進行的事項。
在這例子, 筆者將這 function 命名為 simpleDemo, 在 function 名稱後要加上一個 ( ) , 若這 function 有arguments (請看隨後例子), 就放在這括號內, 若沒有就空出。
2. 在 function 名稱前要加上 function 這個字, 讓瀏覽器知道隨後的資料是屬於一個 function 。
3. 我們用來指定要瀏覽器進行的工作的句子, 就是 statement (指述句子), 這些 statement 要放在 { } 這個大引號 (curly braces) 內, 這就是這 function 的範圍, 所以 function 有以下的格式:
4. 每個 statement 標準是用 ; 來結束, 例如:
alert(" This is alert diolog
box. ");
confirm(" This is confirm dialog box.");
這 ; 字符在 JavaScript 語言中可略去, 不過若你要給瀏覽器很明確的指示, 又不嫌麻煩, 可以用標準寫法。
5. Function 可放在網頁任何地方, 但習慣是放在 及 內, 使到網頁的主體載入前這 function 已預備妥當。若 function 放在網頁後方, 有可能觀看者叫用這 function 時, 瀏覽器還未載入這 function , 就會出現錯誤訊息。
不過若 function 內有變數名稱, 這 function 要放在設定這變數的句子之後, 否則這 function 執行時, 瀏覽器找不到這變數, 就會出現錯誤, 請看 4.5-3 的例子。
B. 叫用部份:
我們定義了一個 function, 這 function 就在備用狀態, 我們要發出指示, 瀏覽器才會執行這 function, 在這例子, 筆者是使用一個按鈕來啟動這 function, 如下:
這處的 onClick="simpleDemo( )" 就是當觀看者按一下 (Click) 這按鈕, 就啟動 simpleDemo( ), 這稱為 function call, 或簡單地稱為 call, 叫用 function 的部份稱為 caller (叫用者/呼喚者)。
我們一般是利用 event handler 的方式來啟動一個 function , 但也可使到瀏覽器在載入網頁時自動執行, 例如:
示範網頁
在以上例子, 瀏覽器由上而下執行這網頁的句子, 去到下方 simpleDemo( ) 這一個 caller, 就會啟動這 function。
許多初學者在編寫 function 時, 常遇到一個難題, 一句中究竟在哪處可以分行, 哪處不可以, 在 1.10-4 的一節已說過 script 內的分行及空格, 除了在一個 argument 內, 瀏覽器是不理會分行及空格, 所以只有 argument 內不可以分行。
Function 也有類似情況, 除了argument不能分行, 其他地方都可自由分行或加上空格, 請看這例子。
練習-35 Function 的分行
1. 請你將示範磁碟中的 複製去硬碟, 然後用瀏覽器開啟這硬碟中的檔案, 這檔案有以下內容:
示範網頁
( ) " >
2. 請你試驗一下按鈕的反應 ,應該一切操作正常。
3. 留意這 function 的三個 statement:
{ if ( confirm ("請你選擇 [確定]
或 [取消] ") )
{ alert("你按了 [確定],
代表選了 TRUE " ) }
else { alert("你按了 [取消], 代表選了 FALSE "
) }
}
4. 請你用「記事本」開啟上述網頁的原始檔案, 在上述的句子加上分行, 例如:
if
(
confirm
(
"請你選擇 [確定] 或 [取消] "
// ← 只有這 argument
內不可以分行
)
)
除了 argument 的句子, 請你隨意分行。改完後, 將這檔案存檔, 然後在瀏覽器重新載入這檔案, 看是否有錯誤的訊息出現。
5. 最後請你將上述的一句 argument 分行, 看有什麼後果。
6. 你也可試試將這 function 的句子在一或兩行中完成, 看有什麼後果, 例如:
function testFormat(
){if ( confirm ("請你選擇 [確定] 或 [取消]
") )
{alert("你按了 [確定], 代表選了 TRUE
" ) }else{alert(
"你按了 [取消], 代表選了 FALSE "
) } }
我們正常不會用這擠擁的寫法, 但操作上這也一樣正常。
在 function 內, { } 這大括號稱為 delimiter (分隔器), 是用來分開每一組運算, 這會給程式明確的指引, 執行時不會將一組運算與另一組運算混淆。
假若 statement 只有一句, 可以不用分隔器, 例如:
function testFormat(
)
{ if ( confirm ("請你選擇 [確定] 或 [取消]
") )
{ alert("你按了 [確定],
代表選了 TRUE " ) }
else { alert("你按了 [取消],
代表選了 FALSE " ) }
}
這可簡為:
{ if ( confirm ("請你選擇
[確定] 或 [取消] ") )
alert("你按了 [確定],
代表選了 TRUE " )
else alert("你按了 [取消],
代表選了 FALSE " )
}
若一組反應中有多個 statements, 這組 statements 就一定要放在一對 delimiter 內, 例如:
在 delimiter 的位置上, 程式員各有不同習慣, 例如有人喜歡這寫法:
function testFormat(
)
{ if(confirm("請你選擇: ") )
{ alert("你按了 [確定] ") }
else { alert("你按了
[取消] ") }
}
在這寫法, 你可清楚看到 { alert("你按了 [確定] ") } 是屬於 if 的, 而 { alert("你按了 [取消] ") } 是屬於 else 的, 這方式出錯的機會較少。
有人喜歡這寫法:
function testFormat(
)
{
if(confirm("請你選擇: ") )
{ alert("你按了 [確定] ")
}
else { alert("你按了 [取消] ")
}
}
這寫法是將一對的 delimiters 放在同一的縮入位置, 這方便我們檢查是否漏了一個大括號, 又或方便檢查一對大括號是否對稱。
Function 內每一組反應以 { 開始, 以 } 結束, 這處的例子是:
{ { } { } }
有時一組設定內又有多組設定 (nesting), 就會有這類似結構:
{ { { } } }
若程式有這類 nesting statement, 我們可將不同階層的 statement 作不同程度的縮入, 這就較方便檢查括號的對稱, 如下:
這些括號必需對稱, 若弄錯了或漏了一個, 瀏覽器執行這 function 時就會有對話盒告訴你在什麼地方出錯。
為了避免漏了這些括號, 筆者的習慣是每寫下一個開括號, 就立刻在下方加上一個關括號, 然後才在這兩個括號之間加上 statement, 這就不會出錯了。
設定一個 function 時, 若有一些數值 caller (叫用部份) 要送給這 function 來處理, 這數值就是一個 argument (引數), 這也稱為 parameter (參數), function 處理完畢後, 要將結果送回 caller 處, 這就是 return (傳回), 請先看以下一個簡單的例子。
練習-36 Function 的 argument 及 return
在這練習, 你要設定一個名為 circleArea( ) 的 function , 這 function 有一個名為 radius 的 argument, 即是 circleArea(radius), 這 function 設定了是 3.1416 * radius * radius, 即是計算圓形面績。
在叫用這 function 時, 你要在 caller 中將一個 5 的數值作為 argument, 傳給這 function來處理。
1. 請用瀏覽器開啟示範磁碟中的 , 這檔案有以下內容:
2. 開啟瀏覽器及載入這網頁, 你應見到以下顯示:
5 cm半徑圓形的面積是: 78.54 cm2
1. 請先看 function caller 的部份, 有這設定:
circleArea(5) ← 這就是 caller
2. 這 (5) 是我們設定的 argument, 叫用時, 將這 5 字傳給 (pass to) 以下的 function definition:
3. 經上述操作, radius 就會等於 5, 所以隨後的 3.1416 * radius * radius 變成 3.1416 * 5 * 5, 得出 78.54 的數值, 這數值用 return 這項操作送回 caller, 而這 caller 就會變成 78.54。
上個練習在網頁固定了將 argument 設定 5, 這當然沒有實際用途, 你明白了 argument 及 return 的原理, 就可看以下例子, 這是讓觀看者輸入他選擇的 argument。
練習-37 可改變的 argument
在這練習, 你要設定一個計算圓形面積的程式, 觀看者在文字框輸入圓形的半徑, 按一個按鈕, 就會有 alert 對話盒顯示計算的結果。
1. 請用瀏覽器開啟示範磁碟中的 , 這檔案有以下內容:
onClick="document.display.outbox.value=calcArea(x.value)">
這圓形的面積是:
10>
2. 網頁開啟後, 請在第一個文字框輸入一個數字, 按 [計算圓形面積] 的按鈕, 你應看到結果在第二個文字框出現。
1. 在這網頁中, 你見到以下的文字框:
在下方的一個 script, 筆者為了方便, 作以下設定:
x=document.display.inbox
2. 例如你在第一個文字框輸入 10 這數值, 就會有這效果:
document.display.inbox.value=x.value=10
這 value 是指文字框內的數值。
3. 在 [計算圓形面積] 的按鈕中, 原本有這設定:
onClick="document.display.outbox.value=calcArea(x.value)"
在第一個文字框輸入 10 的數值後, 有這結果:
onClick="document.display.outbox.value=calcArea(10)"
4. 按一下這按鈕, 就會啟動 calcArea(10), 有以下反應:
(10) 這一個 argument 就會送去 calcArea(radius), 有這結果: radius=10, 因此 3.1416*radius*radius 會變為 314.16 , 這 function 的 return 將結果送回及替代原本的 calcArea(x.value), 有這結果:
onClick="document.display.outbox.value=314.16"
因此 document.display.outbox 這文字框會出現 314.16 的數值。
在上述例子, 為了方便, 筆者用 x 這個變數來代表這物件:
x=document.display.inbox
你要留意這設定內有 display 及 inbox 這些自訂名稱, 假若將這句放在前面, 例如:
: :
瀏覽器執行 x=document.display.inbox 這句時, display 及 inbox 等名稱還未存在, 就會有提示對話盒告訴你 document.dispaly.inbox 不是一個 object (因這 object 還未出現)。
作者利用上個練習, 舉例說明一個初學程式者常犯的錯誤, 就是不能在程式執行時才讀取最新的變數資料。請你試將 練習-37 以下兩項稍作改變 (紅字的部份):
這圓形的面積是:
10>
你試試上述的網頁, 你會發現每次都會得出 0 的結果。
這網頁利用 x 來代表 document.display.inbox.value , 留意這一句是在網頁載入時就已執行, 當時 inbox 內沒有任何資料, 所以 x=0 , 啟動這句時: onClick= "document.display.outbox.value = calcArea(x)" , x 還是等於 0。
假若設定 x=document.display.inbox, 這是用 x 來代表這文字框, 另設定onClick="document.display.outbox.value=calcArea(x.value)" , 這使到程式在 onClick 時讀取最新的 x.value 數值。
前面練習的例子只有一個 argument, 有時一個 function 可以有多個 argument, 我們只要在 function definition 及在 function caller 中順序放好各 arguments, 這 function 就會知道如何處理。
練習-38 Function 的兩個 arguments
在這練習, 你要設定一個顯示橫線的 function , 在 caller 處將兩個 argument 交給這 function , 一個 argument 作為橫線的寬度 (width), 單位是 %, 另一個 argument 作為橫線的粗度 (size), 單位是 pixels。
1. 請用瀏覽器開啟示範磁碟中的 , 這檔案有以下內容:
This is line 1:
This is line
2:
hrline(50,2)
2 網頁開啟後, 請你留意兩條橫線, 第一條應是 80% 寬及 5 點粗, 第二條應是 50% 寬及 2 點粗。
1. 首先看這 caller:
這是叫用 hrline( ) 及送出兩個 arguments, 因此在這 function definition 中:
function hrline(hrwidth,hrsize)
hrwidth=80, hrsize=5, 有這結果:
function hrline(hrwidth,hrsize)
{
document.write("
}
這會產生 80% 寬度及 5 點粗度的橫線。
2. 第二次叫用 hrline( ) 時, 是使用這 argument: hrline(50,2) , 因此 hrwidth=50, hrsize=2, 所以會有 50% 寬度及 2 點粗度的橫線。
3. 在這例子, 你可看到 function 只要設定一次, 就可在整個檔案中重複使用, 每次使用時, 可因應需要而將不同的 argument 傳給這 function , 就可產生不同的結果。(請參看 15.2 的一節中的 Math.ceil( ) 及 Math.floor( ) 的例子。)
4. 若你要對 function 的 argument 及 return 要更加了解, 可再看多以下的一個例子, 但筆者不再解釋了, 你可自行研究。
這例子是設定兩個文字框, 觀看者分別在兩個文字框輸入數字, 再按一個按鈕, 就會有一個 alert 對話盒顯示兩個數字相乘的結果, 請你參看示範磁碟中的 。
請輸入兩個數字:
4>
4>
onClick="z = calc (x.value,
y.value); alert('結果是: ' + z
)">
前面說的 functions 都是我們自己設定的, 瀏覽器也有一些預設 (predefined) 的 functions, 這也稱為 global functions 或 core functions, 我們在 script 中放下這些 functions 的名稱, 就可叫用, 與 method 不同之處是 method 要與一個 object 連結才可使用, 例如 window.open( )、document.write( ) 等等, method 前都有一個 object 名稱, 這處說的 predefined functions 是獨立的, 不與任何 object 連結。
這部份有些深奧地方, 你可稍後才看這部份。
這用來將一些特別符號變為是 ASCII 編碼, 但範圍不包括字母及數目字符 (alphanumeric character) 及不包括這 7 個符號: * @ - _ + . / , 所以被進行編碼的會有 , ; = ( 等符號及空格。
要將文字進行這些編碼, 原因是這些符號在一些程式有特別的意義, 所以將文字交給這程式來處理前, 要將這些字符轉換為編碼, 例如在第 17 章 說到 cookies 的設定, 在 value 的一項就不能有空格及 ; 的字符, 若要加進這兩個字符, 就要使用escape 編碼 (請看 練習-130 )。
escape( ) 是使用這語法: escape(string) , string 是要進行編碼的句子, 留意 escape( ) 前是沒有 object 名稱的, 請看這例子:
網頁開啟後, 畫面會有這句文字:
Number%3D%2323350%2C%20is%20that%20true%3F
這處你可看到以下5個符號的編碼:
= %3D
# %23
, %2C
? %3F
空格 %20
請你看本書 附錄 10 的 ASCII 編碼表, 就會看到這些 escape 編碼實際是使用 ASCII 的 hex 編碼。
unescape( ) 的功能與 escape( ) 相反, 是將 escape 編碼變回字符, 並傳回這些字符, 例如以下的 script:
網頁開啟後, 有以下顯示:
Number%3D%2323350%2C%20is%20that%20true%3F // ←沒有解碼的句子
Number=#23350, is that true? // ← 解碼的句子
unescape( ) 有這格式: unescape("%hex") , 這處的 hex 是任何一個 ASCII hex編碼 (使用十六進位), 例如 unescape("%41") 會是 A 字。
eval( ) 是要瀏覽器進行工作, 使用的是這語法: eval(string) , string 是代表文字, 若這文字是 expression, eval( ) 會進行檢查, 若是 statement 就會執行這statement, 若是數目字, 會進行計算。
請看這例子:
這處的 eval(x > y ) 是要檢查 x 是否大過 y , 若是, 就傳回 true 這字, 若不是, 就傳回 false 這字, 所以在這例子, alert 對話盒中會出現 false 這字。
eval( ) 這功能最有用的地方是強迫瀏覽器將數字作為數值來處理, 而不是文字。例如我們設定一個文字框讓觀看者輸入數字, 瀏覽器可能會將數字作文字來處理, 若使用 eval( ) 就一定會作數字來處理, 請看以下例子。
練習-39 使用 prompt 對話盒來接受觀看者輸入的數字
這網頁有一個 prompt 對話盒, 及要求觀看者輸入一個數字, 這 script 會將這數字與 100 相加, 然後用一個 alert 對話盒顯示結果。
1. 請用瀏覽器開啟示範磁碟中的 , 這網頁有以下內容:
2. 網頁開啟後, 你會見到一個 prompt 對話盒, 請你輸入一個數字, 按 [確定], 看有什麼結果。
在這例子, 你會見到瀏覽器將你輸入的資料作為文字來處理, 例如你輸入 250, 就會有 250100 的結果。假若我們要將一些數字作為數值來處理, 而不是文字, 可使用 eval( ) 這項功能。
練習-40 使用 eval( ) 來處理觀看者輸入的數字
這練習是重複上個例子, 但加多了 eval( ) 來處理輸入的數字。
1. 請用瀏覽器開啟示範磁碟中的 , 這網頁有以下內容:
2. 網頁開啟後, 你會見到一個 prompt 對話盒, 請你輸入一個數字, 按 [確定], 看與上個例子有何不同。
在今次例子, x=eval(x) 是將x放進 eval( ) 內變成數值, 然後再用 x 這變數來代表, 因此 (x + 100) 就會將兩個數字加起。
除了使用 eval( ), 我們也可使用 parseInt( ) 或 parseFloat( ), 請看隨後這兩段的資料。
NaN 是 Not a Number 的簡寫, isNaN( ) 是用來檢查一項資料是否 "不是數字", 使用這語法: isNaN(testValue), 這 testValue 就是要檢查的資料, 若不是數字 (即是文字), 就傳回 true 這字, 若是數字, 就傳回 false, 請看以下例子。
練習-41 使用 isNaN 來檢查輸入的資料是否數字
這練習的網頁有一個文字框及要求觀看者輸入一個數字, 當觀看者輸入一個數字及按 [OK] 的按鈕, 就會啟動 isNaN( ) 這功能來檢查輸入的是否一個數字。
1. 請用瀏覽器開啟示範磁碟中的 , 這網頁有以下內容:
2. 網頁開啟後, 請你在文字框輸入一個數字, 然後按 [OK], 看有什麼反應, 再在文字框輸入文字, 看有何不同。
這用來將一個物件變為數字, 使用這語法: Number(obj) , obj 是代表一個物件, 例如我們將一個 Date 物件放進 Number( ) 內, 如下:
若是 Date object, Number( )
會將這物件變為自 1970 年起計算的微秒數值 (請看
第 14 章 ), 若是正數,
就是這日期之後, 若是負數, 則是這日期之前,
這例子的 Dec 25, 1990 會得出 662054400000 的數值,
若是 Dec 25, 1950, 就會得出
-600249600000 的數值。
若是 Number(true), 這會得出1, 若是 Number(false), 會得出 0, 若是其他沒有數值相連的物件, 這功能會傳回 NaN, 表示 Not a Number。
這是 parse integer (抽取整數), 是將一個字串變為十進位的整數, 使用這語法: parseInt(string, radix), 這 radix 是這 string 的進位基數, 無指定就是十進位。若 parseInt( ) 遇到不是數值的字串, 就會傳回 NaN 的訊息。若遇到數字及字母混雜, 就會抽取至字母前的位置。
例 1 : x=parseInt(13.12, 10) 或 x=parseInt(13.12)
(13.12, 10 ) 表示這 13.12 是十進位數字, 我們也可略去這 10 字, 無指明這 radix, 就表示是十進位, 經過 parseInt( ) 的處理, x 會等於 13。
例 2 : x=parseInt(13.12, 16)
(13.12, 16) 表示這 13.12 是十六進位數字, 經過 parseInt( ) 的處理, 13.12 變為整數 13, 再轉為十進位數字, 所以 x 會等於 19。
十六進位可以有 A 至 F 這六個數字, 若數值中有這六個數字, 就要放在 " " 內, 例如 parseInt("2F", 16), 這會得出 47 的十進位數字。
例 3 : x=parseInt(110100, 2)
(110100, 2) 表示這 110100 是二進位數字, 經過 parseInt( ) 轉為十進位數字, 所以x會等於 52。
例 4 : 若 parseInt( ) 遇到數字及字母混雜的字串, 就會抽取至字母前的位置, 留意這字串要放在 " " 內, 若字母是在第一個位置, 就會傳回 NaN, 例如:
x=parseInt("34.5th")
( x 會等於 34
)
x=parseInt("Version3.4")
( x 會等於 NaN )
例 5 : parseInt( ) 也可以將文字式的字串變為數字, 例如 x="34.5", 這 34.5 是放在 " " 內, 所以會作為文字來處理, 但 parseInt( ) 會將這文字抽出來變為整數, 例如:
x=parseInt("34.5 is the result.") ( x 會等於 34 )
請同時參看 練習-67 中使用 parseInt( ) 的例子。
這是 parse floating number (抽取浮點數), 是將一個字串之首的浮點數 (有小數點的數字) 抽出來, 使用這語法: parseInt(value), 若 parseFloat( ) 遇到不是數值的物件, 就會傳回 NaN 的訊息。
例 1 : 例如 x=parseFloat(13.12) ( x 會等於 13.12 )
例 2 : 例如 x=parseFloat("13.12version") ( x 會等於 13.12 )
若數值是數字及字母混雜的字串, 要放在 " " 內, parseFloat( ) 會抽取數字至字母前的位置, 若字母是在首位置, 就傳回 NaN。
parseFloat( ) 也可以將文字式的字串變為數字, 在 練習-40 , 你看到如何使用eval( ) 來指定將輸入的數字作為數值來處理, 這項功能也可使用 parseInt( ) (只要整數的部份) 或 parseFloat( ), 例如 練習-40 可有以下寫法。
這處的 x=parseFloat(x) 是將觀看者輸入的資料作為數字來處理。
( 第 4 章完 )