對象的簡寫
在過去,若是你想建立一個對象,你須要這樣:html
var car = new Object(); car.colour = 'red'; car.wheels = 4; car.hubcaps = 'spinning'; car.age = 4;
下面的寫法可以達到一樣的效果:node
var car = { colour:'red', wheels:4, hubcaps:'spinning', age:4 }
這樣就簡單多了,你不須要反覆使用這個對象的名稱。
這樣 car 就定義好了,也許你會遇到 invalidUserInSession 的問題,這隻有你在使用IE時會碰到,只要記住一點,不要右大括號前面寫分號,你就不會有麻煩。shell
數組的簡寫編程
傳統的定義數組的方法是這樣:json
var moviesThatNeedBetterWriters = new Array( 'Transformers','Transformers2','Avatar','Indiana Jones 4');
簡寫版是這樣:數組
var moviesThatNeedBetterWriters = [ 'Transformers','Transformers2','Avatar','Indiana Jones 4'];
對於數組,這裏有個問題,其實沒有什麼圖組功能。但你會常常發現有人這樣定義上面的 car ,就像這樣:瀏覽器
var car = new Array(); car['colour'] = 'red'; car['wheels'] = 4; car['hubcaps'] = 'spinning'; car['age'] = 4;
數組不是萬能的;這樣寫不對,會讓人困惑。圖組其實是對象的功能,人們混淆了這兩個概念。緩存
三元條件符號的簡寫安全
另一個很是酷的簡寫方法是使用與三元條件符號。
你沒必要寫成下面的樣子:服務器
var direction; if(x < 200){ direction = 1; } else { direction = -1; }
你可使用三元條件符號簡化它:
var direction = x < 200 ? 1 : -1;
當條件爲true
時取問號後面的值,不然取冒號後面的值。
Douglas Crockford 發明了JSON 以後,一切全變了。
使用JSON,你可使用JavaScript自有功能把數據存貯成複雜的格式,並且不須要再作其它的額外轉換,直接能夠訪問使用。
JSON 是 「JavaScript Object Notation」 的縮寫,它用到了上面提到的兩種簡寫方法。
若是你想描述一個樂隊,你可能會像這樣寫:
var band = { "name":"The Red Hot Chili Peppers", "members": [ { "name":"Anthony Kiedis", "role":"lead vocals" }, { "name":"Michael 'Flea' Balzary", "role":"bass guitar, trumpet, backing vocals" }, { "name":"Chad Smith", "role":"drums,percussion" }, { "name":"John Frusciante", "role":"Lead Guitar" } ], "year":"2009" }
你能夠在JavaScript裏直接使用JSON,能夠把它封裝在函數裏,甚至做爲一個API的返回值形式。
咱們把這稱做 JSON-P ,不少的API都使用這種形式。
你能夠調用一個數據提供源,在script代碼裏直接返回 JSON-P 數據:
<div id="delicious"></div> <script> function delicious(o){ var out = '<ul>'; for(var i=0;i<o.length;i++) { out += '<li><a href="' + o[i].u + '">' + o[i].d + '</a></li>'; } out += '</ul>'; document.getElementById('delicious').innerHTML = out; } </script> <script src="#"></script>
這是調用 Delicious 網站提供的 Web service 功能,得到JSON格式的最近的無序書籤列表。
基本上,JSON是最輕便的描述複雜數據結構的方法,並且它能在瀏覽器裏運行。你甚至能夠在PHP裏用 json_decode() 函數來運行它。
JavaScript裏的math和String函數後,發現它們能極大的簡化個人編程勞動。使用它們,你能夠省去複雜的循環處理和條件判斷。
例如,當須要實現一個功能,找出數字數組裏最大的一個數時,我過去是這樣寫出這個循環的,就像下面:
var numbers = [3,342,23,22,124]; var max = 0; for(var i=0;i<numbers.length;i++) { if(numbers[i] > max){ max = numbers[i]; } } alert(max);
不用循環也能實現:
var numbers = [3,342,23,22,124]; numbers.sort(function(a,b){ return b - a }); alert(numbers[0]);
Web應用都是由事件驅動運轉的。我喜歡事件處理,尤爲喜歡本身定義事件。
它能使你的產品可擴展,而不用改動核心代碼。
有一個很大的問題(也能夠說是功能強大的表現),是關於頁面上事件的移除問題。你能夠對某個元素安裝一個事件監聽器,事件監聽器就開始運轉工做。
但頁面上沒有任何指示說明這有個監聽器。由於這種不可表現的問題 (這尤爲讓一些新手頭疼) ,以及像IE6這樣的」瀏覽器「在太多的使用事件監聽時會出現各類的內存問題,你不得不認可儘可能少使用事件編程是個明智的作法。
因而事件委託就出現了。
當頁面上某個元素上的事件觸發時,而在 DOM 繼承關係上,這個元素的全部子元素也能接收到這個事件,這時你可使用一個在父元素上的事件處理器來處理,而不是使用一堆的各個子元素上的事件監聽器來處理。
到底是什麼意思?這樣說吧,頁面上有不少超連接,你不想直接使用這些連接,想經過一個函數來調用這個連接,HTML代碼是這樣的:
<h2>Great Web resources</h2> <ul id="resources"> <li><a href="http://opera.com/wsc">Opera Web Standards Curriculum</a></li> <li><a href="http://sitepoint.com/">Sitepoint</a></li> <li><a href="http://alistapart.com/">A List Apart</a></li> <li><a href="http://yuiblog.com/">YUI Blog</a></li> <li><a href="http://blameitonthevoices.com/">Blame it on the voices</a></li> <li><a href="http://oddlyspecific.com/">Oddly specific</a></li> </ul>
常見的作法是經過循環這些連接,將每一個連接上附加一個事件處理器:
(function(){ var resources = document.getElementById('resources'); var links = resources.getElementsByTagName('a'); var all = links.length; for(var i=0;i<all;i++) { // Attach a listener to each link links[i].addEventListener('click',handler,false); }; function handler(e) { var x = e.target; // Get the link that was clicked alert(x); e.preventDefault(); }; })();
咱們用一個事件處理器也能完成這項任務:
(function(){ var resources = document.getElementById('resources'); resources.addEventListener('click',handler,false); function handler(e) { var x = e.target; // get the link tha if(x.nodeName.toLowerCase()== 'a') { alert('Event delegation:' + x); e.preventDefault(); } }; })();
由於點擊事件就發生在這些頁面元素裏,你要作的就是比較它們的 nodeName
,找出應該回應這個事件的那個元素。
免責聲明:上面說的這兩個關於事件的例子,在全部瀏覽器裏都能運行,除了IE6,在IE6上你須要使用一個事件模型,而不是簡單的W3C的標準實現。這也就是咱們推薦使用一些工具包的緣由。
這種方法的好處並非僅限於把多個事件處理器縮減爲一個。你想一想,舉個例子,你須要動態的往這個連接表裏追加更多的連接。使用事件委託後,你就不須要作其它修改了;不然的話,你須要從新循環這個連接表,從新給每一個連接安裝事件處理器。
在JavaScript裏最使人懊惱的事情是變量沒有使用範圍。任何變量,函數,數組,對象,只要不在函數內部,都被認爲是全局的,這就是說,這個頁面上的其它腳本也能夠訪問它,並且能夠覆蓋重寫它。
解決辦法是,把你的變量放在一個匿名函數內部,定義完以後當即調用它。
例如,下面的寫法將會產生三個全局變量和兩個全局函數:
var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] }
若是這個頁面上的其它腳本里也存在一個叫 status
的變量,麻煩就會出現。
若是咱們把它們封裝在一個 myApplication
裏,這個問題就迎刃而解了:
可是,這樣一來,在函數外面就沒有什麼功能了。若是這是你須要的,那就能夠了。
你還能夠省去函數的名稱:
(function(){ var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } })();
若是你想在函數外面也能使用裏面的東西,那就要作些修改。
爲了能訪問 createMember() 或 getMemberDetails(),你須要把它們變成 myApplication的屬性,從而把它們暴露於外部的世界:
var myApplication = function() { var name = 'Chris'; var age = '34'; var status = 'single'; return{ createMember:function(){ // [...] }, getMemberDetails:function(){ // [...] } } }();
這被稱做 module 模式或 singleton。
Douglas Crockford 屢次談到過這些,Yahoo User Interface Library YUI 裏對此有大量的使用。但這樣一來讓我感到不便的是,我須要改變句式來使函數和變量能被外界訪問。更甚者,調用時我還須要加上myApplication 這個前綴。因此,我不喜歡這樣作,我更願意簡單的把須要能被外界訪問的元素的指針導出來。這樣作後,反倒簡化了外界調用的寫法:
var myApplication = function() { var name = 'Chris'; var age = '34'; var status = 'single'; function createMember(){ // [...] } function getMemberDetails(){ // [...] } return{ create:createMember, get:getMemberDetails } }();
我把這個稱做 「revealing module pattern.」
一旦我把所寫的JavaScript代碼發佈到這個世界上,就有人想改動它,一般是人們想讓它完成一些它自己完成不了的任務—但一般也是我寫的程序不夠靈活,沒有提供用戶可自定義的功能。
一般狀況下這是你編程過程當中的最後一步要作的事情。我把這些集中表如今了一個例子裏: 「Five things to do to a script before handing it over to the next developer.」
實際上,你也但願你的代碼可以讓人們很方面的使用,而且根據他們各自的須要進行一些改動。
若是你實現了這個功能,你會少收到一些抱怨你的腳本的人發送給你的讓你困惑的郵件,這些信件會告訴你,有人修改了你的腳本,並且很好用。
在這麼多年的編程經歷中,我所領悟到的一個重要的事情就是,JavaScript是一個很優秀的開發界面交互的語言,但若是用來處理數字或訪問數據源,那就有點使不上勁了。
最初,我學習JavaScript,是用來替代Perl的,由於我很討厭非要把代碼拷貝到 cgi-bin
文件夾下才能使Perl運行。
後來,我明白了應該使用一種後臺工做的語言來處理主要的數據,而不能什麼事情都讓JavaScript去作。更重要的是咱們要考慮安全性和語言特徵。
若是我訪問一個Web service, 我能夠獲取到JSON-P 格式的數據,在客戶端瀏覽器裏我把它作各類各樣的數據轉換,但當我有了服務器時,我有了更多的方法來轉換數據,我能夠在Server端生成JSON或HTML格式的數據返回給客戶端,以及緩存數據等操做。
若是你事先了解了並準備了這些,你會長期收益,省去了不少頭疼的時間。
在我最初開始搞Web開發時,在訪問頁面時,到底是使用 document.all
仍是使用 document.layers
的問題上痛苦的掙扎了好久。
我選擇了 document.layers
,由於我喜歡任何層都是本身的document的思想 (並且我寫了太多的 document.write
來生成元素)。
層模式最終失敗了,因而我開始使用 document.all
。
當Netscape 6 公佈只支持 W3C DOM 模型時,我很高興,但其實用戶並不關心這些。
用戶只是看見這種瀏覽器不能顯示大多數瀏覽器都能正常顯示的東西—這是咱們編碼的問題。
咱們編寫了短視的代碼,只能運行在當前的環境下,而不幸的是,咱們的運行環境卻在不停的改變。
我已經浪費了太多的時間來處理對各類瀏覽器各類版本兼容的問題。
善於處理這類問題提供了我一個好的工做機會。但如今咱們沒必要在忍受這種痛苦了。
一些工具包,例如 YUI, jQuery 以及 Dojo 都可以幫咱們處理這類問題。
它們經過抽象各類接口實現來處理瀏覽器的各類問題,像版本不兼容,設計缺陷等,把咱們從痛苦中解救出來。
除非你要測試某個Beta版的瀏覽器,千萬不要在本身的程序裏添加修正瀏覽器的缺陷的代碼,由於你頗有可能當瀏覽器已經修改了這個問題時,你卻忘了刪除你的代碼。
另外一方面,徹底依賴於工具包也是個短視的行爲。工具包能夠幫你快速的開發,但若是你不深刻理解JavaScript,你也會作錯事。