JavaScript精粹.doc_第1頁
JavaScript精粹.doc_第2頁
JavaScript精粹.doc_第3頁
JavaScript精粹.doc_第4頁
JavaScript精粹.doc_第5頁
已閱讀5頁,還剩142頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

JavaScript精粹用javascript判斷窗口關閉事件functionwindow.onbeforeunload()if(event.clientXdocument.body.clientWidth&event.clientY0|event.altKey|event.ctrlKey)/判斷event.altKey是為了Alt+F4關閉的情況;判斷event.ctrlKey是為了Ctrl+W關閉的情況/document.body.clientWidth不包括滾動條,而關閉按鈕恰好在滾動條右側。window.event.returnValue=;1.瀏覽器不是軟件的窗口,要該事件非常困難,因為關閉與刷新這兩個事件就很難區分。2.都沒有對應的事件,只能根據一些條件來判斷,但未必準確。3.前進、后退、刷新、關閉都響應事件window.onbeforeunload。4.javascript之所以能得到某些事件屬性和調用方法,是因為瀏覽器對象為他提供了接口,用COM的術語來說,是IDispatch接口,如果瀏覽器對象沒有為他提供接口,他什么也干不了。所以有些功能在其它語言中可以實現,而在javascript中是永遠無法實現的。 用onUnload方法在body標簽里加入onUnload事件bodyonUnload=myClose()然后在javascript里定義myClose()方法,但是onUnload方法是在關閉窗口之后執行,不是在關閉窗口之前執行,如果你想在關閉窗口之前做判斷,請用第一種方法本書將主要介紹JavaScript的實際應用,因為JavaScript的確是一種令人驚奇的編程語言,有很多獨特的優勢。只要花一點時間學習和思考,就可以使用JavaScript為網站帶來更多的功能、更新穎的設計和更好的易用性。下面先介紹JavaScript的概念,然后討論它的由來以及使用方法。1.1 JavaScript的定義JavaScript是一種用于增強Web網頁與應用程序的交互能力和動態能力的腳本語言。JavaScript可以和Web網頁的各種部件進行交互,例如HTML、CSS,并且可以使它們實時地變化,以響應用戶的操作。毫無疑問,您一定看過網頁中的JavaScript代碼,大多是嵌入HTML元素中的,例如:也可能是作為一個script元素,鏈接到其他文件中:還可能直接在文件中編碼:function saySomething(message) alert(message); saySomething(Hello world!);現在您還不用關心這些片段之間的區別。有很多方法可以用于將JavaScript代碼插入網頁中,后面的章節將會討論具體細節。JavaScript由Netscape公司開發并在Netscape 2中實現,一開始它叫做LiveScript。不過另外一種流行的語言Java啟發了Netscape公司將其更名為JavaScript,JavaScript擁有溝通瀏覽器和Java Applet的能力,Netscape公司也試圖利用這一點大發利市。不過這個語言不是由Netscape公司獨自開發的,雖然最初的開發由Netscape公司發起,但還有一家公司后來也參與其中,這就是微軟公司。微軟公司開發出了相似但又有一些不同的JScript,很明顯,對于Web腳本這樣一種重要的應用,微軟公司不希望落后于任何競爭對手。1996年,有關JavaScript的研發成果被提交為國際標準,并被稱為ECMA,所以JavaScript就成了ECMAScript或者ECMA-262。大多數人還是喜歡JavaScript這個名字。另外,有一點容易引起混淆,即除了名字和語法有一些相似以外,Java和JavaScript再沒有什么相似之處了。1.2 JavaScript的限制JavaScript通常被作為一種客戶端語言使用,這里所說的客戶端,一般是指終端用戶的Web瀏覽器。在瀏覽器中,JavaScript代碼被解釋并被執行,這點和服務端語言截然不同。所謂的服務端語言需要運行在服務器,并發送一些靜態數據給客戶端,例如PHP、ASP等。由于JavaScript根本無法和服務器的環境打交道,很多任務是通過PHP實現的,例如讀寫數據庫,或者創建一個文本文件等。不過因為JavaScript可以與客戶端環境交互,所以它能夠根據客戶端信息來做一些判斷或操作,例如鼠標位置、元素的尺寸等,而這是服務端語言無法做到的。什么是ActiveX?如果您對微軟的JScript已經很熟悉了,那么可能會想到“JavaScript也許可以通過ActiveX做些什么事”。沒錯,確實可以,不過ActiveX并不是ECMAScript的一個組成部分。ActiveX只是Windows操作系統的一種特別機制,以便Internet Explorer可以訪問COM對象,而且通常ActiveX是運行于受信任的環境中的,例如Intranet。我們會很快遇到幾個例外:IE中沒有專門的安全設置的ActiveX控件(例如Flash插件,還有XMLHttpRequest)。但絕大多數情況下,對ActiveX的討論不在本書范疇之內。通常,在任何一臺計算機上運行的客戶端的能力總是沒有服務器端強大,所以,JavaScript并不適合用來進行大量數據的處理。但是它對少量數據的即時處理的能力對于客戶端而言卻有著莫大的吸引力,例如接受響應、驗證表單等,這使得它成為一個完成此類任務的最佳選擇。但是,試圖評價服務器端語言和客戶端語言的優劣卻是不必要的。這兩種語言不具有可比性,它們只是針對不同任務的工具而已,兩者的交集也并不多。然而,對于客戶端腳本和服務器腳本的交互能力的需求卻導致新一代的Web腳本語言的產生,這種新腳本語言使用XmlHttpRequest來請求服務器數據,運行服務器端的腳本,同時在客戶端處理結果。第18章將深入探討這種技術。安全性限制正因為JavaScript可用于操作那些非常敏感的數據和程序,所以它的能力被嚴格地限制,以防止被人惡意使用。因此,JavaScript被禁止去做很多的事情。例如,它不能讀取計算機的系統設置,或者操作硬件,也不能啟動別的程序。一些本來在JavaScript中被禁止的特殊的交互在特定的頁面元素中也可以被允許。例如,修改的值通常是沒什么問題的,除非是一個文件上傳區(例如,),往里面寫入是被禁止的,因為這可以阻止惡意代碼偷偷地讓用戶上傳他本來不希望上傳的文件。還有很多類似的限制,本書將通過大量的例子和應用一一展示。但這里還是可以簡單地總結一下,下面是一個列表,列出了JavaScript中由于安全問題而被禁止的操作:l 不能打開和讀取一個文件(除非在一個特別的環境之下,相關內容會在第18章討論);l 不能在用戶的計算機上創建和編輯文件(除了cookie,相關內容在第8章討論);l 不能讀取HTTP post數據;l 不能讀取系統設置,或者用戶計算機上的任何其他數據,除非是語言本身提供的數據或者是環境提供的宿主對象(host object)1;l 不能修改文本輸入區域的值;l 不能修改一個從其他域載入的document的顯示方式;l 不能關閉和修改工具欄或者其他任何沒有向腳本開放的窗口元素。結果,JavaScript好像被禁止了太多的功能。另外,還有一點值得注意。很多瀏覽器提供了更加精細的權限控制,而不僅僅是一個允許或禁止的選項。例如,Opera可以禁止腳本關閉窗口,禁止移動窗口,禁止狀態欄寫入,禁止接收鼠標右鍵消息這個列表還可以列得更長。加上了這些限制,您能做的事情就更少了,不過通常不需要關心那些選項,在大多數情況下,那些選項是為了對付一些煩人的代碼(走馬燈式的滾動狀態欄、禁止右鍵的腳本等)而準備的,所以如果不想寫那些讓人討厭的腳本,這些限制完全不用放在心上。1.3 JavaScript的最佳實踐JavaScript實踐遇到的一個最大的問題首先是,如果用戶的瀏覽器根本就不支持JavaScript怎么辦?如果他關掉了瀏覽器對JavaScript的支持呢?再或者因為某些原因,他使用了別的不支持JavaScript的技術怎么辦? 這個問題一言難盡,第16章將詳細討論解決方法。下面提出3個寫好JavaScript代碼的原則:l 逐步改進 為那些沒有安裝JavaScript的用戶著想;l 謹慎地編碼 內容和行為的隔離;l 一致的編碼方式 使用括號和分號結束符。第一條原則可以在構建網站的時候提醒開發者,面臨的用戶多種多樣。第二條原則使得維護代碼的代價更小,同時,遇到不支持JavaScript的瀏覽器也可以提供無腳本的訪問方式1。第三條原則則有助于編寫出更易讀、更清晰的代碼。1.4 為那些沒有JavaScript的用戶著想(逐步改進)由于以下原因,用戶可能會得不到JavaScript:l 他們用的設備根本就不支持腳本,或者僅以某種受限制的方式支持;l 他們位于代理服務器或者防火墻之后,JavaScript代碼被過濾;l 他們故意禁用了JavaScript。第一種原因的用戶很多,而且這些用戶還在逐漸增長,包括一些小屏幕設備,如PDA;中等大小屏幕設備,如WebTV和Sony的PSP;還有一些老的部分支持JavaScript的瀏覽器,如Opera 5和Netscape 4。也許上面列出的那些用戶占用戶總數的比例不算很高,但那不重要。不管怎樣,一些用戶沒有JavaScript,但還是需要向他們提供服務。沒有什么好的辦法來統計這樣的用戶究竟有多少,因為從服務器端檢測客戶端對JavaScript的支持是非常不可靠的,不過我曾經看過一個數據,關閉支持JavaScript功能的用戶的比例大約是5%20%之間,當然,前提是我們把各種搜索引擎的爬蟲機器人程序也算成了用戶。方 法一種解決方案就是使用HTML的noscript元素。那么頁面內容就可以被所有不支持腳本的瀏覽器以及被關閉了JavaScript支持的瀏覽器正確查看。雖然這也是一個可行的辦法,不過在實際操作中不是太有用。因為noscript無法區分瀏覽器對腳本的支持程度。那些只是部分支持或者受限制地支持JavaScript的瀏覽器會試圖執行比較復雜的腳本,因為它們甚至可能根本就不認識noscript標簽,其結果是在這些瀏覽器中代碼會不正常地終止,然后什么也沒干。一個更好的辦法是使用靜態HTML,然后通過腳本對靜態內容進行修改或者增加動態行為。下面看一個簡單例子。這個代碼片段是用一個未排序的列表作為主菜單結構,產生一個DHTML菜單。第15章將詳細討論有關內容,不過這個簡單的例子在這里可以充分展示我們的方法: Home About Contact鏈接的列表是純HTML,所以對于所有的用戶來說,不管使用什么瀏覽器,都可以正常顯示。如果腳本是被支持的,那么menu.js腳本就可以執行動態的操作,不過腳本不被支持時,內容仍然會顯示。我們沒有用什么明確的方法來區分不同瀏覽器對于JavaScript的支持程度,而只是提供了動態的內容,如果瀏覽器能夠處理,它就會去處理,如果不能,那么只顯示靜態內容就行了。討 論傳統的方法是,用純JavaScript代碼生成獨立的動態菜單,然后用noscript元素提供一個備用的靜態的內容: Home About Contact 不過,正如前面所說的,網上的很多瀏覽器會在這樣的代碼前面失效,因為對JavaScript的支持往往不是一個簡單的“是或不是”的問題。而這個方法提供了給所有瀏覽器的默認內容,又提供了一個可能有效的腳本功能。這種腳本方法就是所謂的逐步改進,對這種方法的使用將貫穿本書。不要提示太多!不管是這種方法還是noscript元素,都不應該被用來產生這樣的消息給用戶,“請打開JavaScript選項再繼續。”對于某些用戶,這種消息有點蠻橫(“我干嘛要聽您的?”);對于另外一些用戶,這種消息可能是無用的(“我壓根無法打開!”)或者根本是無意義的(“JavaScript是啥?”)。就像很多啟動頁面總是說,“請升級您的瀏覽器”這種消息對于大多數Web用戶而言,就像在路上看到一個牌子,提示“請換一輛車。”有時候,開發者可能會碰到除JavaScript之外再無更好的辦法來實現功能的情況。這時,我認為用一些靜態信息來提示用戶網頁遇到兼容性問題是合理的(當然,這些和技術無關)。不過,在大多數情況下,應盡量避免顯示這種信息,除非它的確有意義而且是必須要告知用戶的。1.5 內容和行為的隔離(謹慎地編碼)將內容從行為中分離,意味著按照網頁的結構分離出不同的層次來。Jeffrey Zeldman曾經將Web開發形容為“三條腿的板凳”1,分別是內容(HTML)、表示(CSS)、行為(JavaScript),他不僅指出三者在功能上的不同,同時也表明他認為這三者應該被互相隔離開來。好的隔離方式將使得網站更容易維護,也更容易被理解和使用,同時對于老的或者支持特性較少的瀏覽器也能夠提供相應的訪問方式。方 法以下是一種極端情況,正好與理想的行為內容互相分離的方法南轅北轍,也可以直接在事件處理屬性中直接寫入內嵌的代碼。但這會把頁面搞得一團糟,應該極力避免:可以把完成這些工作的代碼寫成一個函數:定義一個函數來做這件事可以將大量的代碼集中到一個單獨的JavaScript文件中:File:separate-content-behaviors.js (excerpt)function changeBorder(element, to) element.style.borderColor = to;不過更好的方法是完全不使用內嵌的事件處理,而使用文檔對象模型(DOM)來將事件處理綁定到HTML文檔的元素中。DOM是一種標準的編程接口,它使得像JavaScript這樣的語言可以直接訪問HTML文檔的內容,這也消除了出現在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,而且,因為文檔本身完全不依賴于這些腳本,所以那些不支持JavaScript的瀏覽器將絲毫不受影響。這種方法同時也增加了復用性,如果需要,也可以將相同的函數綁定到其他元素上,同樣也不需要編輯HTML。這種方法讓我們擁有了通過DOM訪問元素的能力,第5章將深入探討DOM。隔離的優點通過將內容和行為分隔開來,不僅使代碼具有更廣泛的適用性,同時這種分而治之的思考方式也將帶來好處。因為HTML和JavaScript完全分離,當我們檢視HTML代碼的時候,不會忘記這個頁面需要顯示的核心內容,而這些內容應當不依賴于任何腳本。Andy Clark把這種方式叫做Web標準甜點1,這是一種有趣的類比,這種比喻方式認為一個好的Web網站設計應該是這樣:當看過去時,應該看到組成整個甜點的隔離的優點不同層次。這種方式的反面是水果蛋糕,您無法看到蛋糕的不同組成部分。您所能看到的就是搞不清什么材料的一塊整個的蛋糕。討 論當把事件處理和如下的元素綁定起來的時候,需要注意,只有在那個元素實際存在的時候才能那么做。如果把處理腳本放到頁面的head區,瀏覽器會報告發生錯誤,然后拒絕執行代碼,因為content div在這個位置還沒有被瀏覽器解讀顯示,而JavaScript卻已經先被處理了。最直接的方法是把代碼放到load事件處理中。這種方式最保險,因為load事件只有在整個頁面已經完全載入的時候才會被激發:window.onload = function() var contentDiv = document.getElementById(content); ;或者更清楚一點,多寫一點代碼:window.onload = init;function init() var contentDiv = document.getElementById(content); 不過使用load事件的問題是,在整個頁面中只能使用一次;如果有兩個或者更多的腳本需要通過load事件來執行,那么每個腳本都會改寫對load事件的處理。解決方法是對load事件采用更好的響應方式,1.8節將繼續探討這個問題。1.6 使用括號和分號結束符(一致的編碼方式)在很多JavaScript的操作中,括號和分號是可選的,那么,既然是可有可無的,它們的價值何在?方 法雖然括號和分號通常是可選的而非必需的,但還是應當盡量多使用這兩個符號,這樣可以使其他人更容易閱讀代碼,甚至也能有助于自己以后閱讀代碼,而且通過復用和重新組織代碼,可以避免很多問題。舉個例子,如下的代碼確實能夠正常地工作:File: semicolons-braces.js (excerpt)if (something) alert(something)else alert(nothing)不過,這樣的代碼能夠正常工作應該歸功于JavaScript解釋器自動插入分號的能力。每當解釋器發現被截斷的位于不同行的兩段相鄰代碼,而且這些代碼段單列在一行上會毫無意義,解釋器就會在段之間插入分號。通過類似的機制,用于if-else語句的括號即使不存在也能夠根據語法被推斷出來,實際上是解釋器做了查遺補漏的工作。雖然這些符號不是必需的,但是如果堅持使用它們,就會發現這些符號既容易記憶也容易使用,而且寫出的代碼更容易閱讀。下面是一個稍微好一點的例子:File: semicolons-braces.js (excerpt)if (something) alert(something); else alert(nothing); 不過下面這個例子具有最佳的可讀性:File: semicolons-braces.js (excerpt)if (something) alert(something);else alert(nothing);使用函數顯式聲明如果對JavaScript的復雜部分已經有了一些經驗,那么可能會經常通過函數顯式聲明來創建匿名函數,并且將匿名函數賦值給JavaScript的變量或者對象的屬性。在下面的代碼中,定義的函數后面需要跟一個分號,因為其實它算是一個賦值語句。var saySomething = function(message) ;1.7 給頁面添加腳本要想讓腳本工作,首先需要在頁面中將其載入。有兩種技術可以做到這一點,而其中一種技術明顯優于另一種。方 法第一種,也是最直接的方法,是把代碼寫入script元素中,正像前面看見過的那樣:function saySomething(message) alert(message);saySomething(Hello world!);這種方法的問題在于,對于老的或者不支持script元素的瀏覽器,這些內容會被解釋為文本。一種更好的替代方式是將腳本放入外部的一個JavaScript文件,如下:這條語句會載入一個外部的名叫what-is-javascript.js的JavaScript文件。這個文件中將包含前一個例子放入script元素中的代碼,如下:File: what-is-javascript.jsfunction saySomething(message) alert(message);saySomething(Hello world!);采用這種方法,不支持script元素的瀏覽器會忽略JavaScript部分,也不會顯示多余內容(因為該元素的內容實際上是空的),不過那些能夠解讀script的瀏覽器會載入并處理該腳本。這有助于腳本和內容的分離,而且很容易維護,可以在不同的頁面中使用同一個腳本,而無須復制腳本,也無需維護多個拷貝。討 論也許您對避免在頁面中寫入腳本這個建議有異議,“不會有問題的呀”,您可能還會說,“我可以使用HTML注釋把代碼框起來”。不過我認為那不是一個好主意,使用HTML注釋來“隱藏”代碼是一種非常壞的習慣,一定要記住這一點。1.7.1 用HTML注釋框住代碼解析器本來無需讀取注釋內容,更不用去執行它。不過現實情況是,被注釋的JavaScript完全可以工作,這是一個歷史遺留問題,也是一種妥協,不應該假定解析器會正確地略過注釋,忽略注釋中的JavaScript,實際上,應該假定解析器一定不能正確地讀取注釋。書中的所有例子都通過HTML提供(與之相對的是XHTML),所以這種假設是合理的。不過如果使用XHTML(使用application/xhtml+xml的MIME類型),在瀏覽器處理該文件之前,XML解析器能夠正確地忽略其中的注釋,這樣,注釋的JavaScript代碼確實不會執行。不過,考慮到兼容性(以及良好的編程習慣),強烈建議您盡量不在注釋中放入代碼。JavaScript代碼應該總是放到一個外部的JavaScript文件中。1.7.2 語言屬性語言屬性不再是必需的了。當Netscape 4和它同時代的瀏覽器成為了主流時,標簽扮演了一個探測腳本支持的角色(在JavaScript 1.3中指定),并且影響著腳本解釋器的工作方式。當JavaScript變成了ECMAScript時,指定JavaScript的版本已經毫無意義,語言屬性已經被類型屬性取代。這種屬性指定了被包含文件的MIME類型,例如腳本和樣式表的類型,而且這也是惟一的一種需要指定的類型: 實際上,值應該被指定為text/ecmascript,不過Internet Explorer不認識這種信息。我個人希望它最好能支持,因為我輸入javascript幾個字比較費勁,有好多次,在輸入text/javascript的時候我都輸錯。1.8 讓不同的腳本在同一頁面中協同工作如果幾個腳本總是不能協同工作,那么很有可能是因為這些腳本試圖對某給定元素的同一種事件處理賦予了不同的處理函數。因為每個元素對每個事件只有一個處理方法,所以同一個事件的處理會被不同的處理函數重復地替換。方 法通常應該懷疑的是window對象的load事件處理,因為在同一頁面中,只有一個腳本能夠使用這個事件;如果兩個或者多個腳本嘗試使用該事件,那么最后一個腳本會將前面腳本的處理函數覆蓋掉。可以在load事件處理函數中調用多個函數,如下:window.onload = function() firstFunction(); secondFunction();不過,如果這樣做,就必須受限于在load事件的處理函數中完成所有的任務。另一個好一點的解決方案是提供一個函數,可以增加對load事件的處理而不與其他已經添加的處理函數沖突。使用下面的函數,可以添加任意數量的load事件的處理函數,而無需擔心它們發生沖突: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事件處理函數了,如下:addLoadListener(firstFunction);addLoadListener(secondFunction);addLoadListener(twentyThirdFunction);討 論JavaScript包括了給事件增加或刪除監聽器的方法,看上去有點像普通的事件處理,但卻允許多個監聽器訂閱同一個元素的同一個事件的消息。不幸的是,在Internet Explorer中這種監聽器的語法與在其他瀏覽器中的語法完全不同,IE使用一種獨有的方式,而其他瀏覽器則完全按照W3C標準來實現。開發者將經常處于這種折磨之中,在第13章將會討論有關的細節。W3C標準方法叫做addEventListener:window.addEventListener(load, firstFunction, false); IE的方法叫做attachEvent:window.attachEvent(onload, firstFunction);正如您所看到的,標準的創建方法是,直接使用事件的名字(沒有on前綴),事件發生時需要調用的函數以及一個用于控制事件傳遞的參數放在事件名字的后面(第13章會有更詳細的討論)。IE的方法則使用事件處理者的名字(前面帶有一個on前綴),需要調用的函數的名字放在其后。在將代碼組織到一起的時候,還需要測試一下試圖調用的方法是否存在。可以用JavaScript的typeof操作符,它可以區分數據的不同類型(例如字符串、數字、布爾值、對象、數組、函數或者未定義類型)。一個不存在的方法會返回未定義類型。if (typeof window.addEventListener != undefined) 支持window.addEventListener還有一點稍稍復雜的地方:在Opera中,load事件可以激發來自文檔對象的事件監聽器,卻不能激發來自窗口對象的監聽器。不過如果只使用文檔對象,這樣的代碼在老版本的Mozilla瀏覽器中(例如Netscape 6)又不能工作。為了處理這種問題,還必須測試一下window.addEventListener,然后是document.addEventListener,最后才是window.attachEvent。最后,對于那些根本不支持這些方法的瀏覽器(例如Mac IE 5),備用的方案是使用老式的鏈式事件處理方式,這樣在事件發生時事件處理函數仍能被調用。可以動態地創建一個新的事件處理函數,當事件發生時,先調用老的事件處理函數,再調用新的事件處理函數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(); ; 如果您現在對這些代碼怎樣工作還不太理解,不用擔心,后續章節還會討論更多的細節。后面大家會了解到事件監聽器不僅適用于load事件,也適用于任何事件驅動的腳本。1.9 隱藏JavaScript源代碼如果您曾經創造過讓自己驕傲的東西,您就會明白自己的智力成果是需要保護的。但是JavaScript是一種自然的源碼開放的語言,它以源代碼的方式被瀏覽器接收,所以,只要瀏覽器可以運行它,任何人也就可以閱讀它。網上有些程序宣稱提供對源代碼的加密,但其實沒有什么加密方法能夠保證別人無法解密。實際上,這些程序往往會造成麻煩,它們會重新格式化代碼,這讓代碼運行更慢、更低效,甚至會因為錯誤而不能運行。想知道我的建議嗎?干脆碰都不要碰那些所謂的加密程序。不過,為了保護代碼成果,有件事情是很容易做到的,那就是混淆代碼,混淆后的代碼非常不易閱讀和理解。方 法被去除了所有的注釋和非必需的空格之后的代碼非常難以閱讀,正如您期望的那樣,從這樣的代碼中分離出功能模塊更加困難。這種簡單的壓縮代碼的方法可以讓大部分黑客放棄讀下去的打算,除了少數非常有毅力的黑客。如下: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之后的空格。討 論除了混淆本身帶來的好處,這種去除了注釋和非必要空格的代碼通常會更加簡短,因此載入速度會更快,執行速度也會更快。但要注意,仍需要準確而嚴格地使用分號結束符和括號,就像在1.6節中討論過的,否則,去除了換行符之后,代碼被集中到一行會造成錯誤。在壓縮代碼之前,要記住先備份一個拷貝。我知道這其實是很顯然的事情,不過我曾經犯過好多次錯誤,您一定能想象我面對一團亂麻般的代碼時的郁悶。我通常的做法是維護一個有注釋和足夠多空格的易讀的版本,然后在發布之前,通過搜索/替換來處理一番。我會保留兩個拷貝,一個叫做myscript.js,另一個叫做myscript-commented.js。第20章將回到這個主題,討論一些相關技術,從而提高腳本的速度和效率,同時降低開銷。1.10 腳本調試調試是一個查錯改錯的過程。絕大多數瀏覽器擁有內建的報告錯誤的功能,還有一些外部的調試工具也值得關注。1.10.1 理解瀏覽器內建的錯誤報告Opera、Mozilla瀏覽器(例如FireFox)以及Internet Explorer都擁有很好的內建的錯誤報告功能,不過Opera和Mozilla的調試工具最為有用。(1)Opera 通過菜單ToolsAdvancedJavaScript console可以打開JavaScript控制臺。也可以把它設置為遇到錯誤的時候自動打開,方法是依次選擇ToolsPreferencesAdvancedContent菜單項,單擊JavaScript選項按鈕,打開一個對話框,然后選中Open JavaScript console on error選項。(2)FireFox和其他的Mozilla瀏覽器 通過菜單ToolsJavaScript console打開JavaScript控制臺。(3)Internet Explorer for Windows 依次選擇ToolsInternet OptionsAdvanced,然后將Disable script debugging選項前的勾取消,再選中Display a notification about every script error選項。這樣,每次發生錯誤就會彈出一個對話框。(4)Internet Explorer for Mac 依次選擇ExplorerPreferenceWeb BrowserWeb Content菜單項,然后選中Show scripting error alerts選項。Safari在默認情況下是不包括錯誤報告的,不過新版本有了一個“隱藏”的調試菜單,包括一個JavaScript控制臺,可以通過如下的終端命令來激活1:$ defaults write com.apple.safari IncludeDebugMenu -bool true 也可以使用一種叫做Safari Enhancer1的擴展,這種擴展包含了一個選項,可以將JavaScript錯誤信息輸出到Mac OS的控制臺;但是,這些信息常常都沒太大用處。理解不同瀏覽器報告的錯誤信息需要一點練習,因為每種瀏覽器給出的信息都不相同。這里給出一個例子一個錯誤類型的函數調用:function saySomething(message) alert(message);saySometing(Hello world);FireFox給出了非常簡要但卻很準確的報告,包括了發生錯誤的行號以及具體描述,如圖1.1所示。圖1.1 Firefox中的JavaScript錯誤控制臺如圖1.2所示,Opera給出了一個非常詳細的報告,包括產生錯誤的回溯信息和發生錯誤的行號,以及具體描述。圖1.2 Opera中的JavaScript控制臺回溯信息有助于定位由別的代碼引發的錯誤,例如,事件處理者調用一個函數,該函數再調用第二個函數,在這個位置發生了錯誤。Opera的控制臺能夠回溯出調用過程并找到錯誤最初發生時的函數調用或事件處理。Internet Explorer給出了非常基本的信息,如圖1.3所示。它提供了發生錯誤的行號(不過可能與真實的錯誤位置有偏差)1,還有一個很概括的錯誤類型描述,但是卻沒有指出具體的錯誤。圖1.3 Windows IE中的JavaScript控制臺我對Internet Explorer給出的很簡略的錯誤報告并沒有太多的抱怨,至少比沒有好,我知道有錯誤發生了。1.10.2 使用alert分析錯誤的時候,使用alert函數是一種非常有用的方法,可以在任何位置用它來顯示對象或者變量的值,看是否是您所期望的值。例如,如果有一個有很多條件分支的函數,可以在每個分支使用alert,看看到底哪條分支被執行了:File:debugging-dialogs.jsfunction checkAge(years) if (years = 13 & years = 21) alert(13 to 21); 其他腳本 else alert(older); 其他腳本 也許傳入的years根本就不是一個數字,不像函數期望的那樣。可以在這段代碼的開頭加入一個alert,看看究竟什么類型的變量被傳了進來:function checkAge(years) alert(typeof years); 從理論上說,可以用alert對話框顯示任意多的信息,雖然一個非常長的串會使得彈出的對話框非常寬,以至于超出了屏幕窗口的限制而被截斷。可以給輸出的信息加上換行符“n”來避免這種情況。1.10.3 使用try-catchtry-catch具有令人難以置信的力量,可以做某種嘗試,然后就能夠處理可能發生的任何錯誤了。最基本的形式如下:File:debugging-trycatch.js (excerpt)try 一些代碼catch (err) 如果try塊中發生了錯誤,這部分代碼將會運行如果無法確定哪里發生了錯誤,可以用一個try-catch的套將一大塊代碼包起來,并且處理最可能的錯誤,然后一點點縮小包圍圈。例如,可以將一個函數的部分包在try語句中,然后看看哪里發生了錯誤。然后將嫌疑代碼再分割,在適當的位置使用try套,這個過程持續下去,直到鎖定出問題的那一行。catch有一個參數(在這個例子中將它命名為err)是用來接收錯誤對象的,我們可以通過檢查這個對象的屬性,例如名字和信息,來得到這個錯誤的具體細節。通常,我會用一個for-in語句來遍歷整個對象,看看它究竟包含了什么信息:File:debugging-trycatch.js (excerpt)for (var i in err) alert(i + : + erri);1.10.4 向頁面和窗口中寫入數據如果在調試的時候需要檢查很多數據,或者正在處理的數據有著很復雜的格式,則最好直接把數據寫入一個頁面或者一個彈出的窗口中,而不需要用許多alert對話框。如果檢查的是循環中的數據,這樣也避免了產生無數個對話框,要知道,這些對話框最后還得一個一個手工去關閉,這是非常麻煩的。針對這些情況,可以使用元素的innerHTML屬性,將數據寫入頁面中。下面的例子是通過使用一個數組的內容創建一個列表,然后將它寫入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 += ;如果在頁面中沒有足夠的和方便的地方來顯示數據,也可以將數據寫入彈出對話框中: 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等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論