![JavaScript精粹.doc_第1頁](http://file.renrendoc.com/FileRoot1/2020-1/13/337db38e-a474-4bcf-90bb-08ddce130fe6/337db38e-a474-4bcf-90bb-08ddce130fe61.gif)
![JavaScript精粹.doc_第2頁](http://file.renrendoc.com/FileRoot1/2020-1/13/337db38e-a474-4bcf-90bb-08ddce130fe6/337db38e-a474-4bcf-90bb-08ddce130fe62.gif)
![JavaScript精粹.doc_第3頁](http://file.renrendoc.com/FileRoot1/2020-1/13/337db38e-a474-4bcf-90bb-08ddce130fe6/337db38e-a474-4bcf-90bb-08ddce130fe63.gif)
![JavaScript精粹.doc_第4頁](http://file.renrendoc.com/FileRoot1/2020-1/13/337db38e-a474-4bcf-90bb-08ddce130fe6/337db38e-a474-4bcf-90bb-08ddce130fe64.gif)
![JavaScript精粹.doc_第5頁](http://file.renrendoc.com/FileRoot1/2020-1/13/337db38e-a474-4bcf-90bb-08ddce130fe6/337db38e-a474-4bcf-90bb-08ddce130fe65.gif)
已閱讀5頁,還剩142頁未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
JavaScript精粹用javascript判斷窗口關(guān)閉事件functionwindow.onbeforeunload()if(event.clientXdocument.body.clientWidth&event.clientY0|event.altKey|event.ctrlKey)/判斷event.altKey是為了Alt+F4關(guān)閉的情況;判斷event.ctrlKey是為了Ctrl+W關(guān)閉的情況/document.body.clientWidth不包括滾動(dòng)條,而關(guān)閉按鈕恰好在滾動(dòng)條右側(cè)。window.event.returnValue=;1.瀏覽器不是軟件的窗口,要該事件非常困難,因?yàn)殛P(guān)閉與刷新這兩個(gè)事件就很難區(qū)分。2.都沒有對(duì)應(yīng)的事件,只能根據(jù)一些條件來判斷,但未必準(zhǔn)確。3.前進(jìn)、后退、刷新、關(guān)閉都響應(yīng)事件window.onbeforeunload。4.javascript之所以能得到某些事件屬性和調(diào)用方法,是因?yàn)闉g覽器對(duì)象為他提供了接口,用COM的術(shù)語來說,是IDispatch接口,如果瀏覽器對(duì)象沒有為他提供接口,他什么也干不了。所以有些功能在其它語言中可以實(shí)現(xiàn),而在javascript中是永遠(yuǎn)無法實(shí)現(xiàn)的。 用onUnload方法在body標(biāo)簽里加入onUnload事件bodyonUnload=myClose()然后在javascript里定義myClose()方法,但是onUnload方法是在關(guān)閉窗口之后執(zhí)行,不是在關(guān)閉窗口之前執(zhí)行,如果你想在關(guān)閉窗口之前做判斷,請(qǐng)用第一種方法本書將主要介紹JavaScript的實(shí)際應(yīng)用,因?yàn)镴avaScript的確是一種令人驚奇的編程語言,有很多獨(dú)特的優(yōu)勢。只要花一點(diǎn)時(shí)間學(xué)習(xí)和思考,就可以使用JavaScript為網(wǎng)站帶來更多的功能、更新穎的設(shè)計(jì)和更好的易用性。下面先介紹JavaScript的概念,然后討論它的由來以及使用方法。1.1 JavaScript的定義JavaScript是一種用于增強(qiáng)Web網(wǎng)頁與應(yīng)用程序的交互能力和動(dòng)態(tài)能力的腳本語言。JavaScript可以和Web網(wǎng)頁的各種部件進(jìn)行交互,例如HTML、CSS,并且可以使它們實(shí)時(shí)地變化,以響應(yīng)用戶的操作。毫無疑問,您一定看過網(wǎng)頁中的JavaScript代碼,大多是嵌入HTML元素中的,例如:也可能是作為一個(gè)script元素,鏈接到其他文件中:還可能直接在文件中編碼:function saySomething(message) alert(message); saySomething(Hello world!);現(xiàn)在您還不用關(guān)心這些片段之間的區(qū)別。有很多方法可以用于將JavaScript代碼插入網(wǎng)頁中,后面的章節(jié)將會(huì)討論具體細(xì)節(jié)。JavaScript由Netscape公司開發(fā)并在Netscape 2中實(shí)現(xiàn),一開始它叫做LiveScript。不過另外一種流行的語言Java啟發(fā)了Netscape公司將其更名為JavaScript,JavaScript擁有溝通瀏覽器和Java Applet的能力,Netscape公司也試圖利用這一點(diǎn)大發(fā)利市。不過這個(gè)語言不是由Netscape公司獨(dú)自開發(fā)的,雖然最初的開發(fā)由Netscape公司發(fā)起,但還有一家公司后來也參與其中,這就是微軟公司。微軟公司開發(fā)出了相似但又有一些不同的JScript,很明顯,對(duì)于Web腳本這樣一種重要的應(yīng)用,微軟公司不希望落后于任何競爭對(duì)手。1996年,有關(guān)JavaScript的研發(fā)成果被提交為國際標(biāo)準(zhǔn),并被稱為ECMA,所以JavaScript就成了ECMAScript或者ECMA-262。大多數(shù)人還是喜歡JavaScript這個(gè)名字。另外,有一點(diǎn)容易引起混淆,即除了名字和語法有一些相似以外,Java和JavaScript再?zèng)]有什么相似之處了。1.2 JavaScript的限制JavaScript通常被作為一種客戶端語言使用,這里所說的客戶端,一般是指終端用戶的Web瀏覽器。在瀏覽器中,JavaScript代碼被解釋并被執(zhí)行,這點(diǎn)和服務(wù)端語言截然不同。所謂的服務(wù)端語言需要運(yùn)行在服務(wù)器,并發(fā)送一些靜態(tài)數(shù)據(jù)給客戶端,例如PHP、ASP等。由于JavaScript根本無法和服務(wù)器的環(huán)境打交道,很多任務(wù)是通過PHP實(shí)現(xiàn)的,例如讀寫數(shù)據(jù)庫,或者創(chuàng)建一個(gè)文本文件等。不過因?yàn)镴avaScript可以與客戶端環(huán)境交互,所以它能夠根據(jù)客戶端信息來做一些判斷或操作,例如鼠標(biāo)位置、元素的尺寸等,而這是服務(wù)端語言無法做到的。什么是ActiveX?如果您對(duì)微軟的JScript已經(jīng)很熟悉了,那么可能會(huì)想到“JavaScript也許可以通過ActiveX做些什么事”。沒錯(cuò),確實(shí)可以,不過ActiveX并不是ECMAScript的一個(gè)組成部分。ActiveX只是Windows操作系統(tǒng)的一種特別機(jī)制,以便Internet Explorer可以訪問COM對(duì)象,而且通常ActiveX是運(yùn)行于受信任的環(huán)境中的,例如Intranet。我們會(huì)很快遇到幾個(gè)例外:IE中沒有專門的安全設(shè)置的ActiveX控件(例如Flash插件,還有XMLHttpRequest)。但絕大多數(shù)情況下,對(duì)ActiveX的討論不在本書范疇之內(nèi)。通常,在任何一臺(tái)計(jì)算機(jī)上運(yùn)行的客戶端的能力總是沒有服務(wù)器端強(qiáng)大,所以,JavaScript并不適合用來進(jìn)行大量數(shù)據(jù)的處理。但是它對(duì)少量數(shù)據(jù)的即時(shí)處理的能力對(duì)于客戶端而言卻有著莫大的吸引力,例如接受響應(yīng)、驗(yàn)證表單等,這使得它成為一個(gè)完成此類任務(wù)的最佳選擇。但是,試圖評(píng)價(jià)服務(wù)器端語言和客戶端語言的優(yōu)劣卻是不必要的。這兩種語言不具有可比性,它們只是針對(duì)不同任務(wù)的工具而已,兩者的交集也并不多。然而,對(duì)于客戶端腳本和服務(wù)器腳本的交互能力的需求卻導(dǎo)致新一代的Web腳本語言的產(chǎn)生,這種新腳本語言使用XmlHttpRequest來請(qǐng)求服務(wù)器數(shù)據(jù),運(yùn)行服務(wù)器端的腳本,同時(shí)在客戶端處理結(jié)果。第18章將深入探討這種技術(shù)。安全性限制正因?yàn)镴avaScript可用于操作那些非常敏感的數(shù)據(jù)和程序,所以它的能力被嚴(yán)格地限制,以防止被人惡意使用。因此,JavaScript被禁止去做很多的事情。例如,它不能讀取計(jì)算機(jī)的系統(tǒng)設(shè)置,或者操作硬件,也不能啟動(dòng)別的程序。一些本來在JavaScript中被禁止的特殊的交互在特定的頁面元素中也可以被允許。例如,修改的值通常是沒什么問題的,除非是一個(gè)文件上傳區(qū)(例如,),往里面寫入是被禁止的,因?yàn)檫@可以阻止惡意代碼偷偷地讓用戶上傳他本來不希望上傳的文件。還有很多類似的限制,本書將通過大量的例子和應(yīng)用一一展示。但這里還是可以簡單地總結(jié)一下,下面是一個(gè)列表,列出了JavaScript中由于安全問題而被禁止的操作:l 不能打開和讀取一個(gè)文件(除非在一個(gè)特別的環(huán)境之下,相關(guān)內(nèi)容會(huì)在第18章討論);l 不能在用戶的計(jì)算機(jī)上創(chuàng)建和編輯文件(除了cookie,相關(guān)內(nèi)容在第8章討論);l 不能讀取HTTP post數(shù)據(jù);l 不能讀取系統(tǒng)設(shè)置,或者用戶計(jì)算機(jī)上的任何其他數(shù)據(jù),除非是語言本身提供的數(shù)據(jù)或者是環(huán)境提供的宿主對(duì)象(host object)1;l 不能修改文本輸入?yún)^(qū)域的值;l 不能修改一個(gè)從其他域載入的document的顯示方式;l 不能關(guān)閉和修改工具欄或者其他任何沒有向腳本開放的窗口元素。結(jié)果,JavaScript好像被禁止了太多的功能。另外,還有一點(diǎn)值得注意。很多瀏覽器提供了更加精細(xì)的權(quán)限控制,而不僅僅是一個(gè)允許或禁止的選項(xiàng)。例如,Opera可以禁止腳本關(guān)閉窗口,禁止移動(dòng)窗口,禁止?fàn)顟B(tài)欄寫入,禁止接收鼠標(biāo)右鍵消息這個(gè)列表還可以列得更長。加上了這些限制,您能做的事情就更少了,不過通常不需要關(guān)心那些選項(xiàng),在大多數(shù)情況下,那些選項(xiàng)是為了對(duì)付一些煩人的代碼(走馬燈式的滾動(dòng)狀態(tài)欄、禁止右鍵的腳本等)而準(zhǔn)備的,所以如果不想寫那些讓人討厭的腳本,這些限制完全不用放在心上。1.3 JavaScript的最佳實(shí)踐JavaScript實(shí)踐遇到的一個(gè)最大的問題首先是,如果用戶的瀏覽器根本就不支持JavaScript怎么辦?如果他關(guān)掉了瀏覽器對(duì)JavaScript的支持呢?再或者因?yàn)槟承┰?,他使用了別的不支持JavaScript的技術(shù)怎么辦? 這個(gè)問題一言難盡,第16章將詳細(xì)討論解決方法。下面提出3個(gè)寫好JavaScript代碼的原則:l 逐步改進(jìn) 為那些沒有安裝JavaScript的用戶著想;l 謹(jǐn)慎地編碼 內(nèi)容和行為的隔離;l 一致的編碼方式 使用括號(hào)和分號(hào)結(jié)束符。第一條原則可以在構(gòu)建網(wǎng)站的時(shí)候提醒開發(fā)者,面臨的用戶多種多樣。第二條原則使得維護(hù)代碼的代價(jià)更小,同時(shí),遇到不支持JavaScript的瀏覽器也可以提供無腳本的訪問方式1。第三條原則則有助于編寫出更易讀、更清晰的代碼。1.4 為那些沒有JavaScript的用戶著想(逐步改進(jìn))由于以下原因,用戶可能會(huì)得不到JavaScript:l 他們用的設(shè)備根本就不支持腳本,或者僅以某種受限制的方式支持;l 他們位于代理服務(wù)器或者防火墻之后,JavaScript代碼被過濾;l 他們故意禁用了JavaScript。第一種原因的用戶很多,而且這些用戶還在逐漸增長,包括一些小屏幕設(shè)備,如PDA;中等大小屏幕設(shè)備,如WebTV和Sony的PSP;還有一些老的部分支持JavaScript的瀏覽器,如Opera 5和Netscape 4。也許上面列出的那些用戶占用戶總數(shù)的比例不算很高,但那不重要。不管怎樣,一些用戶沒有JavaScript,但還是需要向他們提供服務(wù)。沒有什么好的辦法來統(tǒng)計(jì)這樣的用戶究竟有多少,因?yàn)閺姆?wù)器端檢測客戶端對(duì)JavaScript的支持是非常不可靠的,不過我曾經(jīng)看過一個(gè)數(shù)據(jù),關(guān)閉支持JavaScript功能的用戶的比例大約是5%20%之間,當(dāng)然,前提是我們把各種搜索引擎的爬蟲機(jī)器人程序也算成了用戶。方 法一種解決方案就是使用HTML的noscript元素。那么頁面內(nèi)容就可以被所有不支持腳本的瀏覽器以及被關(guān)閉了JavaScript支持的瀏覽器正確查看。雖然這也是一個(gè)可行的辦法,不過在實(shí)際操作中不是太有用。因?yàn)閚oscript無法區(qū)分瀏覽器對(duì)腳本的支持程度。那些只是部分支持或者受限制地支持JavaScript的瀏覽器會(huì)試圖執(zhí)行比較復(fù)雜的腳本,因?yàn)樗鼈兩踔量赡芨揪筒徽J(rèn)識(shí)noscript標(biāo)簽,其結(jié)果是在這些瀏覽器中代碼會(huì)不正常地終止,然后什么也沒干。一個(gè)更好的辦法是使用靜態(tài)HTML,然后通過腳本對(duì)靜態(tài)內(nèi)容進(jìn)行修改或者增加動(dòng)態(tài)行為。下面看一個(gè)簡單例子。這個(gè)代碼片段是用一個(gè)未排序的列表作為主菜單結(jié)構(gòu),產(chǎn)生一個(gè)DHTML菜單。第15章將詳細(xì)討論有關(guān)內(nèi)容,不過這個(gè)簡單的例子在這里可以充分展示我們的方法: Home About Contact鏈接的列表是純HTML,所以對(duì)于所有的用戶來說,不管使用什么瀏覽器,都可以正常顯示。如果腳本是被支持的,那么menu.js腳本就可以執(zhí)行動(dòng)態(tài)的操作,不過腳本不被支持時(shí),內(nèi)容仍然會(huì)顯示。我們沒有用什么明確的方法來區(qū)分不同瀏覽器對(duì)于JavaScript的支持程度,而只是提供了動(dòng)態(tài)的內(nèi)容,如果瀏覽器能夠處理,它就會(huì)去處理,如果不能,那么只顯示靜態(tài)內(nèi)容就行了。討 論傳統(tǒng)的方法是,用純JavaScript代碼生成獨(dú)立的動(dòng)態(tài)菜單,然后用noscript元素提供一個(gè)備用的靜態(tài)的內(nèi)容: Home About Contact 不過,正如前面所說的,網(wǎng)上的很多瀏覽器會(huì)在這樣的代碼前面失效,因?yàn)閷?duì)JavaScript的支持往往不是一個(gè)簡單的“是或不是”的問題。而這個(gè)方法提供了給所有瀏覽器的默認(rèn)內(nèi)容,又提供了一個(gè)可能有效的腳本功能。這種腳本方法就是所謂的逐步改進(jìn),對(duì)這種方法的使用將貫穿本書。不要提示太多!不管是這種方法還是noscript元素,都不應(yīng)該被用來產(chǎn)生這樣的消息給用戶,“請(qǐng)打開JavaScript選項(xiàng)再繼續(xù)。”對(duì)于某些用戶,這種消息有點(diǎn)蠻橫(“我干嘛要聽您的?”);對(duì)于另外一些用戶,這種消息可能是無用的(“我壓根無法打開!”)或者根本是無意義的(“JavaScript是啥?”)。就像很多啟動(dòng)頁面總是說,“請(qǐng)升級(jí)您的瀏覽器”這種消息對(duì)于大多數(shù)Web用戶而言,就像在路上看到一個(gè)牌子,提示“請(qǐng)換一輛車。”有時(shí)候,開發(fā)者可能會(huì)碰到除JavaScript之外再無更好的辦法來實(shí)現(xiàn)功能的情況。這時(shí),我認(rèn)為用一些靜態(tài)信息來提示用戶網(wǎng)頁遇到兼容性問題是合理的(當(dāng)然,這些和技術(shù)無關(guān))。不過,在大多數(shù)情況下,應(yīng)盡量避免顯示這種信息,除非它的確有意義而且是必須要告知用戶的。1.5 內(nèi)容和行為的隔離(謹(jǐn)慎地編碼)將內(nèi)容從行為中分離,意味著按照網(wǎng)頁的結(jié)構(gòu)分離出不同的層次來。Jeffrey Zeldman曾經(jīng)將Web開發(fā)形容為“三條腿的板凳”1,分別是內(nèi)容(HTML)、表示(CSS)、行為(JavaScript),他不僅指出三者在功能上的不同,同時(shí)也表明他認(rèn)為這三者應(yīng)該被互相隔離開來。好的隔離方式將使得網(wǎng)站更容易維護(hù),也更容易被理解和使用,同時(shí)對(duì)于老的或者支持特性較少的瀏覽器也能夠提供相應(yīng)的訪問方式。方 法以下是一種極端情況,正好與理想的行為內(nèi)容互相分離的方法南轅北轍,也可以直接在事件處理屬性中直接寫入內(nèi)嵌的代碼。但這會(huì)把頁面搞得一團(tuán)糟,應(yīng)該極力避免:可以把完成這些工作的代碼寫成一個(gè)函數(shù):定義一個(gè)函數(shù)來做這件事可以將大量的代碼集中到一個(gè)單獨(dú)的JavaScript文件中:File:separate-content-behaviors.js (excerpt)function changeBorder(element, to) element.style.borderColor = to;不過更好的方法是完全不使用內(nèi)嵌的事件處理,而使用文檔對(duì)象模型(DOM)來將事件處理綁定到HTML文檔的元素中。DOM是一種標(biāo)準(zhǔn)的編程接口,它使得像JavaScript這樣的語言可以直接訪問HTML文檔的內(nèi)容,這也消除了出現(xiàn)在HTML文檔中的JavaScript代碼。HTML代碼如下:JavaScript代碼如下:File: separate-content-behaviors.jsfunction changeBorder(element, to) element.style.borderColor = to;var contentDiv = document.getElementById(content);contentDiv.onmouseover = function() changeBorder(red);contentDiv.onmouseout = function() changeBorder(black);這種方法允許增加、刪除或者修改事件處理,而無需編輯HTML,而且,因?yàn)槲臋n本身完全不依賴于這些腳本,所以那些不支持JavaScript的瀏覽器將絲毫不受影響。這種方法同時(shí)也增加了復(fù)用性,如果需要,也可以將相同的函數(shù)綁定到其他元素上,同樣也不需要編輯HTML。這種方法讓我們擁有了通過DOM訪問元素的能力,第5章將深入探討DOM。隔離的優(yōu)點(diǎn)通過將內(nèi)容和行為分隔開來,不僅使代碼具有更廣泛的適用性,同時(shí)這種分而治之的思考方式也將帶來好處。因?yàn)镠TML和JavaScript完全分離,當(dāng)我們檢視HTML代碼的時(shí)候,不會(huì)忘記這個(gè)頁面需要顯示的核心內(nèi)容,而這些內(nèi)容應(yīng)當(dāng)不依賴于任何腳本。Andy Clark把這種方式叫做Web標(biāo)準(zhǔn)甜點(diǎn)1,這是一種有趣的類比,這種比喻方式認(rèn)為一個(gè)好的Web網(wǎng)站設(shè)計(jì)應(yīng)該是這樣:當(dāng)看過去時(shí),應(yīng)該看到組成整個(gè)甜點(diǎn)的隔離的優(yōu)點(diǎn)不同層次。這種方式的反面是水果蛋糕,您無法看到蛋糕的不同組成部分。您所能看到的就是搞不清什么材料的一塊整個(gè)的蛋糕。討 論當(dāng)把事件處理和如下的元素綁定起來的時(shí)候,需要注意,只有在那個(gè)元素實(shí)際存在的時(shí)候才能那么做。如果把處理腳本放到頁面的head區(qū),瀏覽器會(huì)報(bào)告發(fā)生錯(cuò)誤,然后拒絕執(zhí)行代碼,因?yàn)閏ontent div在這個(gè)位置還沒有被瀏覽器解讀顯示,而JavaScript卻已經(jīng)先被處理了。最直接的方法是把代碼放到load事件處理中。這種方式最保險(xiǎn),因?yàn)閘oad事件只有在整個(gè)頁面已經(jīng)完全載入的時(shí)候才會(huì)被激發(fā):window.onload = function() var contentDiv = document.getElementById(content); ;或者更清楚一點(diǎn),多寫一點(diǎn)代碼:window.onload = init;function init() var contentDiv = document.getElementById(content); 不過使用load事件的問題是,在整個(gè)頁面中只能使用一次;如果有兩個(gè)或者更多的腳本需要通過load事件來執(zhí)行,那么每個(gè)腳本都會(huì)改寫對(duì)load事件的處理。解決方法是對(duì)load事件采用更好的響應(yīng)方式,1.8節(jié)將繼續(xù)探討這個(gè)問題。1.6 使用括號(hào)和分號(hào)結(jié)束符(一致的編碼方式)在很多JavaScript的操作中,括號(hào)和分號(hào)是可選的,那么,既然是可有可無的,它們的價(jià)值何在?方 法雖然括號(hào)和分號(hào)通常是可選的而非必需的,但還是應(yīng)當(dāng)盡量多使用這兩個(gè)符號(hào),這樣可以使其他人更容易閱讀代碼,甚至也能有助于自己以后閱讀代碼,而且通過復(fù)用和重新組織代碼,可以避免很多問題。舉個(gè)例子,如下的代碼確實(shí)能夠正常地工作:File: semicolons-braces.js (excerpt)if (something) alert(something)else alert(nothing)不過,這樣的代碼能夠正常工作應(yīng)該歸功于JavaScript解釋器自動(dòng)插入分號(hào)的能力。每當(dāng)解釋器發(fā)現(xiàn)被截?cái)嗟奈挥诓煌械膬啥蜗噜彺a,而且這些代碼段單列在一行上會(huì)毫無意義,解釋器就會(huì)在段之間插入分號(hào)。通過類似的機(jī)制,用于if-else語句的括號(hào)即使不存在也能夠根據(jù)語法被推斷出來,實(shí)際上是解釋器做了查遺補(bǔ)漏的工作。雖然這些符號(hào)不是必需的,但是如果堅(jiān)持使用它們,就會(huì)發(fā)現(xiàn)這些符號(hào)既容易記憶也容易使用,而且寫出的代碼更容易閱讀。下面是一個(gè)稍微好一點(diǎn)的例子:File: semicolons-braces.js (excerpt)if (something) alert(something); else alert(nothing); 不過下面這個(gè)例子具有最佳的可讀性:File: semicolons-braces.js (excerpt)if (something) alert(something);else alert(nothing);使用函數(shù)顯式聲明如果對(duì)JavaScript的復(fù)雜部分已經(jīng)有了一些經(jīng)驗(yàn),那么可能會(huì)經(jīng)常通過函數(shù)顯式聲明來創(chuàng)建匿名函數(shù),并且將匿名函數(shù)賦值給JavaScript的變量或者對(duì)象的屬性。在下面的代碼中,定義的函數(shù)后面需要跟一個(gè)分號(hào),因?yàn)槠鋵?shí)它算是一個(gè)賦值語句。var saySomething = function(message) ;1.7 給頁面添加腳本要想讓腳本工作,首先需要在頁面中將其載入。有兩種技術(shù)可以做到這一點(diǎn),而其中一種技術(shù)明顯優(yōu)于另一種。方 法第一種,也是最直接的方法,是把代碼寫入script元素中,正像前面看見過的那樣:function saySomething(message) alert(message);saySomething(Hello world!);這種方法的問題在于,對(duì)于老的或者不支持script元素的瀏覽器,這些內(nèi)容會(huì)被解釋為文本。一種更好的替代方式是將腳本放入外部的一個(gè)JavaScript文件,如下:這條語句會(huì)載入一個(gè)外部的名叫what-is-javascript.js的JavaScript文件。這個(gè)文件中將包含前一個(gè)例子放入script元素中的代碼,如下:File: what-is-javascript.jsfunction saySomething(message) alert(message);saySomething(Hello world!);采用這種方法,不支持script元素的瀏覽器會(huì)忽略JavaScript部分,也不會(huì)顯示多余內(nèi)容(因?yàn)樵撛氐膬?nèi)容實(shí)際上是空的),不過那些能夠解讀script的瀏覽器會(huì)載入并處理該腳本。這有助于腳本和內(nèi)容的分離,而且很容易維護(hù),可以在不同的頁面中使用同一個(gè)腳本,而無須復(fù)制腳本,也無需維護(hù)多個(gè)拷貝。討 論也許您對(duì)避免在頁面中寫入腳本這個(gè)建議有異議,“不會(huì)有問題的呀”,您可能還會(huì)說,“我可以使用HTML注釋把代碼框起來”。不過我認(rèn)為那不是一個(gè)好主意,使用HTML注釋來“隱藏”代碼是一種非常壞的習(xí)慣,一定要記住這一點(diǎn)。1.7.1 用HTML注釋框住代碼解析器本來無需讀取注釋內(nèi)容,更不用去執(zhí)行它。不過現(xiàn)實(shí)情況是,被注釋的JavaScript完全可以工作,這是一個(gè)歷史遺留問題,也是一種妥協(xié),不應(yīng)該假定解析器會(huì)正確地略過注釋,忽略注釋中的JavaScript,實(shí)際上,應(yīng)該假定解析器一定不能正確地讀取注釋。書中的所有例子都通過HTML提供(與之相對(duì)的是XHTML),所以這種假設(shè)是合理的。不過如果使用XHTML(使用application/xhtml+xml的MIME類型),在瀏覽器處理該文件之前,XML解析器能夠正確地忽略其中的注釋,這樣,注釋的JavaScript代碼確實(shí)不會(huì)執(zhí)行。不過,考慮到兼容性(以及良好的編程習(xí)慣),強(qiáng)烈建議您盡量不在注釋中放入代碼。JavaScript代碼應(yīng)該總是放到一個(gè)外部的JavaScript文件中。1.7.2 語言屬性語言屬性不再是必需的了。當(dāng)Netscape 4和它同時(shí)代的瀏覽器成為了主流時(shí),標(biāo)簽扮演了一個(gè)探測腳本支持的角色(在JavaScript 1.3中指定),并且影響著腳本解釋器的工作方式。當(dāng)JavaScript變成了ECMAScript時(shí),指定JavaScript的版本已經(jīng)毫無意義,語言屬性已經(jīng)被類型屬性取代。這種屬性指定了被包含文件的MIME類型,例如腳本和樣式表的類型,而且這也是惟一的一種需要指定的類型: 實(shí)際上,值應(yīng)該被指定為text/ecmascript,不過Internet Explorer不認(rèn)識(shí)這種信息。我個(gè)人希望它最好能支持,因?yàn)槲逸斎雑avascript幾個(gè)字比較費(fèi)勁,有好多次,在輸入text/javascript的時(shí)候我都輸錯(cuò)。1.8 讓不同的腳本在同一頁面中協(xié)同工作如果幾個(gè)腳本總是不能協(xié)同工作,那么很有可能是因?yàn)檫@些腳本試圖對(duì)某給定元素的同一種事件處理賦予了不同的處理函數(shù)。因?yàn)槊總€(gè)元素對(duì)每個(gè)事件只有一個(gè)處理方法,所以同一個(gè)事件的處理會(huì)被不同的處理函數(shù)重復(fù)地替換。方 法通常應(yīng)該懷疑的是window對(duì)象的load事件處理,因?yàn)樵谕豁撁嬷?,只有一個(gè)腳本能夠使用這個(gè)事件;如果兩個(gè)或者多個(gè)腳本嘗試使用該事件,那么最后一個(gè)腳本會(huì)將前面腳本的處理函數(shù)覆蓋掉??梢栽趌oad事件處理函數(shù)中調(diào)用多個(gè)函數(shù),如下:window.onload = function() firstFunction(); secondFunction();不過,如果這樣做,就必須受限于在load事件的處理函數(shù)中完成所有的任務(wù)。另一個(gè)好一點(diǎn)的解決方案是提供一個(gè)函數(shù),可以增加對(duì)load事件的處理而不與其他已經(jīng)添加的處理函數(shù)沖突。使用下面的函數(shù),可以添加任意數(shù)量的load事件的處理函數(shù),而無需擔(dān)心它們發(fā)生沖突:File: add-load-listener.jsfunction addLoadListener(fn) if (typeof window.addEventListener != undefined) window.addEventListener(load, fn, false); else if (typeof document.addEventListener != undefined) document.addEventListener(load, fn, false);else if (typeof window.attachEvent != undefined) window.attachEvent(onload, fn);else var oldfn = window.onload; if (typeof window.onload != function) window.onload = fn; else window.onload = function() oldfn(); fn(); ; 這樣,就可以隨心所欲地增加新的load事件處理函數(shù)了,如下:addLoadListener(firstFunction);addLoadListener(secondFunction);addLoadListener(twentyThirdFunction);討 論JavaScript包括了給事件增加或刪除監(jiān)聽器的方法,看上去有點(diǎn)像普通的事件處理,但卻允許多個(gè)監(jiān)聽器訂閱同一個(gè)元素的同一個(gè)事件的消息。不幸的是,在Internet Explorer中這種監(jiān)聽器的語法與在其他瀏覽器中的語法完全不同,IE使用一種獨(dú)有的方式,而其他瀏覽器則完全按照W3C標(biāo)準(zhǔn)來實(shí)現(xiàn)。開發(fā)者將經(jīng)常處于這種折磨之中,在第13章將會(huì)討論有關(guān)的細(xì)節(jié)。W3C標(biāo)準(zhǔn)方法叫做addEventListener:window.addEventListener(load, firstFunction, false); IE的方法叫做attachEvent:window.attachEvent(onload, firstFunction);正如您所看到的,標(biāo)準(zhǔn)的創(chuàng)建方法是,直接使用事件的名字(沒有on前綴),事件發(fā)生時(shí)需要調(diào)用的函數(shù)以及一個(gè)用于控制事件傳遞的參數(shù)放在事件名字的后面(第13章會(huì)有更詳細(xì)的討論)。IE的方法則使用事件處理者的名字(前面帶有一個(gè)on前綴),需要調(diào)用的函數(shù)的名字放在其后。在將代碼組織到一起的時(shí)候,還需要測試一下試圖調(diào)用的方法是否存在??梢杂肑avaScript的typeof操作符,它可以區(qū)分?jǐn)?shù)據(jù)的不同類型(例如字符串、數(shù)字、布爾值、對(duì)象、數(shù)組、函數(shù)或者未定義類型)。一個(gè)不存在的方法會(huì)返回未定義類型。if (typeof window.addEventListener != undefined) 支持window.addEventListener還有一點(diǎn)稍稍復(fù)雜的地方:在Opera中,load事件可以激發(fā)來自文檔對(duì)象的事件監(jiān)聽器,卻不能激發(fā)來自窗口對(duì)象的監(jiān)聽器。不過如果只使用文檔對(duì)象,這樣的代碼在老版本的Mozilla瀏覽器中(例如Netscape 6)又不能工作。為了處理這種問題,還必須測試一下window.addEventListener,然后是document.addEventListener,最后才是window.attachEvent。最后,對(duì)于那些根本不支持這些方法的瀏覽器(例如Mac IE 5),備用的方案是使用老式的鏈?zhǔn)绞录幚矸绞?,這樣在事件發(fā)生時(shí)事件處理函數(shù)仍能被調(diào)用??梢詣?dòng)態(tài)地創(chuàng)建一個(gè)新的事件處理函數(shù),當(dāng)事件發(fā)生時(shí),先調(diào)用老的事件處理函數(shù),再調(diào)用新的事件處理函數(shù)1。File: add-load-listener.js (excerpt)var oldfn = window.onload;if (typeof window.onload != function) window.onload = fn;else window.onload = function() oldfn(); fn(); ; 如果您現(xiàn)在對(duì)這些代碼怎樣工作還不太理解,不用擔(dān)心,后續(xù)章節(jié)還會(huì)討論更多的細(xì)節(jié)。后面大家會(huì)了解到事件監(jiān)聽器不僅適用于load事件,也適用于任何事件驅(qū)動(dòng)的腳本。1.9 隱藏JavaScript源代碼如果您曾經(jīng)創(chuàng)造過讓自己驕傲的東西,您就會(huì)明白自己的智力成果是需要保護(hù)的。但是JavaScript是一種自然的源碼開放的語言,它以源代碼的方式被瀏覽器接收,所以,只要瀏覽器可以運(yùn)行它,任何人也就可以閱讀它。網(wǎng)上有些程序宣稱提供對(duì)源代碼的加密,但其實(shí)沒有什么加密方法能夠保證別人無法解密。實(shí)際上,這些程序往往會(huì)造成麻煩,它們會(huì)重新格式化代碼,這讓代碼運(yùn)行更慢、更低效,甚至?xí)驗(yàn)殄e(cuò)誤而不能運(yùn)行。想知道我的建議嗎?干脆碰都不要碰那些所謂的加密程序。不過,為了保護(hù)代碼成果,有件事情是很容易做到的,那就是混淆代碼,混淆后的代碼非常不易閱讀和理解。方 法被去除了所有的注釋和非必需的空格之后的代碼非常難以閱讀,正如您期望的那樣,從這樣的代碼中分離出功能模塊更加困難。這種簡單的壓縮代碼的方法可以讓大部分黑客放棄讀下去的打算,除了少數(shù)非常有毅力的黑客。如下:File: obfuscate-code.js (excerpt)var oldfn = window.onload;if (typeof window.onload != function) window.onload = fn;else window.onload = function() oldfn(); fn(); ;可以通過去掉一些非必要的空格從而將代碼壓縮成兩行:File:obfuscate-code.js (excerpt)var oldfn=window.onload;if(typeof window.onload!=function)window.onload=fn;elsewindow.onload=function()oldfn();fn();不過,還要注意,去除的是非必需的空格。一些空格是必需的,如var和typeof之后的空格。討 論除了混淆本身帶來的好處,這種去除了注釋和非必要空格的代碼通常會(huì)更加簡短,因此載入速度會(huì)更快,執(zhí)行速度也會(huì)更快。但要注意,仍需要準(zhǔn)確而嚴(yán)格地使用分號(hào)結(jié)束符和括號(hào),就像在1.6節(jié)中討論過的,否則,去除了換行符之后,代碼被集中到一行會(huì)造成錯(cuò)誤。在壓縮代碼之前,要記住先備份一個(gè)拷貝。我知道這其實(shí)是很顯然的事情,不過我曾經(jīng)犯過好多次錯(cuò)誤,您一定能想象我面對(duì)一團(tuán)亂麻般的代碼時(shí)的郁悶。我通常的做法是維護(hù)一個(gè)有注釋和足夠多空格的易讀的版本,然后在發(fā)布之前,通過搜索/替換來處理一番。我會(huì)保留兩個(gè)拷貝,一個(gè)叫做myscript.js,另一個(gè)叫做myscript-commented.js。第20章將回到這個(gè)主題,討論一些相關(guān)技術(shù),從而提高腳本的速度和效率,同時(shí)降低開銷。1.10 腳本調(diào)試調(diào)試是一個(gè)查錯(cuò)改錯(cuò)的過程。絕大多數(shù)瀏覽器擁有內(nèi)建的報(bào)告錯(cuò)誤的功能,還有一些外部的調(diào)試工具也值得關(guān)注。1.10.1 理解瀏覽器內(nèi)建的錯(cuò)誤報(bào)告Opera、Mozilla瀏覽器(例如FireFox)以及Internet Explorer都擁有很好的內(nèi)建的錯(cuò)誤報(bào)告功能,不過Opera和Mozilla的調(diào)試工具最為有用。(1)Opera 通過菜單ToolsAdvancedJavaScript console可以打開JavaScript控制臺(tái)。也可以把它設(shè)置為遇到錯(cuò)誤的時(shí)候自動(dòng)打開,方法是依次選擇ToolsPreferencesAdvancedContent菜單項(xiàng),單擊JavaScript選項(xiàng)按鈕,打開一個(gè)對(duì)話框,然后選中Open JavaScript console on error選項(xiàng)。(2)FireFox和其他的Mozilla瀏覽器 通過菜單ToolsJavaScript console打開JavaScript控制臺(tái)。(3)Internet Explorer for Windows 依次選擇ToolsInternet OptionsAdvanced,然后將Disable script debugging選項(xiàng)前的勾取消,再選中Display a notification about every script error選項(xiàng)。這樣,每次發(fā)生錯(cuò)誤就會(huì)彈出一個(gè)對(duì)話框。(4)Internet Explorer for Mac 依次選擇ExplorerPreferenceWeb BrowserWeb Content菜單項(xiàng),然后選中Show scripting error alerts選項(xiàng)。Safari在默認(rèn)情況下是不包括錯(cuò)誤報(bào)告的,不過新版本有了一個(gè)“隱藏”的調(diào)試菜單,包括一個(gè)JavaScript控制臺(tái),可以通過如下的終端命令來激活1:$ defaults write com.apple.safari IncludeDebugMenu -bool true 也可以使用一種叫做Safari Enhancer1的擴(kuò)展,這種擴(kuò)展包含了一個(gè)選項(xiàng),可以將JavaScript錯(cuò)誤信息輸出到Mac OS的控制臺(tái);但是,這些信息常常都沒太大用處。理解不同瀏覽器報(bào)告的錯(cuò)誤信息需要一點(diǎn)練習(xí),因?yàn)槊糠N瀏覽器給出的信息都不相同。這里給出一個(gè)例子一個(gè)錯(cuò)誤類型的函數(shù)調(diào)用:function saySomething(message) alert(message);saySometing(Hello world);FireFox給出了非常簡要但卻很準(zhǔn)確的報(bào)告,包括了發(fā)生錯(cuò)誤的行號(hào)以及具體描述,如圖1.1所示。圖1.1 Firefox中的JavaScript錯(cuò)誤控制臺(tái)如圖1.2所示,Opera給出了一個(gè)非常詳細(xì)的報(bào)告,包括產(chǎn)生錯(cuò)誤的回溯信息和發(fā)生錯(cuò)誤的行號(hào),以及具體描述。圖1.2 Opera中的JavaScript控制臺(tái)回溯信息有助于定位由別的代碼引發(fā)的錯(cuò)誤,例如,事件處理者調(diào)用一個(gè)函數(shù),該函數(shù)再調(diào)用第二個(gè)函數(shù),在這個(gè)位置發(fā)生了錯(cuò)誤。Opera的控制臺(tái)能夠回溯出調(diào)用過程并找到錯(cuò)誤最初發(fā)生時(shí)的函數(shù)調(diào)用或事件處理。Internet Explorer給出了非?;镜男畔ⅲ鐖D1.3所示。它提供了發(fā)生錯(cuò)誤的行號(hào)(不過可能與真實(shí)的錯(cuò)誤位置有偏差)1,還有一個(gè)很概括的錯(cuò)誤類型描述,但是卻沒有指出具體的錯(cuò)誤。圖1.3 Windows IE中的JavaScript控制臺(tái)我對(duì)Internet Explorer給出的很簡略的錯(cuò)誤報(bào)告并沒有太多的抱怨,至少比沒有好,我知道有錯(cuò)誤發(fā)生了。1.10.2 使用alert分析錯(cuò)誤的時(shí)候,使用alert函數(shù)是一種非常有用的方法,可以在任何位置用它來顯示對(duì)象或者變量的值,看是否是您所期望的值。例如,如果有一個(gè)有很多條件分支的函數(shù),可以在每個(gè)分支使用alert,看看到底哪條分支被執(zhí)行了:File:debugging-dialogs.jsfunction checkAge(years) if (years = 13 & years = 21) alert(13 to 21); 其他腳本 else alert(older); 其他腳本 也許傳入的years根本就不是一個(gè)數(shù)字,不像函數(shù)期望的那樣。可以在這段代碼的開頭加入一個(gè)alert,看看究竟什么類型的變量被傳了進(jìn)來:function checkAge(years) alert(typeof years); 從理論上說,可以用alert對(duì)話框顯示任意多的信息,雖然一個(gè)非常長的串會(huì)使得彈出的對(duì)話框非常寬,以至于超出了屏幕窗口的限制而被截?cái)唷?梢越o輸出的信息加上換行符“n”來避免這種情況。1.10.3 使用try-catchtry-catch具有令人難以置信的力量,可以做某種嘗試,然后就能夠處理可能發(fā)生的任何錯(cuò)誤了。最基本的形式如下:File:debugging-trycatch.js (excerpt)try 一些代碼catch (err) 如果try塊中發(fā)生了錯(cuò)誤,這部分代碼將會(huì)運(yùn)行如果無法確定哪里發(fā)生了錯(cuò)誤,可以用一個(gè)try-catch的套將一大塊代碼包起來,并且處理最可能的錯(cuò)誤,然后一點(diǎn)點(diǎn)縮小包圍圈。例如,可以將一個(gè)函數(shù)的部分包在try語句中,然后看看哪里發(fā)生了錯(cuò)誤。然后將嫌疑代碼再分割,在適當(dāng)?shù)奈恢檬褂胻ry套,這個(gè)過程持續(xù)下去,直到鎖定出問題的那一行。catch有一個(gè)參數(shù)(在這個(gè)例子中將它命名為err)是用來接收錯(cuò)誤對(duì)象的,我們可以通過檢查這個(gè)對(duì)象的屬性,例如名字和信息,來得到這個(gè)錯(cuò)誤的具體細(xì)節(jié)。通常,我會(huì)用一個(gè)for-in語句來遍歷整個(gè)對(duì)象,看看它究竟包含了什么信息:File:debugging-trycatch.js (excerpt)for (var i in err) alert(i + : + erri);1.10.4 向頁面和窗口中寫入數(shù)據(jù)如果在調(diào)試的時(shí)候需要檢查很多數(shù)據(jù),或者正在處理的數(shù)據(jù)有著很復(fù)雜的格式,則最好直接把數(shù)據(jù)寫入一個(gè)頁面或者一個(gè)彈出的窗口中,而不需要用許多alert對(duì)話框。如果檢查的是循環(huán)中的數(shù)據(jù),這樣也避免了產(chǎn)生無數(shù)個(gè)對(duì)話框,要知道,這些對(duì)話框最后還得一個(gè)一個(gè)手工去關(guān)閉,這是非常麻煩的。針對(duì)這些情況,可以使用元素的innerHTML屬性,將數(shù)據(jù)寫入頁面中。下面的例子是通過使用一個(gè)數(shù)組的內(nèi)容創(chuàng)建一個(gè)列表,然后將它寫入test div中:File:debugging-writing.js (excerpt)var test = document.getElementById(testdiv);test.innerHTML += ;for (var i = 0; i data.length; i+) test.innerHTML += + i + = + datai + ;test.innerHTML += ;如果在頁面中沒有足夠的和方便的地方來顯示數(shù)據(jù),也可以將數(shù)據(jù)寫入彈出對(duì)話框中: File:debugging-writing.js (excerpt)var win = window.open(, win, width=320,height=240);win.document.open();win.document.write();for (var i = 0; i data.length; i+) win.document.write( + i + = + datai + )win.document.write();win.docume
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 買房車購車合同范例
- 代發(fā)快遞服務(wù)合同范本
- 2025年度環(huán)保技術(shù)研發(fā)與應(yīng)用合作合同
- 2025年度國際物流信息平臺(tái)進(jìn)口與實(shí)施合同
- 兄弟合伙生意合同范本
- 城市中等裝修房屋出租合同范本
- 入股代理合同范本
- 關(guān)于砂石購買標(biāo)準(zhǔn)合同范本
- 出版社教材出版合同范本
- 2025年食品級(jí)甘氨酸鈉項(xiàng)目投資可行性研究分析報(bào)告
- JJF 1069-2012 法定計(jì)量檢定機(jī)構(gòu)考核規(guī)范(培訓(xùn)講稿)
- 最新如何進(jìn)行隔代教育專業(yè)知識(shí)講座課件
- 當(dāng)前警察職務(wù)犯罪的特征、原因及防范,司法制度論文
- 計(jì)算機(jī)文化基礎(chǔ)單元設(shè)計(jì)-windows
- 創(chuàng)建動(dòng)物保護(hù)家園-完整精講版課件
- 廣東省保安服務(wù)監(jiān)管信息系統(tǒng)用戶手冊(操作手冊)
- DNA 親子鑒定手冊 模板
- DB33T 1233-2021 基坑工程地下連續(xù)墻技術(shù)規(guī)程
- 天津 建設(shè)工程委托監(jiān)理合同(示范文本)
- 部編一年級(jí)語文下冊教材分析
- 火炬及火炬氣回收系統(tǒng)操作手冊
評(píng)論
0/150
提交評(píng)論