- JavaScript前端開(kāi)發(fā)模塊化教程
- 趙建保
- 8770字
- 2019-12-20 19:23:32
2.3 核心知識(shí)
2.3.1 表格常用標(biāo)簽
<table>元素用來(lái)創(chuàng)建表格,最簡(jiǎn)單的表格由一個(gè)<table>元素構(gòu)成,其中包含一個(gè)或多個(gè)行元素<tr>,每一行又包含一個(gè)或多個(gè)數(shù)據(jù)單元格<td>或表頭單元格<th>。表頭單元格用于顯示說(shuō)明列和行用途的標(biāo)題文字,行或列可以沒(méi)有表頭單元格,也可以有多行或多列表頭單元格。數(shù)據(jù)單元格可以包含任意內(nèi)容,包括嵌套表格、塊級(jí)元素、文字和對(duì)象。通常表頭單元格放置標(biāo)題文字,數(shù)據(jù)單元格顯示表格式數(shù)據(jù),如表2-1所示。
表2-1 table相關(guān)標(biāo)簽

為方便對(duì)表格進(jìn)行模塊化樣式設(shè)置,可以對(duì)表格進(jìn)行行與列的分組,形成更為完整的表格結(jié)構(gòu)。選用thead標(biāo)記表頭行組,選用tbody標(biāo)記表體行組,選用tfoot標(biāo)記表腳行組,選用colgroup標(biāo)記列組,選用col標(biāo)記列(col列沒(méi)有尾標(biāo)記)。caption元素定義表格標(biāo)題,每個(gè)表格僅定義一個(gè)標(biāo)題,一般放置在table標(biāo)簽之后,該標(biāo)題會(huì)被居中于表格之上,可通過(guò)樣式屬性caption-side設(shè)置標(biāo)題在表格中的位置,默認(rèn)top值時(shí)標(biāo)題定位在表格第一行上邊,設(shè)置為bottom值時(shí)標(biāo)題定位在表格最后一行下邊。一般表格結(jié)構(gòu)如下:
<table> <caption> 項(xiàng)目成員通信錄</caption> <thead> <tr> <th> 姓名</th> <th> 手機(jī)號(hào)碼</th> <th> 電子郵箱</th> </tr> </thead> <tbody> <tr> <td> 趙建保</td> <td>1353876xxxx</td> <td>mpcer@163.com</td> </tr> </tbody> <tfoot> <tr> <th> 姓名</th> <th> 手機(jī)號(hào)碼</th> <th> 電子郵箱</th> </tr> </tfoot> </table>
表格行可以包含任意數(shù)量的<tbody>元素,但是最多只能包含一個(gè)<thead>和一個(gè)<tfoot>,這是因?yàn)闉g覽器在每個(gè)表格中只能顯示一個(gè)表頭和表腳分組,通常表頭分組位于表開(kāi)頭,而表腳分組位于表末尾,thead/tbody/tfoot的顯示位置與代碼順序無(wú)關(guān)。即使表腳各行的HTML代碼位于表體代碼之前也如此。
表格層次結(jié)構(gòu)按從下至上的堆疊順序?yàn)楸砀瘢╰able)>列組(colgroup)>列(col)>行組(thead、tbody、tfoot)>行(tr)>單元格(td)。后一個(gè)樣式會(huì)覆蓋前一個(gè)結(jié)構(gòu)相同的樣式,比如背景(background)。包含表格的HTML頁(yè)面從底層的到頂層的結(jié)構(gòu)分別是html、body、table、表格標(biāo)題(caption)、行組(thead、tbody、tfoot)、行(tr)、單元格(td或th)。
2.3.2 表格斑馬線原理
表格斑馬線能夠美化表格和提高閱讀效率,避免閱讀表格行時(shí)跳行,其實(shí)現(xiàn)原理是通過(guò)周期性地設(shè)置表格行(tr)的背景顏色屬性來(lái)實(shí)現(xiàn),具體思路是:把HTML頁(yè)面文檔里所有table元素找出來(lái),對(duì)每個(gè)table元素的所有行(tr)進(jìn)行遍歷,依照斑馬線變化周期設(shè)置tr背景樣式即可。
2.3.3 讀寫HTML DOM className屬性
HTML DOM className屬性可設(shè)置或返回元素的class屬性值。獲取屬性值的語(yǔ)法如下:
HTMLElementObject.className
設(shè)置屬性值的語(yǔ)法如下:
HTMLElementObject.className=classname
給元素添加class時(shí),如果原來(lái)沒(méi)有設(shè)置過(guò)className屬性,則直接進(jìn)行設(shè)置;如果已經(jīng)設(shè)置過(guò)className屬性,則采用類名稱字符串拼接操作,把新class設(shè)置值追加到classname屬性上。注意,追加的字符串前增加一個(gè)空格,避免新添加的類覆蓋掉原來(lái)設(shè)置的類,可編寫成addClass函數(shù),代碼如下:
function addClass(element, value){ if (element.className) { element.className = value; } else { element.className += " value"; } }
函數(shù)實(shí)現(xiàn)步驟:檢查className屬性值是否為null,如果是,把新的class值直接賦值給className屬性;如果不是,把一個(gè)空格和新的class設(shè)置追加到className屬性上。
所有主要瀏覽器Internet Explorer、Firefox、Opera、Google Chrome和Safari都支持className屬性。
2.3.4 嚴(yán)格模式(use strict)
ECMAScript 5.0新增嚴(yán)格運(yùn)行模式,要求JavaScript在更嚴(yán)格的條件下運(yùn)行。嚴(yán)格模式具有以下好處:①消除JavaScript語(yǔ)法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;②消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全;③提高編譯器的效率和運(yùn)行速度;④為未來(lái)新版本的JavaScript做好鋪墊。“嚴(yán)格模式”體現(xiàn)了JavaScript更合理、更安全、更嚴(yán)謹(jǐn)?shù)陌l(fā)展方向,包括IE10在內(nèi)的主流瀏覽器都已經(jīng)支持它,許多大項(xiàng)目已經(jīng)開(kāi)始全面擁抱它。另一方面,同樣的代碼,在“嚴(yán)格模式”中,可能會(huì)有不一樣的運(yùn)行結(jié)果;一些在“正常模式”下可以運(yùn)行的語(yǔ)句,在“嚴(yán)格模式”下將不能運(yùn)行。掌握這些內(nèi)容,有助于更細(xì)致深入地理解JavaScript,使自己變成一個(gè)更優(yōu)秀的程序員。
啟用嚴(yán)格模式只要在代碼首部加入“use strict”注釋字符串即可,不支持該模式的瀏覽器會(huì)把它當(dāng)作一行普通字符串忽略掉。嚴(yán)格模式有全局模式和局部模式兩種場(chǎng)景。全局模式將“use strict”放在腳本文件的第一行,則整個(gè)腳本都將以嚴(yán)格模式運(yùn)行。如果該語(yǔ)句不在第一行(實(shí)際運(yùn)行的腳本,前面可以有注釋),則無(wú)效,整個(gè)腳本將以正常模式運(yùn)行。如果不同模式的代碼合并成一個(gè)文件,需要特別注意。將“use strict”放在函數(shù)內(nèi)的第一行,則整個(gè)函數(shù)將以嚴(yán)格模式運(yùn)行。因?yàn)槿帜J讲焕谖募喜ⅲ愿玫淖龇ㄊ墙栌镁植磕J降姆椒ǎ瑢⒄麄€(gè)腳本文件放在一個(gè)立即執(zhí)行的匿名函數(shù)中。
(function () { "uses trict"; //JavaScript 代碼 })();
嚴(yán)格模式的限制如下。
? 不允許使用未聲明的變量,對(duì)象也是一個(gè)變量,必須先用var顯式聲明變量,然后才能被使用。
? 不允許刪除變量或?qū)ο螅挥衏onfigurable設(shè)置為true的對(duì)象屬性才能被刪除。
? 不允許刪除函數(shù)。
? 禁止this關(guān)鍵字指向全局對(duì)象。
? 禁止在函數(shù)內(nèi)部遍歷調(diào)用棧。caller、callee和arguments的調(diào)用行為都被禁用。
? 禁止使用with語(yǔ)句。
? 嚴(yán)格模式下會(huì)創(chuàng)設(shè)eval作用域,不再生成全局變量,它所生成的變量只能用于eval內(nèi)部,在作用域eval()創(chuàng)建的變量不能被調(diào)用,在正常模式下,eval語(yǔ)句的作用域取決于它處于全局作用域還是函數(shù)作用域。
? 不允許標(biāo)識(shí)符重名,包括對(duì)象不能有重名的屬性、函數(shù)不能有重名的參數(shù)。
? 不允許使用八進(jìn)制,整數(shù)第一位為0將報(bào)錯(cuò),但在正常模式下,整數(shù)第一位如果是0,表示八進(jìn)制數(shù),如0100為十進(jìn)制的64。
? 不允許使用轉(zhuǎn)義字符。
? 不允許對(duì)只讀屬性賦值,賦值將報(bào)錯(cuò),但在正常模式下,對(duì)一個(gè)對(duì)象的只讀屬性進(jìn)行賦值,失敗時(shí)不會(huì)報(bào)錯(cuò)。
? 不允許對(duì)一個(gè)使用getter方法讀取的屬性進(jìn)行賦值,否則報(bào)錯(cuò)。
? 不允許刪除一個(gè)不允許刪除的屬性,否則報(bào)錯(cuò)。
? 不允許對(duì)禁止擴(kuò)展的對(duì)象添加新屬性,否則報(bào)錯(cuò)。
? 變量名不能使用“eval”字符串。
? 函數(shù)必須聲明在頂層,嚴(yán)格模式只允許在全局作用域或函數(shù)作用域的頂層聲明函數(shù),不允許在非函數(shù)的代碼塊內(nèi)聲明函數(shù)。
? arguments對(duì)象限制,arguments是函數(shù)的參數(shù)對(duì)象,在嚴(yán)格模式下不允許賦值、不再追蹤參數(shù)的變化、禁止使用arguments.callee,無(wú)法在匿名函數(shù)內(nèi)部調(diào)用自身。
? 保留關(guān)鍵字,為了向?qū)?lái)JavaScript的新版本過(guò)渡,嚴(yán)格模式新增了一些保留關(guān)鍵字:implements、interface、let、package、private、protected、public、static、yield。
2.3.5 定義變量
變量用來(lái)存儲(chǔ)數(shù)據(jù),是一個(gè)存放數(shù)值的容器,當(dāng)需要多次使用同一數(shù)據(jù)(比如3.1415926 53589793)或者所存儲(chǔ)的數(shù)據(jù)在初始化之后可能改變時(shí)應(yīng)該使用變量。變量用來(lái)代表某些程序運(yùn)行前還未知的數(shù)據(jù),例如某個(gè)計(jì)算結(jié)果。變量保存的數(shù)據(jù)可以在需要時(shí)設(shè)置、更新或提取,賦給變量的值會(huì)更新變量的類型。變量被創(chuàng)建后不需要再使用var關(guān)鍵字給變量賦予新值,只需要使用變量名、=和新值即可。當(dāng)離開(kāi)頁(yè)面后,瀏覽器就會(huì)刪除變量。
定義變量通常用var操作符,var是variable的縮寫,后跟變量名稱(標(biāo)識(shí)符),聲明變量時(shí),可以使用賦值操作符等于符號(hào)(=)給變量賦初值或者更新變量值,也可以不給變量指定值,未初始化的變量會(huì)保存一個(gè)特殊的值undefined。變量、函數(shù)名和操作符都區(qū)分大小寫。標(biāo)識(shí)符是指變量、函數(shù)、屬性的名字,或者函數(shù)的參數(shù)。
2.3.6 常量
常量在程序運(yùn)行時(shí)值不能改變,主要用于為程序提供固定和精確的值,如數(shù)字、邏輯值等都是常量。通常使用const來(lái)聲明常量。
2.3.7 變量命名規(guī)則
變量命名請(qǐng)遵守以下4條規(guī)則。
(1)變量名必須以字母、下劃線(_)及美元符號(hào)($)開(kāi)頭,不能以數(shù)字開(kāi)頭,以便JavaScript可以輕易區(qū)分標(biāo)識(shí)符和數(shù)字,中間可以是數(shù)字、字母、下劃線和美元符號(hào),但不能包含空格、加號(hào)(+)、減號(hào)(-)、點(diǎn)(。)號(hào)、標(biāo)點(diǎn)符號(hào)(美元符號(hào)$例外),可以用下劃線分隔。
(2)JavaScript變量名嚴(yán)格區(qū)分大小寫。hour與Hour是兩個(gè)不同的變量名,但不建議使用僅有大小寫區(qū)別的變量。
(3)變量名應(yīng)簡(jiǎn)潔明確。變量取名建議:選擇有意義的名稱。_m、r或者foo等標(biāo)識(shí)符含義模糊,不如angle、currentRate更容易理解;創(chuàng)建由多個(gè)單詞組成的變量名時(shí),采用駱駝式拼寫法。按照慣例,JavaScript變量名采用駱駝命名法,JavaScript內(nèi)置的函數(shù)和對(duì)象命名格式保持一致,第一個(gè)字母小寫,剩下的每個(gè)單詞的首字母大寫,例如myCar、doSomethingImportant;少用_或$作為標(biāo)識(shí)符開(kāi)頭。以$開(kāi)頭的標(biāo)識(shí)符通常保留用于JavaScript庫(kù)。
(4)變量名不能使用JavaScript關(guān)鍵字和保留字。關(guān)鍵字是一些特殊的單詞,預(yù)留著未來(lái)版本可能使用的單詞,指定瀏覽器解釋器控制語(yǔ)句的開(kāi)始或結(jié)束,或者用于執(zhí)行特定操作,如var用來(lái)聲明變量。ECMAScript描述了一組具有特定用途的關(guān)鍵字,關(guān)鍵字不能用作標(biāo)識(shí)符,如表2-2所示。
表2-2 JavaScript關(guān)鍵字和保留字

變量的使用通常可分為以下兩個(gè)步驟:聲明變量和初始化變量。變量初始化,實(shí)際上指的是變量的第一次賦值,可先聲明變量,然后初始化,也可以聲明變量與初始化同步進(jìn)行。
2.3.8 JavaScript語(yǔ)法規(guī)范
JavaScript是區(qū)分大小寫的語(yǔ)言。關(guān)鍵字、變量、函數(shù)名和所有的標(biāo)識(shí)符都必須采取一致的大小寫形式,大小寫敏感,這點(diǎn)不同于HTML標(biāo)簽。在輸入關(guān)鍵字、函數(shù)名、變量及其他標(biāo)識(shí)符時(shí),都必須采用正確的大小寫形式。User和user是兩個(gè)不同的變量,hourNow和HourNow是不同的變量。具體的語(yǔ)法規(guī)范如下。
(1)空白無(wú)關(guān)緊要。在標(biāo)識(shí)符前后、運(yùn)算符前后,空格有無(wú)和數(shù)量不影響程序功能。
(2)單雙引號(hào)無(wú)區(qū)別。可以使用單引號(hào)(")和雙引號(hào)("")包括字符串,但最好統(tǒng)一,且不要使用引號(hào)包括布爾值true和false。
(3)每條語(yǔ)句都以分號(hào)(;)結(jié)尾。JavaScript中的語(yǔ)句以一個(gè)分號(hào)結(jié)尾,告訴JavaScript解釋器該條語(yǔ)句執(zhí)行完畢,準(zhǔn)備開(kāi)始執(zhí)行下一個(gè)步驟。分號(hào)不是必須的,但建議任何時(shí)候都不要省略它。分號(hào)可以避免程序輸入錯(cuò)誤,方便程序代碼壓縮,減少執(zhí)行時(shí)斷句開(kāi)銷。如果省略分號(hào),則由解釋器確定語(yǔ)句的結(jié)尾。表達(dá)式不改變程序的運(yùn)行狀態(tài),僅僅計(jì)算一個(gè)值而不做任何操作。語(yǔ)句改變程序的運(yùn)行狀態(tài)。每條語(yǔ)句放在不同行,方便跟蹤JavaScript腳本的執(zhí)行順序,多條語(yǔ)句放在同一行上時(shí),用分號(hào)隔開(kāi),建議在每條語(yǔ)句的末尾加一個(gè)分號(hào)。
換行表明一個(gè)語(yǔ)句的結(jié)束,一個(gè)語(yǔ)句分為兩行,將會(huì)產(chǎn)生錯(cuò)誤。
可以用{}來(lái)組織代碼塊,使程序更容易閱讀,即使是條件控制語(yǔ)句的單條語(yǔ)句也使用代碼塊。代碼塊是放在花括號(hào)內(nèi)的一組語(yǔ)句,可以只包含一條語(yǔ)句,也可以包括任意數(shù)量的語(yǔ)句。代碼塊中的所有語(yǔ)句被視為一個(gè)整體,可能都執(zhí)行,也可能都不執(zhí)行,右花括號(hào)(})的后面不需要加上分號(hào)。
(4)注釋。注釋可以解釋程序某些語(yǔ)句的作用和功能,使程序易于閱讀和理解,也可以用注釋暫時(shí)屏蔽某些語(yǔ)句,使瀏覽器對(duì)其暫時(shí)忽略,輔助代碼調(diào)試。JavaScript使用C語(yǔ)言風(fēng)格的注釋,包括單選注釋和塊級(jí)注釋。單選注釋以兩個(gè)斜杠開(kāi)頭(//),之后的內(nèi)容被視為注釋,不會(huì)被JavaScript解釋器處理。塊級(jí)注釋以一個(gè)斜杠(/)和一個(gè)星號(hào)(*)開(kāi)頭,以一個(gè)星號(hào)(*)和一個(gè)斜杠(/)結(jié)尾,中間行添加星號(hào)(*)提高注釋的可讀性,如
/ * * 第一行塊注釋 * 第二行塊注釋 * /
2.3.9 變量類型
JavaScript有6種數(shù)據(jù)類型:undefined、null、boolean、number、string和object。字面值表示某種特定類型的一個(gè)值。盡管JavaScript有多種變量類型,然而不同于C/C++、C#或Java,它并不是一種強(qiáng)類型語(yǔ)言。在強(qiáng)類型語(yǔ)言中,聲明變量時(shí)要指定變量類型,在JavaScript中,只需要使用關(guān)鍵字var而不必指定變量類型,因此JavaScript不是強(qiáng)類型語(yǔ)言。
數(shù)字(number)包括浮點(diǎn)數(shù)與整數(shù),JavaScript不區(qū)分浮點(diǎn)數(shù)值和整型數(shù)值,所有數(shù)字都由浮點(diǎn)型表示,如1、586、3.14。在Web前端開(kāi)發(fā)中,數(shù)字可以用于算術(shù)計(jì)算,表示屏幕尺寸、元素位置和時(shí)間長(zhǎng)度等。當(dāng)變量值以0開(kāi)頭時(shí)表示一個(gè)八進(jìn)制(以8為基數(shù))數(shù),當(dāng)變量值以0x開(kāi)頭時(shí)表示一個(gè)十六進(jìn)制(以16為基數(shù))數(shù)。數(shù)字采用指數(shù)表示法時(shí),xe+y表示數(shù)字x后面加y個(gè)0(2e+3表示2000),xe-y表示數(shù)字x的小數(shù)點(diǎn)向左移動(dòng)y位(2e-3表示0.002)。JavaScript所能處理的最大正整數(shù)(Number.MAX_SAFE_INTEGER)的安全值是9007199 254740991,最大負(fù)整數(shù)(Number.MIN_SAFE_INTEGER)的安全值為-9007199254740991。最大值(Number.MAX_VALUE)為1.7976931348623157e+308,最小值(Number.MIN_VALUE)為5e-324。
字符串(string)是由Unicode字符、數(shù)字、標(biāo)點(diǎn)符號(hào)等組成的序列,是JavaScript用來(lái)表示文本的數(shù)據(jù)類型,字符包括(但不限于)字母、數(shù)字、標(biāo)點(diǎn)符號(hào)和空格。字符串本身包含了引號(hào)時(shí),使用轉(zhuǎn)義符號(hào)“\”進(jìn)行轉(zhuǎn)義。字符串必須包在整個(gè)引號(hào)里,單引號(hào)或雙引號(hào)都可以,但起始引號(hào)必須和結(jié)尾引號(hào)相匹配,字符串的引號(hào)必須用半角字符,不能使用全角字符,字符串必須寫在一行中。如果要在字符串中使用雙引號(hào),則必須用單引號(hào)包含整個(gè)字符串,反之,要在字串符中使用單引號(hào),則字符串用雙引號(hào)包含。由單引號(hào)定界的字符串中可以含有雙引號(hào),由雙引號(hào)定界的字符串中也可以含有單引號(hào),此時(shí)不需要轉(zhuǎn)義,但雙引號(hào)內(nèi)出現(xiàn)雙引號(hào)或者單引號(hào)內(nèi)出現(xiàn)單引號(hào)時(shí)則必須進(jìn)行轉(zhuǎn)義,轉(zhuǎn)義符號(hào)為反斜杠(\),聲明轉(zhuǎn)義符號(hào)后的字符是內(nèi)容的一部分,而不是字符串的結(jié)束符號(hào)。字符串里由任意個(gè)字符組成的序列,例如:"h"、"username"、"1"。JavaScript中雙引號(hào)或單引號(hào)之間的任何值都會(huì)被視為一個(gè)字符串,"1"也是一個(gè)字符串。在一個(gè)字符串前使用typeof操作符會(huì)返回"string"。將一個(gè)數(shù)字字符串用于算術(shù)運(yùn)算中的操作數(shù)時(shí),該字符串會(huì)在運(yùn)算中被當(dāng)作數(shù)字類型來(lái)使用。
布爾值(boolean)包括true和false,類似一個(gè)開(kāi)關(guān),要么開(kāi),要么關(guān),可以想象成on/off,或者是0/1,true相當(dāng)于on或1,false相當(dāng)于off或0。布爾值通常用來(lái)構(gòu)建選擇語(yǔ)句執(zhí)行的條件。
undefined表示這個(gè)值未定義或者未初始化,或者賦予一個(gè)不存在的屬性值。如果只是聲明了變量,并未對(duì)其賦值,則其值默認(rèn)為undefined。
null是一個(gè)特殊的值,用于定義空的或不存在的引用。如果試圖引用一個(gè)沒(méi)有定義的變量,則返回一個(gè)null,null不等同于空的字符串。null與undefined的區(qū)別是,null表示一個(gè)變量被賦予了一個(gè)空值,而undefined則表示該變量尚未被賦值。
對(duì)象(object)本質(zhì)上是由一組無(wú)序的名值對(duì)組成的,也可以分為基本類型和對(duì)象兩大類。ECMAScript的變量是松散類型的,可以保存任何類型的數(shù)據(jù)。修改變量的值會(huì)同時(shí)修改變量的類型。布爾值的轉(zhuǎn)換規(guī)則如表2-3所示。
表2-3 布爾值轉(zhuǎn)換規(guī)則表

使用var操作符定義的變量將成為定義該變量的作用域中的局部變量,函數(shù)中使用var定義的變量,在函數(shù)退出后就會(huì)被銷毀。省略var創(chuàng)建的是全局變量,調(diào)用過(guò)一次后變量就有了定義,就可以在函數(shù)外部的任何地方被訪問(wèn)了。當(dāng)給一個(gè)尚未聲明的變量賦值時(shí),JavaScript會(huì)自動(dòng)用該變量名創(chuàng)建一個(gè)全局變量。要?jiǎng)?chuàng)建函數(shù)內(nèi)部的局部變量,必須使用var語(yǔ)句進(jìn)行變量聲明。
JavaScript可以使用三種方式輸出變量值:第一種是alert(),將變量值輸出到瀏覽器的警示窗口;第二種是console.log(),將變量輸出到調(diào)試工具的Console標(biāo)簽;第三種方法是通過(guò)document.write()直接輸出到HTML頁(yè)面并被瀏覽器呈現(xiàn)。
2.3.10 變量作用域
JavaScript程序按照在HTML文件中出現(xiàn)的順序逐行執(zhí)行,有時(shí)語(yǔ)句的執(zhí)行過(guò)程可能很復(fù)雜,要等到其他語(yǔ)句或函數(shù)運(yùn)行完成才能執(zhí)行。當(dāng)一條語(yǔ)句必須調(diào)用其他一些代碼才能完成任務(wù)時(shí),執(zhí)行順序就會(huì)改變。函數(shù)體內(nèi)的代碼不會(huì)被立即執(zhí)行,只有函數(shù)被其他程序調(diào)用時(shí),該代碼才會(huì)被執(zhí)行。調(diào)用函數(shù)的語(yǔ)句和函數(shù)處于同一執(zhí)行上下文時(shí),能正常執(zhí)行。在解釋器中,每個(gè)執(zhí)行上下文都包含variables對(duì)象(variables對(duì)象無(wú)法訪問(wèn),是瀏覽器內(nèi)部機(jī)制),它保存該執(zhí)行上下文中的所有變量、函數(shù)和參數(shù)。每個(gè)執(zhí)行上下文還可以訪問(wèn)其上層的variables對(duì)象。函數(shù)作用域會(huì)被連接到其所屬的外層對(duì)象,其作用域覆蓋范圍是當(dāng)前執(zhí)行上下文的variables對(duì)象加上它所有外層執(zhí)行上下文的variables對(duì)象。子對(duì)象可以訪問(wèn)父對(duì)象的變量信息,但父對(duì)象卻無(wú)法獲取子對(duì)象的變量信息。每個(gè)子對(duì)象都會(huì)從相同的父對(duì)象那里拿到相同的信息。如果某個(gè)變量不在當(dāng)前上下文的variables對(duì)象中,就會(huì)在其外層執(zhí)行上下文的variables對(duì)象中繼續(xù)尋找,查找會(huì)影響性能,所以最好在使用變量時(shí)創(chuàng)建變量。
變量作用域指某個(gè)變量在程序中的作用(可訪問(wèn))范圍,也就是程序中存在該變量的區(qū)域。變量的聲明位置將影響它的應(yīng)用范圍。JavaScript根據(jù)作用域不同可分為全局變量和局部變量?jī)煞N。
局部變量在函數(shù)體內(nèi)通過(guò)var關(guān)鍵字定義,只能在此函數(shù)體的內(nèi)部使用,無(wú)法在創(chuàng)建它的函數(shù)之外使用。在函數(shù)運(yùn)行時(shí),解釋器創(chuàng)建一個(gè)局部變量,當(dāng)函數(shù)完成任務(wù)時(shí)立即銷毀。函數(shù)的參數(shù)也是局部性的,只在函數(shù)內(nèi)部起作用。函數(shù)每次運(yùn)行的變量值可能不同,兩個(gè)不同的函數(shù)可以使用同名變量而不會(huì)引起命名沖突。局部變量只在固定的代碼片段內(nèi)可訪問(wèn),一般在函數(shù)體內(nèi)聲明而且只作用在函數(shù)體內(nèi)部及該函數(shù)體的子函數(shù)的變量。在函數(shù)中使用var關(guān)鍵字進(jìn)行顯式申明的變量是局部變量。如果一個(gè)變量是在函數(shù)內(nèi)聲明的,而且只能在函數(shù)中使用,也稱為函數(shù)級(jí)作用域。
全局變量定義在所有函數(shù)之外,作用于整個(gè)腳本代碼的變量可以在腳本的任何地方使用,擁有全局作用域,在JavaScript代碼中的任何地方都有效。擁有全局作用域的變量的定義情形有:① 定義在最外層函數(shù)和在最外層函數(shù)外面定義的變量;② 所有沒(méi)有用var關(guān)鍵字而直接賦值的變量;③ 所有window對(duì)象的屬性都擁有全局作用域。window對(duì)象的內(nèi)置屬性都擁有全局作用域,例如window.name、window.location、window.top等。全局變量在頁(yè)面載入瀏覽器時(shí)就進(jìn)駐內(nèi)存,全局變量比局部變量占用更多的內(nèi)存,瀏覽器在整個(gè)頁(yè)面載入期間保存全局變量,并且增加了命名沖突的風(fēng)險(xiǎn),所以應(yīng)盡量使用局部變量。如果定義變量時(shí)沒(méi)有使用var關(guān)鍵字,變量仍可用,只不過(guò)將被當(dāng)作全局變量對(duì)待。變量作用域示例代碼如下:
function outerFun() { var a = 0; alert(a); } var a = 4; outerFun(); alert(a);
上面的代碼結(jié)果是0,4。因?yàn)樵诤瘮?shù)內(nèi)部使用了var關(guān)鍵字維護(hù)a的作用域在outerFun()內(nèi)部。再看下面的代碼:
function outerFun() { // 沒(méi)有var a = 0; alert(a); } var a = 4; outerFun(); alert(a);
代碼結(jié)果為0,0,真是奇怪,為什么呢?作用域鏈?zhǔn)敲枋鲆环N路徑的術(shù)語(yǔ),沿著該路徑可以確定變量的值。當(dāng)執(zhí)行a=0時(shí),因?yàn)闆](méi)有使用var關(guān)鍵字,因此賦值操作會(huì)沿著作用域鏈到var a=4并改變其值。
在一些類似C語(yǔ)言的編程語(yǔ)言中,花括號(hào)內(nèi)的每一段代碼都具有各自的作用域,而且變量在聲明它們的花括號(hào)外是不可見(jiàn)的,稱之為塊級(jí)作用域。但JavaScript沒(méi)有塊級(jí)作用域,取而代之地使用了函數(shù)作用域,變量在聲明的函數(shù)體及這個(gè)函數(shù)體嵌套的任意函數(shù)體內(nèi)都可訪問(wèn)。
2.3.11 避免變量污染
定義全局變量有3種方式:一是在任何函數(shù)外面直接執(zhí)行var語(yǔ)句;二是直接添加一個(gè)屬性到全局對(duì)象上,全局對(duì)象是所有全局變量的容器,在Web瀏覽器中,全局對(duì)象為window,例如window.myVar=value;三是直接使用未經(jīng)聲明的變量,以這種方式定義的全局變量被稱為隱式的全局變量,例如myVar=value。
由于全局變量在所有作用域中都可見(jiàn),使用全局變量會(huì)降低程序的可靠性,因此應(yīng)努力減少使用全局變量。可以在應(yīng)用程序中創(chuàng)建唯一一個(gè)全局變量,并定義該變量為當(dāng)前應(yīng)用的容器。
var my = {}; my.name = { "real-name": "zhaojianbao", "nickname": "mpcer" }; my.phone = { "cell-phone": "135****4952", "telephone-number": "020872124 **" }
把多個(gè)全局都添加在一個(gè)名稱空間下,可以降低與其他應(yīng)用程序產(chǎn)生沖突的可能性,應(yīng)用程序也會(huì)變得容易閱讀,本例my.name指向的是頂層結(jié)構(gòu)。另一種方法是使用函數(shù)體將信息隱藏起來(lái),它是另一種有效減少變量污染的方法。
var my = function () { var name = { "real-name": "zhaojianbao", "nickname": "mpcer" }; var phone = { "cell-phone": "135 ****4952", "telephone-number": "020872124**" } }
JavaScript支持函數(shù)作用域,定義在函數(shù)中的參數(shù)和變量在函數(shù)外部是不可見(jiàn)的,且在一個(gè)函數(shù)中的任何位置定義的變量在該函數(shù)中的任何地方都可見(jiàn)。
2.3.12 閉包函數(shù)
在JavaScript中,內(nèi)嵌函數(shù)可以訪問(wèn)定義在外層函數(shù)中的所有變量和函數(shù),但是在函數(shù)外部則不能訪問(wèn)函數(shù)的內(nèi)部變量和嵌套函數(shù),這時(shí)可以使用“閉包”來(lái)實(shí)現(xiàn)。所謂“閉包”,是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù),實(shí)現(xiàn)在函數(shù)外部讀取函數(shù)內(nèi)部的變量和讓變量的值始終保持在內(nèi)存中。閉包的常見(jiàn)創(chuàng)建方式就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù),通過(guò)另一個(gè)函數(shù)訪問(wèn)這個(gè)函數(shù)的局部變量。
2.3.13 JavaScript轉(zhuǎn)義字符
JavaScript轉(zhuǎn)義字符如表2-4所示。
表2-4 轉(zhuǎn)義字符表

2.3.14 相等操作符
使用==時(shí),不同類型的值也可以看作相等。如果x和y是相同類型,JavaScript會(huì)比較它們的值或?qū)ο螅渌麤](méi)有列在這個(gè)表格中的情況都會(huì)返回false,如表2-5所示。
表2-5 不同類型值比較結(jié)果

使用===操作符時(shí),如果兩個(gè)值類型相同,如表2-6所示。
表2-6 全等比較符判斷規(guī)則

2.3.15 toNumber
toNumber對(duì)不同類型的值的返回結(jié)果如表2-7所示。
表2-7 toNumber轉(zhuǎn)換規(guī)則

2.3.16 使用typeof檢測(cè)類型
JavaScript是弱類型語(yǔ)言,對(duì)類型沒(méi)有嚴(yán)格限制,但是在程序中經(jīng)常需要對(duì)類型進(jìn)行檢測(cè)和轉(zhuǎn)換。typeof操作符用來(lái)檢測(cè)給定變量的數(shù)據(jù)類型,用于返回操作數(shù)當(dāng)前容納的數(shù)據(jù)類型,對(duì)于判斷一個(gè)變量是否已經(jīng)被定義特別有用。對(duì)于尚未聲明過(guò)的變量,只能執(zhí)行typeof操作符檢測(cè)其數(shù)據(jù)類型。typeof不是函數(shù),不需要使用圓括號(hào)。也可以直接對(duì)一個(gè)數(shù)值調(diào)用typeof,并非一定要事先將其賦值給變量,例如typeof 123。typeof運(yùn)算符把類型信息當(dāng)作字符串返回,返回值有number、string、boolean、object、function和undefined。
2.3.17 使用constructor檢測(cè)類型
對(duì)于對(duì)象、數(shù)組等復(fù)雜數(shù)據(jù),可以使用Object對(duì)象的constructor屬性進(jìn)行檢測(cè)。constructor屬性值引用的是構(gòu)造當(dāng)前對(duì)象的函數(shù),表示創(chuàng)建對(duì)象的函數(shù),語(yǔ)法如下:
object.constructor
參數(shù)說(shuō)明:object為必選項(xiàng),是對(duì)象或函數(shù)的名稱。constructor屬性是所有具有prototype的對(duì)象的成員,包括除Global和Math對(duì)象以外的所有JavaScript固有對(duì)象。constructor屬性保存了對(duì)構(gòu)造特定對(duì)象實(shí)例的函數(shù)的引用,例如:
x=newString("Hi"); if(x.constructor==String) //進(jìn)行處理(條件為真)
2.3.18 使用toString()檢測(cè)封裝類型
toString()方法是JavaScript所有內(nèi)部對(duì)象的一個(gè)成員方法,其操作依賴于對(duì)象的類型,toString()方法返回對(duì)象的字符串表示,語(yǔ)法如下:
objectname.toString([radix])
參數(shù)說(shuō)明:objectname為必選項(xiàng),是由字符串表示的對(duì)象名稱;radix為可選項(xiàng),指定將數(shù)字值轉(zhuǎn)換為字符串時(shí)的進(jìn)制,如表2-8所示。
表2-8 typeof和constructor返回值對(duì)比

2.3.19 事件委托
對(duì)“事件處理程序過(guò)多”問(wèn)題的解決方案就是事件委托,事件委托利用了事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類型的所有事件。例如,click事件會(huì)一直冒泡到document層級(jí)。也就是說(shuō),可以為整個(gè)頁(yè)面指定一個(gè)onclick事件處理程序,而不必給每個(gè)可單擊的元素分別添加事件處理程序。使用事件委托,只需在DOM樹(shù)中盡量最高的層次上添加一個(gè)事件處理程序,代碼如下。
<body> <ul id='myLinks'> <li id='baidu'>百度</li> <li id='qq'>騰訊</li> <li id='360'>360</li> </ul> <script> var ul = document.getElementById('myLinks'); ul.addEventListener('click', function (event) { switch (event.target.id) { case 'baidu': location.; break; case 'qq': location.; break; case '360': location.; break; } }); </script> </body>
以上代碼使用事件委托,只為<ul>元素添加了一個(gè)onclick事件處理程序。由于所有列表項(xiàng)都是這個(gè)元素的子節(jié)點(diǎn),而且它們單擊事件會(huì)冒泡,所以單擊事件最終會(huì)被這個(gè)函數(shù)處理。事件目標(biāo)是被單擊的列表項(xiàng),故而可以通過(guò)檢測(cè)id屬性來(lái)決定采取適當(dāng)?shù)牟僮鳌Ec前面未使用事件委托的代碼相比,會(huì)發(fā)現(xiàn)這段代碼的事件消耗更低,因?yàn)橹蝗〉昧艘粋€(gè)DOM元素,只添加了一個(gè)事件處理程序。雖然對(duì)用戶來(lái)說(shuō)最終的結(jié)果相同,但這種技術(shù)需要占用的內(nèi)存更少。
如果可行的話,也可以考慮為document對(duì)象添加一個(gè)事件處理程序,用以處理頁(yè)面上發(fā)生的某種特定類型的事件。這樣做與采取傳統(tǒng)的做法相比具有如下優(yōu)點(diǎn):① document對(duì)象很快就可以訪問(wèn),可以在頁(yè)面生命周期的任何時(shí)點(diǎn)上為它添加事件處理程序(無(wú)須等待DOMContentLoaded或load事件)。換句話說(shuō),只要可單擊的元素呈現(xiàn)在頁(yè)面上,就可以立即具備交互功能。② 在頁(yè)面中設(shè)置事件處理程序所需的時(shí)間更少。只添加一個(gè)事件處理程序所需的DOM引用更少,所花的時(shí)間也更少。整個(gè)頁(yè)面占用的內(nèi)存空間更少,能夠提升整體性能。
所有用到按鈕的事件(多數(shù)鼠標(biāo)事件和鍵盤事件)都適合采用“事件委托”技術(shù)。最適合采用事件委托技術(shù)的事件包括click、mousedown、mouseup、keydown、keyup和keypress,雖然mouseover和mouseout事件也冒泡,但要適當(dāng)處理它們并不容易,而且經(jīng)常需要計(jì)算元素的位置。
- 數(shù)據(jù)庫(kù)程序員面試筆試真題與解析
- SQL Server 2012數(shù)據(jù)庫(kù)管理與開(kāi)發(fā)項(xiàng)目教程
- 實(shí)戰(zhàn)Java高并發(fā)程序設(shè)計(jì)(第3版)
- 精通Python設(shè)計(jì)模式(第2版)
- Android Native Development Kit Cookbook
- Protocol-Oriented Programming with Swift
- The Professional ScrumMaster’s Handbook
- Android群英傳
- Access 2010數(shù)據(jù)庫(kù)應(yīng)用技術(shù)實(shí)驗(yàn)指導(dǎo)與習(xí)題選解(第2版)
- MATLAB GUI純代碼編寫從入門到實(shí)戰(zhàn)
- ExtJS Web應(yīng)用程序開(kāi)發(fā)指南第2版
- Python期貨量化交易實(shí)戰(zhàn)
- JQuery風(fēng)暴:完美用戶體驗(yàn)
- Bitcoin Essentials
- Spring Boot學(xué)習(xí)指南:構(gòu)建云原生Java和Kotlin應(yīng)用程序