- jQuery即學即用
- 王志剛編著
- 1582字
- 2019-01-09 16:34:21
第2章 JavaScript語法基礎
無論使用何種JavaScript程序庫,都必須使用基本的JavaScript語句來調用。因此在學習jQuery前,有必要先了解一下JavaScript的基本知識。對那些已經掌握了JavaScript編程知識的讀者,可以跳過本章,直接進入下一章的學習。
2.1 JavaScript的語言基礎
2.1.1 在HTML/xHTML文檔內插入JavaScript
使用標記<script>…</script>可以在HTML/xHTML文檔的任意處,甚至在<HTML>之前插入JavaScript。如果要在聲明框架的網頁(框架網頁)中插入,則一定要在<frameset>之前插入;否則不會運行。
基本格式如下:
<script> <!-- ... (JavaScript代碼) ... //--> </script>
第2行和第4行的作用是讓不能識別<script>標記的瀏覽器忽略JavaScript代碼,一般可以省略。第4行前的雙反斜杠“//”是JavaScript的注釋標號。
另外一種插入JavaScript的方法是把JavaScript代碼寫到另一個文件中(此文件通常用“.js”作為擴展名),然后用格式為“<script src="javascript.js"></script>”的標記將其嵌入到文檔中。注意,一定要用“</script& gt;”標記。
<script>標記還有一個屬性“language”(縮寫為“lang”),說明腳本使用的語言,在JavaScript中為“language="JavaScript"”。
相對于<script>,還有一個<server>標記,其中包含服務器端(Server Side)的腳本。本書只討論客戶端(Client Side)的JavaScript,即使用<script>標記包含的腳本。
如果要在瀏覽器的“地址”欄中執行JavaScript語句,則使用如下格式:
javascript:<JavaScript語句>
這樣的格式也可以用在鏈接中:
<a href="javascript:<JavaScript語句>">...</a>
2.1.2 JavaScript基本語法
每一句JavaScript都有如下類似格式:
<語句>;
其中分號“;”是JavaScript語言的語句結束標識符。雖然現在很多瀏覽器允許使用回車符,但是使用分號仍然是很好的習慣。
語句塊用花括號“{ }”括起,其中可包含多個語句,在花括號外邊的語句塊被作為一個語句。語句塊可以嵌套,即一個語句塊中可以包含一個或多個語句塊。
1. 變量
從字面上看,變量是可變的量;從編程角度講,變量是用于存儲某種/某些數值的存儲器。所存儲的值可以是數字、字符或其他內容。
(1)命名變量
命名變量有以下要求。
● 只包含字母、數字和/或下畫線。
● 以字母開頭。
● 不能過長。
● 不能與JavaScript保留字(Key Words或Reserved Words,凡是可以用來作為JavaScript命令的字都是保留字)重復。
變量區分大小寫,如variable和Variable是兩個不同的變量。
提示
命名變量最好避免用單個字母如“a”、“b”和“c”等,而使用能清楚表達該變量在程序中作用的詞語。這樣不僅他人更容易了解程序,而且在以后要修改程序時也很快會記得該變量的作用。變量名一般用小寫,如果由多個單詞組成,那么第1個單詞用小寫,其他單詞的第1個字母用大寫。例如,myVariable和myAnotherVariable。這樣做僅僅是為了美觀和易讀。因為JavaScript的一些命令都使用這種方法命名,如indexOf和charAt等。
(2)聲明變量
沒有聲明的變量不能使用,否則提示“未定義”。聲明變量可以用如下語句:
var <變量> [= <值>];
var是一個關鍵字(即保留字),用于聲明變量。最簡單的聲明方法是“var <變量>;”,這將為<變量>準備內存,并為其賦初始值“null”。如果加上“= <值>”,則為<變量>賦予自定義初始值。
(3)數據類型
變量的數據類型如下。
● 整型
可以是正整數、0和負整數,可以是十進制、八進制和十六進制。八進制數的表示方法是在數字前加“0”,如“0123”表示八進制數 “123”;十六進制則加“0x”,如“0xEF”表示十六進制數“EF”。
● 浮點型
即“實型”。有資料顯示,某些平臺不能穩定地支持浮點型變量,因此沒有需要就不要用該類型。
● 字符串型
用引號“" "”和“' '”包括的零個或多個字符,可用單引號或雙引號,用哪種引號開始就用哪種引號結束。單雙引號可嵌套使用,如'這里是"JavaScript教程"'。JavaScript中引號的嵌套只能有一層,如果需要多嵌套多層,則使用轉義字符。
由于一些字符在屏幕上不能顯示,或者JavaScript語法上已經有了特殊用途,所以在使用這些字符時必須添加轉義字符。轉義字符用斜杠“\”開頭,如\' 單引號、\" 雙引號、\n換行符和\r回車。使用轉義字符可以實現引號的多重嵌套,如'Micro說:"這里是\"JavaScript教程\"。" '。
● 布爾型
常用于判斷,只有兩個值可選,即true(真)和false(假)。true和false是JavaScript的保留字,屬于常數。
● 對象
見2.2節。
由于JavaScript對數據類型的要求不嚴格,所以一般聲明變量時不需要聲明類型。而且即使聲明了類型,在代碼執行過程中還可以為變量賦予其他類型的值。聲明類型可以用賦予初始值的方法實現,如:
var aString = '';
這將把aString定義為具有空值的字符串型變量。
var anInteger = 0;
這將把anInteger定義為值為0 的整型。
(4)賦值變量
聲明一個變量后可以在任何時候用如下語法為其賦值:
<變量> = <表達式>;
其中“=”為“賦值符”,作用是把右邊的值賦給左邊的變量。
2. 常數
JavaScript的常數如下。
(1)null
一個特殊的空值。當變量未定義或者定義后未執行賦值操作,則其值為“null”。試圖返回一個不存在的對象時也會出現null值。
(2)NaN “Not a Number”
當運算無法返回正確的數值時,會返回“NaN”值。該值非常特殊,因其不是數字,所以任何數均與其不等,甚至NaN本身也不等于NaN。
(3)true
布爾值真。
(4)false
布爾值假。
3. 表達式與運算符
(1)表達式
與數學中的定義相似,指具有一定值并用運算符連接常數和變量的代數式。一個表達式可以只包含一個常數或一個變量。
(2)運算符
運算符包括四則運算符、關系運算符、位運算符、邏輯運算符和復合運算符等,這些運算符及其從高到低的優先級如表2-1所示。
表2-1 運算符及其從高到低的優先級

提示
(1)所有與四則運算有關的運算符都不能用在字符串型變量中,可以使用 +和+= 連接兩個字符串。
(2)如果編程時不記得運算符的優先級,可以使用括號( )。例如,(a == 0)||(b ==0)。
由于一些用來賦值的表達式有返回值,所以可加以利用。例如,語句a = b = c =10可以一次為3個變量賦值。
4. 語句
JavaScript的基本編程命令稱為“語句”。
(1)注釋
在腳本運行時忽略注釋語句,JavaScript注釋語句包括單行和多行注釋語句,單行注釋語句用雙反斜杠“//”開始,其后部分將被忽略;而多行注釋語句是用“/*”和 “*/”括起的一行或多行文本。程序執行到“/*”處,將忽略其后的所有內容,直到出現“*/”為止。
提示
養成寫注釋的習慣能節省寶貴的開發和維護程序的時間。在程序調試時,有時需要把一段代碼換成另一段或者暫時不需要一段代碼。這時最忌刪除代碼,應用中使用注釋語句注釋暫時不需要的代碼。
(2)if語句
其格式如下:
if ( <條件> ) <語句1> [ else <語句2> ];
本語句類似條件表達式“?:”,當<條件>為真時執行<語句1>;否則執行<語句2>。與“?:”不同,if只是一條語句,不會返回數值。<條件>是布爾值,必須用尖括號括起。<語句1>和<語句2>只能是一個語句,多條語句可使用語句塊。
看下例:
if (a == 1) if (b == 0) alert(a+b); else alert(a-b);
本例試圖用縮進方法說明else對應if (a == 1),但是實際上else與if (b == 0) 對應。正確的代碼如下:
if (a == 1) { if (b == 0) alert(a+b); } else { alert(a-b); }
提示
一行代碼過長或者涉及比較復雜的嵌套,可以考慮用多行代碼。如上例,if (a == 1)后面沒有語句,而是換一行繼續寫。使用縮進也是很好的習慣,當一些語句與上面的一兩個語句有從屬關系時使用縮進能使程序更易讀。
(3)for語句
其格式如下:
for (<變量>=<初始值>; <循環條件>; <變量累加方法>) <語句>;
本語句的作用是重復執行<語句>,直到<循環條件>為false為止。執行過程是首先為<變量>賦<初始值>,然后判斷<循環條件>(應該是一個關于變量的條件表達式)是否成立。如果成立,則執行<語句>,即按<變量累加方法>累加<變量>;否則退出循環,稱為“for循環”。
看下例:
for (i = 1; i < 10; i++) document.write(i);
本例首先為i賦初始值1,然后執行document.write(i)語句(在文檔中寫i值)。重復i++,即i加1。循環直到i>=10結束,結果是在文檔中輸出“123456789”。
<語句>只能是一行語句,如果需要多條語句,則使用語句塊。
for循環沒有規定循環變量,每次循環一定要加1或減1,<變量累加方法>可以是任意的賦值表達式,如i+=3、i*=2和i-=j等都成立。
提示
適當使用for循環語句可簡化HTML文檔中大量有規律的重復部分,即使用for循環重復寫一些HTML代碼達到提高網頁下載速度的目的。不過應在Netscape中重復嚴格測試,保證通過后上傳網頁,筆者多次試過因為用for循環向文檔重復寫HTML代碼而導致Netscape“猝死”,IE中沒有這種情況發生。
(4)while語句
其格式如下:
while (<循環條件>) <語句>;
while語句的作用是當滿足<循環條件>時執行<語句>,一般情況下<語句>使用語句塊。因為除了要重復執行某些語句之外,還需要一些改變<循環條件>所涉及變量值的語句;否則就會因為條件總是滿足而產生“死循環”。
(5)break和continue語句
有時在循環體內需要立即跳出循環或跳過循環體內其余代碼而執行下一次循環,break語句放在循環體內,作用是立即跳出循環;continue語句放在循環體內,作用是中止本次循環并執行下一次循環。如果循環的條件已經不符合,則跳出循環。
看下例:
for (i = 1; i < 10; i++) { if (i == 3 || i == 5 || i == 8) continue; document.write(i); }
輸出結果為124679。
(6)switch語句
如果要把某些數據分類,如按優、良、中和差分類學生的成績,則可以使用if語句:
if (score >= 0 && score < 60) { result = 'fail'; } else if (score < 80) { result = 'pass'; } else if (score < 90) { result = 'good'; } else if (score <= 100) { result = 'excellent'; } else { result = 'error'; }
使用過多的if語句導致程序看起來有些亂,使用switch語句是解決這個問題的最好方法:
switch (e) { case r1: ... [break;] case r2: ... [break;] ... [default: ...] }
上述代碼計算e的值(e為表達式),然后與下邊“case”后的r1、r2……比較。當找到一個相等于e的值時,則執行該“case”后的語句,直到遇到break或switch語句塊結束(“}”);如果沒有一個值與e匹配,則執行“default:”后邊的語句。如果沒有default塊,switch語句結束。
上述if代碼段用switch改寫后為:
switch (parseInt(score / 10)) { case 0: case 1: case 2: case 3: case 4: case 5: result = 'fail'; break; case 6: case 7: result = 'pass'; break; case 8: result = 'good'; break; case 9: result = 'excellent'; break; default: if (score == 100) result = 'excellent'; else result = 'error'; }
其中parseInt()方法的作用是取整,最后default段使用if語句是為了不把100 分作為錯誤處理(parseInt(100 / 10) == 10)。
2.2 對象化編程
JavaScript使用“對象化編程”,即面向對象編程。對象化編程指將JavaScript涉及的范圍劃分為對象,對象下面繼續劃分對象,直至詳盡為止。所有編程都以對象為出發點。小到一個變量,大到網頁文檔、窗口,甚至屏幕等都是對象。
2.2.1 對象的基本知識
對象是可以從JavaScript“勢力范圍”中劃分出來的一塊內容,可以是一段文字、一幅圖片或一個表單(Form)等。每個對象有自己的屬性、方法和事件,對象的屬性反映該對象的某些特定性質,如字符串長度、圖像長寬及文本框(Textbox)中的文本等;對象的方法為該對象可執行的操作,如表單的“提交”(Submit)和窗口的“滾動”(Scrolling)等;對象的事件為該對象可以響應的操作,如提交表單產生表單的“提交事件”和單擊鏈接產生的“單擊事件”。有些對象沒有事件,有些只有屬性。引用對象的任一“性質”使用“<對象名>.<性質名>”方法。
2.2.2 基本對象
1.Number
即數字對象,這個對象用得很少,大多用于變量。
(1)屬性
● MAX_VALUE :Number.MAX_VALUE返回“最大值”。
● MIN_VALUE :Number.MIN_VALUE返回“最小值”。
● NaN :Number.NaN或NaN返回“NaN”。
● NEGATIVE_INFINITY :Number.NEGATIVE_INFINITY返回負無窮大,即比最小值還小的值。
● POSITIVE_INFINITY :Number.POSITIVE_INFINITY返回正無窮大,即比最大值還大的值。
(2)方法
toString() 用法為<數值變量>.toString()返回字符串形式的數值。如a == 123,則a.toString() == '123'。
2.String
即字符串對象,聲明一個字符串對象最簡單、快捷、有效和常用的方法是直接賦值。
(1)屬性
length :<字符串對象>.length,返回該字符串的長度。
(2)方法
● charAt() :<字符串對象>.charAt(<位置>),返回該字符串位于第<位置>位的單個字符。字符串中的第1個字符為第0位,第2個為第1位,最后一個字符為第length -1位。
● charCodeAt() :<字符串對象>.charCodeAt(<位置>),返回該字符串位于第<位置>位的單個字符的ASCII碼。
● fromCharCode() :String.fromCharCode(a, b, c...),返回一個字符串,其中每個字符的ASCII碼由a, b, c... 等來確定。
● indexOf() :<字符串對象>.indexOf(<另一個字符串對象>[, <起始位置>]),在<字符串對象>中查找<另一個字符串對象>(如果給出<起始位置>,則忽略之前的位置)。如果找到,返回其位置;否則返回-1。所有位置都從0開始。
● lastIndexOf() :<字符串對象>.lastIndexOf(<另一個字符串對象>[, <起始位置>])與indexOf() 相似,不過是從后邊開始查找的。
● split() :<字符串對象>.split(<分隔符字符>),返回一個數組,該數組從<字符串對象>中分離而來,<分隔符字符>決定了分離處,它本身不會包含在所返回的數組中。如'1&2&345&678'.split('&')返回數組1,2,345,678。
● substring() :<字符串對象>.substring(<始>[, <終>]),返回原字符串的子字符串,該字符串是原字符串從<始>位置到<終>位置的前一位置的一段,< 終> - <始> =返回字符串的長度(length)。如果沒有指定<終>或指定了超過字符串長度,則子字符串從<始>位置一直取到原字符串尾;如果指定的位置不能返回字符串,則返回空字符串。
● substr() :<字符串對象>.substr(<始>[, <長>]),返回原字符串的子字符串,該字符串是原字符串從<始>位置開始,長度為<長>的一段。如果沒有指定<長>或指定了超過字符串長度,則子字符串從<始>位置一直取到原字符串尾;如果指定的位置不能返回字符串,則返回空字符串。
● toLowerCase() :<字符串對象>.toLowerCase(),返回把原字符串所有大寫字母都變成小寫的字符串。
● toUpperCase() :<字符串對象>.toUpperCase(),返回把原字符串所有小寫字母都變成大寫的字符串。
3.Array
數組對象,是一個對象的集合,其中的對象可以是不同類型的。數組的每一個成員對象都有一個下標,用來表示它在數組中的位置(從0開始)。
數組的定義方法如下:
var <數組名> = new Array();
這樣定義了一個空數組,添加數組元素的語句如下:
<數組名>[<下標>] = ...;
注意這里的方括號用于括起數組的下標。
如果要在定義數組時直接初始化數據,則使用如下語句:
var <數組名> = new Array(<元素1>, <元素2>, <元素3>...);
例如,var myArray = new Array(1, 4.5, 'Hi'); 定義了一個數組myArray,其中的元素是myArray[0] == 1、myArray[1] == 4.5和myArray[2] == 'Hi'。
如果元素列表中只有一個元素,而且又是一個正整數,則定義一個包含<正整數>個空元素的數組。
提示
JavaScript只有一維數組,千萬不要用“Array(3,4)”這種方法來定義4 × 5 的二維數組,或者用“myArray[2,3]”這種方法來返回“二維數組”中的元素。如果使用“myArray[...,3]”這種形式的調用,則返回“myArray[3]”。要使用多維數組,則使用如下虛擬法:
var myArray = new Array(new Array(), new Array(), new Array(), ...);
其實這是一個一維數組,其中的每一個元素又是一個數組,調用這個“二維數組”的元素使用myArray[2][3] = ...語句。
(1)屬性
length :<數組對象>.length,返回數組的長度。即數組中的元素數,等于數組中最后一個元素的下標加1,所以添加一個元素只需使用myArray[myArray.length] = ...語句。
(2)方法
● join() :<數組對象>.join(<分隔符>),返回一個字符串。該字符串把數組中的各個元素串起,用<分隔符>置于元素之間。這個方法不影響數組的原值。
● reverse() :<數組對象>.reverse(),使數組中的元素順序反過來。如果對數組[1, 2, 3]使用這個方法,則為[3, 2, 1]。
● slice() :<數組對象>.slice(<始>[, <終>]),返回一個數組,該數組是原數組的子集。始于<始>,終于<終>。如果未給出<終>,則子集一直取到原數組的結尾。
● sort() :<數組對象>.sort([<方法函數>]),使數組中的元素按照一定的順序排列。如果未指定<方法函數>,則按字母順序排列。在這種情況下,8排在9前;如果指定了<方法函數>,則按指定的方法排序。
如按升序排列數字:
function sortMethod(a, b) { return a - b; } myArray.sort(sortMethod);
按降序排列數字則把上面的“a - b”換為“b - a”。
4. Math
數學對象,提供數據的數學計算,在使用時記住“Math.<名>”這種格式。
(1)屬性
● E:返回常數e(2.718281828...)。
● LN2:返回2的自然對數(ln 2)。
● LN10:返回10的自然對數(ln 10)。
● LOG2E:返回以2為底的e的對數(log2e)。
● LOG10E:返回以10為底的e的對數(log10e)。
● PI:返回π(3.1415926535...)。
● SQRT1_2:返回1/2的平方根。
● SQRT2:返回2的平方根。
(2)方法
● abs(x):返回 x 的絕對值。
● acos(x):返回 x 的反余弦值(余弦值等于 x 的角度),用弧度表示。
● asin(x):返回 x 的反正弦值。
● atan(x):返回 x 的反正切值。
● atan2(x, y):返回復平面內點(x, y)對應的復數的幅角,用弧度表示,其值為 -π ~ π。
● ceil(x):返回大于等于 x 的最小整數。
● cos(x):返回 x 的余弦。
● exp(x):返回e的 x 次冪(ex)。
● floor(x):返回小于等于 x 的最大整數。
● log(x):返回 x 的自然對數(ln x)。
● max(a, b):返回a, b中較大的數。
● min(a, b):返回a, b中較小的數。
● pow(n, m):返回 n 的 m 次冪(nm)。
● random():返回大于0小于1的一個隨機數。
● round(x):返回x 四舍五入后的值。
● sin(x):返回x 的正弦。
● sqrt(x):返回x 的平方根。
● tan(x):返回x 的正切。
5. Date
日期對象,用于保存任意一個日期,范圍為0001年-9999年,并且可以精確到毫秒(1/1000秒)。在內部日期對象是一個整數,從1970年1月1日零時整開始計算到日期對象指日期的毫秒數。如果所指日期比1970年早,則是一個負數;如果所有日期時間未指定時區,則采用UTC(世界時)時區,它與GMT(格林尼治時間)在數值上相同。
定義一個日期對象:
var d = new Date;
這個方法使d成為日期對象,并且已有初始值,即當前時間。如果要自定義初始值,可以使用:
var d = new Date(99, 10, 1); //99 年 10 月 1 日 var d = new Date(‘Oct 1, 1999’); //99 年 10 月 1 日
等方法。
以下有很多“g/set[UTC]XXX”這樣的方法,表示既有“getXXX”方法,又有“setxxx”方法。“get”獲得某個數值,而“set”設定某個數值。如果帶有“UTC”字母,則表示獲得/設定的數值基于UTC時間;否則基于本地時間或瀏覽器的默認時間。
如無說明,方法的使用格式為“<對象>.<方法>”。
日期對象的方法如下。
(1)g/set[UTC]FullYear():返回/設置年份,用4位數表示。如果使用“x.set[UTC] FullYear(99)”,則年份被設定為0099 年。
(2)g/set[UTC]Year():返回/設置年份,用兩位數表示。設定時瀏覽器自動加上“19”開頭,故使用 “x.set[UTC]Year(00)”把年份設定為1900 年。
(3)g/set[UTC]Month():返回/設置月份。
(4)g/set[UTC]Date():返回/設置日期。
(5)g/set[UTC]Day():返回/設置星期,0表示星期天。
(6)g/set[UTC]Hours():返回/設置小時數,24小時制。
(7)g/set[UTC]Minutes():返回/設置分鐘數。
(8)g/set[UTC]Seconds():返回/設置秒鐘數。
(9)g/set[UTC]Milliseconds():返回/設置毫秒數。
(10)g/setTime():返回/設置時間,該時間是日期對象從1970 年1 月1 日零時整開始計算到日期對象所指的日期的毫秒數。如果要使某日期對象所指的時間推遲1 小時,則用 “x.setTime(x.getTime() + 60×60×1000);(1小時為60分,1分鐘為60秒,1秒鐘為1000毫秒)語句。
(11)getTimezoneOffset():返回日期對象采用的時區與格林尼治時間所差的分鐘數,在格林尼治東方的時區,該值為負。例如,中國時區(GMT+0800)返回“-480”。
(12)toString():返回一個字符串,描述日期對象所指的日期,這個字符串的格式類似 “Fri Jul 21 15:43:46 UTC+08002000”。
(13)toLocaleString():返回一個字符串,描述日期對象所指的日期,用本地時間表示格式,如“2000-07-21 15:43:46”。
(14)toGMTString():返回一個字符串,描述日期對象所指的日期,用GMT格式。
(15)toUTCString():返回一個字符串,描述日期對象所指的日期,用UTC格式。
(16)parse() 用法:Date.parse(<日期對象>);返回該日期對象的內部表達方式。
6. 全局對象
全局對象從不現形,可以說是虛擬出來的,目的在于把全局函數“對象化”。在Microsoft JScript語言參考中稱為“Global對象”,但是引用其方法和屬性應直接使用“xxx”,使用“Global.xxx”格式會出錯。
(1)屬性
NaN如前所述。
(2)方法
● eval():把括號內的字符串作為標準語句或表達式執行。
● isFinite() :如果括號內的數字是有限的(Number.MIN_VALUE~Number.MAX_VALUE),則返回true;否則返回false。
● isNaN():如果括號內的值是NaN,則返回true;否則返回false。
● parseInt():返回把括號內的內容轉換為整數之后的值,如果括號內是字符串,則字符串開頭的數字部分被轉換為整數;如果以字母開頭,則返回NaN。
● parseFloat():返回把括號內的字符串轉換為浮點數之后的值,字符串開頭的數字部分被轉換為浮點數;如果以字母開頭,則返回NaN。
● toString():<對象>.toString()把對象轉換為字符串,如果在括號中指定一個數值,則轉換過程中所有數值轉換為特定進制。
● escape():返回括號中的字符串經過編碼后的新字符串,該編碼應用于URL,把空格寫成“%20”這種格式。“+”不被編碼,如果要編碼,則用escape('...', 1)語句。
● unescape() : escape() 的反過程。解編括號中字符串成為一般字符串。
2.3 函數
函數是有返回值的對象或對象的方法。
函數的內部有一行或多行語句,這些語句在其他程序調用它時才執行。在執行一個函數時遇到return語句,函數停止執行,并返回調用它的程序。如果return后帶有<值>,則退出函數的同時返回該值。
常見的函數有構造函數(如Array()構造一個數組)、全局函數(即全局對象中的方法)和自定義函數等。
(1)自定義函數
自定義函數使用以下語句:
function函數名([參數集]) { ... [return[ <值>];] ... }
其中不能省略用在function之后和函數結尾的花括號。
函數名與變量名的命名規則相同,即包含字母、數字和下畫線。并且以字母開始,不能與保留字重復等。
參數集可有可無,但括號一定要有。
● 參數
參數是函數外部向函數內部傳遞信息的橋梁,如需要一個函數返回3 的立方,則要讓函數知道3這個數值。為此需要有一個變量來接收數值,即參數。
參數集是一個或多個用逗號分隔開的參數集合,如a, b, c。
在函數的內部參數可以直接作為變量來使用,并可以用var語句來新建一些變量,但是這些變量不能被函數外部的過程調用。要使函數內部的數據能被外部調用,則使用“return”返回值或全局變量。
● 全局變量
在Script的“根部”(非函數內部)的var語句定義的變量即全局變量,它能在整個過程的任意處被調用和更改。
看下例:
function addAll(a, b, c) { return a + b + c; } var total = addAll(3, 4, 5);
這個例子建立一個名“addAll”的函數,它的3個參數是a、b和c。作用是返回3個數的相加結果,在函數外部利用“var total = addAll(3, 4, 5);”接收函數的返回值。
函數一般沒有返回值,這種函數在一些比較強調嚴格的語言中叫做“過程”。例如,Basic類語言的“Sub”和Pascal語言的“procedure”。
● 屬性
Arguments是一個數組,反映外部程序調用函數時指定的參數,其用法是直接在函數內部調用“arguments”。
(2)自定義構造函數
自定義構造函數使用function,并使用其中的this來定義屬性:
function <構造函數名> [(<參數>)] { ... this.<屬性名> = <初始值>; ... }
然后使用new構造函數關鍵字來構造變量:
var <變量名> = new <構造函數名>[(<參數>)];
構造變量后,<變量名>成為一個對象,其屬性使用this設定。
以下是一個從網上找到的搜集瀏覽器詳細資料的自定義構造函數的例子:
function Is() { var agent = navigator.userAgent.toLowerCase(); this.major = parseInt(navigator.appVersion); //主版本號 this.minor = parseFloat(navigator.appVersion); //全版本號 this.ns = ((agent.indexOf('mozilla')!=-1) && ((agent.indexOf(‘spoofer’)==-1) && //是否Netscape (agent.indexOf('compatible') == -1))); this.ns2 = (this.ns && (this.major == 3)); //是否Netscape 2 this.ns3 = (this.ns && (this.major == 3)); //是否Netscape 3 this.ns4b = (this.ns && (this.minor < 4.04)); //是否Netscape 4 低版本 this.ns4 = (this.ns && (this.major >= 4)); //是否Netscape 4 高版本 this.ie = (agent.indexOf(“msie”) != -1); //是否IE this.ie3 = (this.ie && (this.major == 2)); //是否IE 3 this.ie4 = (this.ie && (this.major >= 4)); //是否IE 4 this.op3 = (agent.indexOf(“opera”) != -1); //是否Opera 3 this.win = (agent.indexOf(“win”)!=-1); //是否Windows版本 this.mac = (agent.indexOf(“mac”)!=-1); //是否Macintosh版本 this.unix = (agent.indexOf(“x11”)!=-1); //是否Unix版本 } var is = new Is();
這個構造函數完整地搜集瀏覽器的信息,它為對象定義了多個屬性,如major、minor、ns、ie、win和mac等。把is變量定義為Is() 對象后,使用if (is.ns) 這種格式可以方便地知道瀏覽器的信息。從這個構造函數中也可以看到它使用的是一般的JavaScript語句(例中為var語句)。
再來看一個使用參數的構造函數:
function myFriend(theName, gender, theAge, birthOn, theJob) { this.name = theName; this.isMale = (gender.toLowerCase == 'male'); this.age = theAge; this.birthday = new Date(birthOn); this.job = theJob } var Stephen = new myFriend('Stephen', 'Male', 18, 'Dec 22, 1982', 'Student');
從這個構造函數可以看到參數的用法及不同屬性可用不同的數據型(例中的5個屬性分別為字符串、布爾值、數字、日期和字符串)和構造函數來“構造”屬性。如果使用足夠的“保護措施”來避免無限循環,則可以用構造函數自身來構造自己的屬性。
(3)無名函數(function表達式)
在JavaScript中存在一種不用指定函數名定義函數的方法,用這種方法定義的函數稱為“無名函數”。
在JavaScript中使用無名函數現在已經漸漸變為主流,在學習編寫jQuery的插件前一定要掌握這種編程方法。定義無名函數的語法如下:
function(參數系列){函數的具體內容};
實際上只是沒有指定函數名,其他與普通函數的定義沒有區別。但是因為沒有函數名,所以已經不能使用通常的函數調用方法。調用方法如下:
var變量名= function(參數系列){函數的具體內容}; 變量名(參數值);//函數調用
上面將無名函數賦值給變量,事件、數組和對象也可以這樣為變量賦值,為函數參數賦值等與通常的函數調用沒有區別。
2.3.1 閉包
閉包(closure)是JavaScript語言的一個難點,也是其特色之一,很多高級應用(如jQurey)都要依靠閉包實現。
要理解閉包,首先必須理解JavaScript特殊的變量作用域,變量的作用域包括全局變量和局部變量。JavaScript語言的特殊之處就在于函數內部可以直接讀取全局變量,如下例:
var n='test'; function f1(){ alert(n); } f1(); // test
在函數外部無法讀取函數內的局部變量,如:
function f1(){ var n='test'; } alert(n); // error
注意函數內部聲明變量時一定要使用var命令;否則實際上聲明了一個全局變量,如:
function f1(){ n='test'; } f1(); alert(n); // test
出于種種原因,有時需要得到函數內的局部變量。但是必須通過變通方法實現。即在函數的內部再定義一個函數,如:
function f1(){ var n='test'; function f2(){ alert(n); // test } }
在上面的代碼中,函數f2被包括在函數f1內部。這時f1內部的所有局部變量對f2都是可見的,但是f2內部的局部變量對f1不可見。這就是JavaScript語言特有的“鏈式作用域”結構(chain scope),子對象會一級一級地向上查找所有父對象的變量。所以父對象的所有變量對子對象都是可見的,反之則不成立。
既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,即可在f1外部讀取其內部變量,如:
function f1(){ var n='test'; function f2(){ alert(n); } return f2; } var result=f1(); result(); //test
上面的f2函數就是閉包。
各種專業文獻中有關閉包的定義非常抽象,比較難理解,其實閉包就是能夠讀取其他函數內部變量的函數。由于在JavaScript語言中只有函數內部的子函數才能讀取局部變量,因此可以把閉包簡單理解為定義在一個函數內部的函數。所以在本質上,閉包是連接函數內部和外部的一座橋梁。
閉包的最大用處有兩個,一是前面提到的讀取函數內部的變量;二是讓這些變量的值始終保存在內存中,實現數據共享。下面再看幾個使用無名函數來定義閉包的例子:
var cnt = (function (){ var i=0; return function(){ alert(i); i++; } })(); cnt(); //顯示0 cnt(); //顯示1 cnt(); //顯示2
第1次調用[cnt()]后開始執行無名函數,執行后變量i的值將保存在內存中;第2次調用[cnt()]時將使用內存中保存的i值,因此結果為1。
也可以向閉包內部傳入參數,如下:
var cnt = (function (num){ return function(){ alert(num); num++; } })(5); cnt(); //顯示5 cnt(); //顯示6 cnt(); //顯示7
另外,還可以在調用時指定參數值,如:
var cnt = (function (){ var i = 0; return function(num){ num += i; alert(num); num++; } })(); cnt(5); //顯示5 cnt(6); //顯示7 cnt(7); //顯示9
還可以以哈希表的形式定義多個返回的function函數,如:
var cnt = (function (){ var i = 0; return { counter:function(){ i++; this.getValue(); }, getValue: function(){ return alert(i); } } })(); cnt.counter(); //顯示1 cnt.getValue(); //顯示1 cnt.counter(); //顯示2
2.3.2 基于prototype的對象
Prototype對象在JavaScript中實現面向對象編程的主要功能,通常在生成類(class)和繼承已有類時使用。
在生成的function對象中使用Prototype對象在生成的function對象中追加內容,稱為“基于prototype的對象”,下面是一個簡單的例子:
var cnt = function (){}; cnt.prototype = { i : 0; num:function(){ alert(this.i); this.i++; } }; var c = new cnt(); c.num(); //顯示0 c.num(); //顯示1 c.num(); //顯示2
作為高級的JavaScript編程方法,在編寫庫或框架時會用到閉包和Prototype對象。
2.3.3 with語句和this對象
1. with語句
該語句為一個或一組語句指定默認對象。
用法:
with (<對象>) <語句>;
with語句通常用來縮短特定情形下必須寫的代碼量,在下例中注意Math的重復使用:
x = Math.cos(3 * Math.PI) + Math.sin(Math.LN10); y = Math.tan(14 * Math.E);
當使用with語句時,代碼變得更短且更易讀:
with (Math) { x = cos(3 * PI) + sin(LN10); y = tan(14 * E); }
2. this對象
該對象返回當前對象,在不同處this代表不同的對象。如果在JavaScript的主程序,而不在任何function和事件處理程序中使用this,則代表window對象;如果在with語句塊中使用this,則代表with所指定的對象;如果在事件處理程序中使用this,則代表發生事件的對象。
一個常用的this用法如下:
<script> ... function check(formObj) { ... } ... </script> <body ...> ... <form ...> ... <input type="text" ... onchange="check(this.form)"> ... </form> ... </body>
這個用法常用于檢測表單輸入的有效性。
2.4 事件處理
事件處理是對象化編程的一個很重要的環節,沒有事件處理,程序就會缺乏靈活性。事件處理的過程即發生事件,然后啟動事件處理程序做出反應,必須首先告訴對象可能發生的事件及其處理程序;否則這個流程就不能進行下去。事件處理程序可以是任意JavaScript語句,但是一般用特定的自定義函數(function)來處理事件。
2.4.1 指定事件處理程序
指定事件處理程序有如下3種方法。
(1)直接在HTML標記中指定,這種方法運用最為普遍,格式如下:
<標記 ... ... 事件="事件處理程序" [事件="事件處理程序" ...]>
看下例:
<body ... onload="alert('網頁讀取完成,請慢慢欣賞!')" onunload="alert(' 再見!')">
這樣定義的<body>標記能使讀取文檔后彈出一個對話框,提示“網頁讀取完成,請慢慢欣賞!”,并且在用戶退出文檔(或者關閉窗口或者到另一個頁面)時彈出“再見!”。
(2)編寫特定對象特定事件的JavaScript,這種方法用得比較少。但是在某些場合很好用,格式如下:
<script language="JavaScript" for="對象" event="事件"> ... (事件處理程序代碼) ... </script>
例如:
<script language="JavaScript" for="window" event="onload"> alert('網頁讀取完成,請慢慢欣賞!'); </script>
(3)在JavaScript中聲明,格式如下:
<事件主角 - 對象>.<事件> = <事件處理程序>;
用這種方法要注意 “事件處理程序”是真正的代碼,而不是字符串形式的代碼。如果事件處理程序是一個自定義函數,如無使用參數的需要,則不要加圓括號 “()”。例如:
... function ignoreError() { return true; } ... window.onerror = ignoreError; // 沒有使用“()”
這個例子將ignoreError() 函數定義為window對象的onerror事件的處理程序,作用是忽略該window對象下任何錯誤(由引用不允許訪問的location對象產生的“沒有權限”錯誤不能被忽略)。
2.4.2 常用事件
常用事件如下。
(1)onblur事件:發生在窗口失去焦點時。
應用于window對象。
(2)onchange事件:發生在文本輸入區的內容被更改,然后焦點從文本輸入區移走之后。捕捉此事件主要用于實時檢測輸入的有效性,或者立即改變文檔內容。
應用于Password、Select、Text和Textarea對象。
(3)onclick事件:發生在對象被單擊時。
一個普通按鈕對象(Button)通常會有onclick事件處理程序,因為這種對象不能從用戶處得到任何信息。為按鈕添加onclick事件處理程序可以模擬另一個“提交”按鈕的方法是在事件處理程序中更改表單的action、target、encoding和method等一個或多個屬性,然后調用表單的submit()方法。
在Link對象的onclick事件處理程序中返回false值,能阻止瀏覽器打開此鏈接。如果有一個鏈接為<a onclick="return false">Go!</a>,那么無論用戶如何單擊,都不會打開www.a.com網站;除非用戶禁止瀏覽器運行JavaScript。
應用于Button、Checkbox、Image、Link、Radio、Reset和Submit對象。
(4)onerror事件:發生在錯誤發生時,其事件處理程序通常叫做“錯誤處理程序”(Error Handler)。要忽略一切錯誤,則使用如下代碼:
function ignoreError() { return true; } window.onerror = ignoreError;
應用于window對象。
(5)onfocus事件:發生在窗口得到焦點時。
應用于window對象。
(6)onload事件:發生在文檔全部下載完畢時,意味著不但HTML文件,而且包含的圖片、插件、控件和小程序等全部內容都下載完畢。本事件是window事件,但是在HTML中指定事件處理程序時將寫在<body>標記中。
應用于window對象。
(7)onmousedown事件:發生在用戶把鼠標放在對象上并按下鼠標鍵時,參考onmouseup事件。
應用于Button和Link對象。
(8)onmouseout事件:發生在鼠標離開對象時,參考onmouseover事件。
應用于Link對象。
(9)onmouseover事件:發生在鼠標進入對象范圍時,這個事件和onmouseout事件加上圖片的預讀,即可實現當鼠標移到圖像鏈接上更改圖像的效果。有時在指向一個鏈接時狀態欄中未顯示地址,而顯示其他信息,并且看起來這些信息可以隨時更改。這個效果的實現如下:
<a href="..." onmouseover="window.status='Click Me Please!'; return true;" onmouseout="window.status=''; return true;">
應用于Link對象。
(10)onmouseup事件:發生在用戶把鼠標放在對象上且按下鼠標鍵,然后放開鼠標鍵時。如果按下鼠標鍵時,鼠標并不在放開鼠標的對象上,則不會發生本事件。
應用于Button和Link對象。
(11)onreset事件:發生在單擊表單的“重置”按鈕時,通過在事件處理程序中返回false值可以阻止表單重置。
應用于Form對象。
(12)onresize事件:發生在調整窗口大小時。
應用于window對象。
(13)onsubmit事件:發生在單擊表單中的“提交”按鈕時,可以使用該事件來驗證表單的有效性,并且通過在事件處理程序中返回false值可以阻止提交表單。
應用于Form對象。
(14)onunload事件:發生在用戶退出文檔(或者關閉窗口,或者打開另一個頁面)時,與onload一樣,要放在HTML中的<body>標記中。
有的Web Masters用這個方法來彈出“調查表單”,以“強迫”來訪者填寫;有的彈出廣告窗口,誘使來訪者單擊鏈接。
應用于Window對象。
2.5 DOM
W3C已于2000年11月13日推出了DOM level 2規范,DOM(Document Object Model,文檔對象模型)是HTML和XML文檔的編程接口規范。由于與平臺和語言無關,因而可以用多種語言并在多種平臺上實現。
該規范定義了HTML和XML文件在內存中的文檔結構,提供了訪問和存取HTML和XML文件的方法。利用DOM規范,可以實現DOM和XML文檔之間的相互轉換,并對相應DOM文檔的內容執行遍歷或其他操作。要想自由地操作XML文件,則會用到DOM規范。
DOM的原理簡單地說就是通過解析XML文檔,為其在邏輯上建立一個樹模型。樹的節點是一個個對象,通過存取這些對象即可操作XML文檔中的內容。
在jQuery中使用DOM來處理HTML/xHTML文檔,提供取得父節點和子節點的函數。
2.6 Ajax
Ajax(Asynchronous JavaScript and XML)用來描述一組技術,使瀏覽器可以為用戶提供更為自然的瀏覽體驗。在Ajax之前,Web站點強制用戶進入提交/等待/重新顯示范例,用戶的動作總是與服務器的“思考時間”同步。Ajax提供與服務器異步通信的能力,從而使用戶從請求/響應的循環中解脫出來。借助于Ajax可以在用戶單擊按鈕時使用JavaScript和DHTML立即更新UI,并向服務器發出異步請求,以執行更新或查詢數據庫。當請求返回時,就可以使用JavaScript和CSS來相應地更新UI,而不是刷新整個頁面。最重要的是,用戶甚至不知道瀏覽器正在與服務器通信,Web站點看起來是即時響應的。
雖然Ajax所需的基礎架構已經出現了一段時間,但直到Google公司在Google Maps中應用該技術,這種異步請求技術的真正威力才廣為網絡技術人員所認知。能夠擁有一個響應極其靈敏的Web站點確實激動人心,因為它最終允許開發人員和設計人員使用標準的HTML/CSS/JavaScript堆棧創建“桌面風格”(desktop-like)且可用性強的Web應用程序。
根據Ajax提出者Jesse James Garrett的建議,Ajax技術應該包含如下特征。
(1)使用xHTML+CSS來表示信息。
(2)使用JavaScript操作DOM實現動態顯示及交互。
(3)使用XML和XSLT執行數據交換及相關操作。
(4)使用XMLHttpRequest對象與Web服務器執行異步數據交換。
(5)使用JavaScript將所有內容綁定在一起。
因此Ajax技術類似DHTML或LAMP,不是指一種單一的技術,而是有機地利用了一系列相關的技術,并且與服務器端應用程序(PHP、Perl、Java和DB等)組合來構建Web應用程序的解決方案總稱。