文章出處

5. Underscore.js

Underscore封裝了常用的JavaScript對象操作方法,用于提高開發效率。它本身與我們介紹的主題“Backbone”沒有半毛錢的關系,因此你可以完全不理會“Backbone”的概念來學習它,或將它單獨運用到任何一個頁面。(另外,Underscore還可以被使用在Node.js運行環境。)

在學習Underscore之前,你應該先保存它的API地址,因為你將在以后經常訪問它:

http://documentcloud.github.com/underscore/

從API中,你已經可以看出,Underscore沒有任何復雜的結構和流程,它僅僅提供了一系列常用的函數。如果你將API中的方法從頭至尾用一遍,你就會對它非常了解。

盡管如此,但我覺得還是有必要將一些重要的方法拿出來與大家討論,它們十分重要,卻在API中描述地還不夠清楚。

5.1 Underscore對象封裝

Underscore并沒有在原生的JavaScript對象原型中進行擴展,而是像jQuery一樣,將數據封裝在一個自定義對象中(下文中稱“Underscore對象”)。

你可以通過調用一個Underscore對象的value()方法來獲取原生的JavaScript數據,例如:

//定義一個JavaScript內置對象

varjsData={

name:'data'

}

//通過_()方法將對象創建為一個Underscore對象

//underscoreData對象的原型中包含了Underscore中定義的所有方法,你可以任意使用

varunderscoreData=_(jsData);

//通過value方法獲取原生數據,即jsData

underscoreData.value();

5.2 優先調用JavaScript 1.6內置方法

Underscore中有許多方法在JavaScript1.6中已經被納入規范,因此在Underscore對象內部,會優先調用宿主環境提供的內置方法(如果宿主環境已經實現了這些方法),以此提高函數的執行效率。

而對于不支持JavaScript 1.6的宿主環境,Underscore會通過自己的方式實現,而對開發者來說,這些完全是透明的。

這里所說的宿主環境,可能是Node.js運行環境,或客戶端瀏覽器。

5.3 改變命名空間

Underscore默認使用_(下劃線)來訪問和創建對象,但這個名字可能不符合我們的命名規范,或容易引起命名沖突。

我們可以通過noConflict()方法來改變Underscore的命名,并恢復_(下劃線)變量之前的值,例如:

var_='自定義變量';

//Underscore對象

console.dir(_);

//將Underscore對象重命名為us,后面都通過us來訪問和創建Underscore對象

varus=_.noConflict();

//輸出"自定義變量"

console.dir(_);

5.4 鏈式操作

還記得我們在jQuery中是如何進行鏈接操作嗎?例如:

$('a')

.css('position','relative')

.attr('href','#')

.show();

Underscore同樣支持鏈式操作,但你需要先調用chain()方法進行聲明:

vararr=[10,20,30];

_(arr)

.chain()

.map(function(item){returnitem++;})

.first()

.value();

如果調用了chain()方法,Underscore會將所調用的方法封裝在一個閉包內,并將返回值封裝為一個Underscore對象并返回:

//這是Underscore中實現鏈式操作的關鍵函數,它將返回值封裝為一個新的Underscore對象,并再次調用chain()方法,為方法鏈中的下一個函數提供支持。

varresult=function(obj,chain){

returnchain?_(obj).chain():obj;

}

5.5 擴展Underscore

我們可以通過mixin()方法輕松地向Underscore中擴展自定義方法,例如:

_.mixin({

method1:function(object){

//todo

},

method2:function(arr){

//todo

},

method3:function(fn){

//todo

}

});

這些方法被追加到Underscore的原型對象中,所有創建的Underscore對象都可以使用這些方法,它們享有和其它方法同樣的環境。

5.6 遍歷集合

each()和map()方法是最常用用到的兩個方法,它們用于迭代一個集合(數組或對象),并依次處理集合中的每一個元素,例如:

vararr=[1,2,3];

_(arr).map(function(item,i){

arr[i]=item+1;

});

varobj={

first:1,

second:2

}

_(obj).each(function(value,key){

returnobj[key]=value+1;

});

map()方法與each()方法的作用、參數相同,但它會將每次迭代函數返回的結果記錄到一個新的數組并返回。

5.7 函數節流

函數節流是指控制一個函數的執行頻率或間隔(就像控制水流的閘門一樣),Underscore提供了debounce()和throttle()兩個方法用于函數節流。

為了更清楚地描述這兩個方法,假設我們需要實現兩個需求:

需求1:當用戶在文本框輸入搜索條件時,自動查詢匹配的關鍵字并提示給用戶(就像在Tmall輸入搜索關鍵字時那樣)

首先分析第1個需求,我們可以綁定文本框的keypress事件,當輸入框內容發生變化時,查詢匹配關鍵字并展示。假設我想查詢“windows phone”,它包含13個字符,而我輸入完成只花了1秒鐘(好像有點快,就意思意思吧),那么在這1秒內,調用了13次查詢方法。這是一件非常恐怖的事情,如果Tmall也這樣實現,我擔心它會不會在光棍節到來之前就掛掉了(當然,它并沒有這么脆弱,但這絕對不是最好的方案)

更好的方法是,我們希望用戶已經輸入完成,或者正在等待提示(也許他懶得再輸入后面的內容)的時候,再查詢匹配關鍵字。

最后我們發現,在我們期望的這兩種情況下,用戶會暫時停止輸入,于是我們決定在用戶暫停輸入200毫秒后再進行查詢(如果用戶在不斷地輸入內容,那么我們認為他可能很明確自己想要的關鍵字,所以等一等再提示他)

這時,利用Underscore中的debounce()函數,我們可以輕松實現這個需求:

varquery=_(function(){

//在這里進行查詢操作

}).debounce(200);

$('#search').bind('keypress',query);

你能看到,我們的代碼非常簡潔,節流控制在debounce()方法中已經被實現,我們只告訴它當query函數在200毫秒內沒有被調用過的話,就執行我們的查詢操作,然后再將query函數綁定到輸入框的keypress事件。

query函數是怎么來的?我們在調用debounce()方法時,會傳遞一個執行查詢操作的函數和一個時間(毫秒數),debounce()方法會根據我們傳遞的時間對函數進行節流控制,并返回一個新的函數(即query函數),我們可以放心大膽地調用query函數,而debounce()方法會按要求幫我們做好控制。

需求2:當用戶拖動瀏覽器滾動條時,調用服務器接口檢查是否有新的內容

再來分析第2個需求,我們可以將查詢方法綁定到window.onscroll事件,但這顯然不是一個好的做法,因為用戶拖動一次滾動條可能會觸發幾十次甚至上百次onscroll事件。

我們是否可以使用上面的debounce()方法來進行節流控制?當用戶拖動滾動條完畢后,再查詢新的內容?但這與需求不符,用戶希望在拖動的過程中也能看到新內容的變化。

因此我們決定這樣做:用戶在拖動時,每兩次查詢的間隔不少于500毫秒,如果用戶拖動了1秒鐘,這可能會觸發200次onscroll事件,但我們最多只進行2次查詢。

利用Underscore中的throttle()方法,我們也可以輕松實現這個需求:

varquery=_(function(){

//在這里進行查詢操作

}).throttle(500);

$(window).bind('scroll',query);

代碼仍然十分簡潔,因為在throttle()方法內部,已經為我們實現的所有控制。

你可能已經發現,debounce()和throttle()兩個方法非常相似(包括調用方式和返回值),作用卻又有不同。

它們都是用于函數節流,控制函數不被頻繁地調用,節省客戶端及服務器資源。

debounce()方法關注函數執行的間隔,即函數兩次的調用時間不能小于指定時間。

throttle()方法更關注函數的執行頻率,即在指定頻率內函數只會被調用一次。

5.8 模板解析

Underscore提供了一個輕量級的模板解析函數,它可以幫助我們有效地組織頁面結構和邏輯。

我將通過一個例子來介紹它:

//獲取渲染元素和模板內容

varelement=$('#element'),

tpl=$('#tpl').html();

//創建數據,這些數據可能是你從服務器獲取的

vardata={

list:[

{firstName:'Zhang',lastName:'San',city:'Shanghai'},

{firstName:'Li',lastName:'Si',city:'Beijing'},

{firstName:'Wang',lastName:'Wu',city:'Guangzhou'},

{firstName:'Zhao',lastName:'Liu',city:'Shenzhen'}

]

}

//解析模板,返回解析后的內容

varhtml=_.template(tpl,data);

//將解析后的內容填充到渲染元素

element.html(html);

在本例中,我們將模板內容放到一個

看文倉www.kanwencang.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20170206/98366.html

文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()