Underscore簡介

?

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]?view plain?copy

  1. //?定義一個JavaScript內置對象??
  2. var?jsData?=?{??
  3. ????name?:?'data'??
  4. }??
  5. ??
  6. //?通過_()方法將對象創建為一個Underscore對象??
  7. //?underscoreData對象的原型中包含了Underscore中定義的所有方法,你可以任意使用??
  8. var?underscoreData?=?_(jsData);??
  9. ??
  10. //?通過value方法獲取原生數據,?即jsData??
  11. underscoreData.value();??

5.2 優先調用JavaScript 1.6內置方法

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

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

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

5.3 改變命名空間

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

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

[html]?view plain?copy

  1. <script?type="text/javascript">??
  2. ????var?_?=?'自定義變量';??
  3. </script>??
  4. <script?type="text/javascript"?src="underscore/underscore-min.js"></script>??
  5. <script?type="text/javascript">??
  6. ????//?Underscore對象??
  7. ????console.dir(_);??
  8. ????//?將Underscore對象重命名為us,?后面都通過us來訪問和創建Underscore對象??
  9. ????var?us?=?_.noConflict();??
  10. ????//?輸出"自定義變量"??
  11. ????console.dir(_);??
  12. </script>??

?

5.4 鏈式操作

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

$('a').css('position', 'relative').attr('href', '#').show();

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

[javascript]?view plain?copy

  1. var?arr?=?[10,?20,?30];??
  2. _(arr)??
  3. ????.chain()??
  4. ????.map(function(item)?{??
  5. ????????return?item++;??
  6. ????})??
  7. ????.first()??
  8. ????.value();??

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

[javascript]?view plain?copy

  1. //?這是Underscore中實現鏈式操作的關鍵函數,它將返回值封裝為一個新的Underscore對象,并再次調用chain()方法,為方法鏈中的下一個函數提供支持。??
  2. var?result?=?function(obj,?chain)?{??
  3. ????return?chain???_(obj).chain()?:?obj;??
  4. }??

5.5 擴展Underscore

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

[javascript]?view plain?copy

  1. _.mixin({??
  2. ????method1:?function(object)?{??
  3. ????????//?todo??
  4. ????},??
  5. ????method2:?function(arr)?{??
  6. ????????//?todo??
  7. ????},??
  8. ????method3:?function(fn)?{??
  9. ????????//?todo??
  10. ????}??
  11. });??

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

5.6 遍歷集合

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

[javascript]?view plain?copy

  1. var?arr?=?[1,?2,?3];??
  2. ??
  3. _(arr).map(function(item,?i)?{??
  4. ????arr[i]?=?item?+?1;??
  5. });??
  6. ??
  7. var?obj?=?{??
  8. ????first:?1,??
  9. ????second:?2??
  10. }??
  11. ??
  12. _(obj).each(function(value,?key)?{??
  13. ????return?obj[key]?=?value?+?1;??
  14. });??

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

5.7 函數節流

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

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

?

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

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

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

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

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

[html]?view plain?copy

  1. <input?type="text"?id="search"?name="search"?/>??
  2. <script?type="text/javascript">??
  3. ????var?query?=?_(function()?{??
  4. ????????//?在這里進行查詢操作??
  5. ????}).debounce(200);??
  6. ??
  7. ????$('#search').bind('keypress',?query);??
  8. </script>??

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

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

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

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

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

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

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

[html]?view plain?copy

  1. <script?type="text/javascript">??
  2. ????var?query?=?_(function()?{??
  3. ????????//?在這里進行查詢操作??
  4. ????}).throttle(500);??
  5. ??
  6. ????$(window).bind('scroll',?query);??
  7. </script>??

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

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

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

?

  • debounce()方法關注函數執行的間隔,即函數兩次的調用時間不能小于指定時間。
  • throttle()方法更關注函數的執行頻率,即在指定頻率內函數只會被調用一次。

?

5.8 模板解析

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

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

[html]?view plain?copy

  1. <!--?用于顯示渲染后的標簽?-->??
  2. <ul?id="element"></ul>??
  3. ??
  4. <!--?定義模板,將模板內容放到一個script標簽中?-->??
  5. <script?type="text/template"?id="tpl">??
  6. ????<%?for(var?i?=?0;?i?<?list.length;?i++)?{?%>??
  7. ????????<%?var?item?=?list[i]?%>??
  8. ????????<li>??
  9. ????????????<span><%=item.firstName%>?<%=item.lastName%></span>??
  10. ????????????<span><%-item.city%></span>??
  11. ????????</li>??
  12. ????<%?}?%>??
  13. </script>??
  14. <script?type="text/javascript"?src="underscore/underscore-min.js"></script>??
  15. <script?type="text/javascript">??
  16. ????//?獲取渲染元素和模板內容??
  17. ????var?element?=?$('#element'),??
  18. ????????tpl?=?$('#tpl').html();??
  19. ??????
  20. ????//?創建數據,?這些數據可能是你從服務器獲取的??
  21. ????var?data?=?{??
  22. ????????list:?[??
  23. ????????????{firstName:?'<a?href="#">Zhang</a>',?lastName:?'San',?city:?'Shanghai'},??
  24. ????????????{firstName:?'Li',?lastName:?'Si',?city:?'<a?href="#">Beijing</a>'},??
  25. ????????????{firstName:?'Wang',?lastName:?'Wu',?city:?'Guangzhou'},??
  26. ????????????{firstName:?'Zhao',?lastName:?'Liu',?city:?'Shenzhen'}??
  27. ????????]??
  28. ????}??
  29. ??????
  30. ????//?解析模板,?返回解析后的內容??
  31. ????var?html?=?_.template(tpl,?data);??
  32. ????//?將解析后的內容填充到渲染元素??
  33. ????element.html(html);??
  34. </script>??

在本例中,我們將模板內容放到一個<script>標簽中,你可能已經注意到標簽的type是text/template而不是text/javascript,因為它無法作為JavaScript腳本直接運行。

  我也建議你將模板內容放在<script>中,因為如果你將它們寫在一個<div>或其它標簽中,它們可能會被添加到DOM樹中進行解析(即使你隱藏了這個標簽也無法避免)。

  _.template模板函數只能解析3種模板標簽(這比Smarty、JSTL要簡單得多):

  <% ?%>:用于包含JavaScript代碼,這些代碼將在渲染數據時被執行。

  <%= %>:用于輸出數據,可以是一個變量、某個對象的屬性、或函數調用(將輸出函數的返回值)。

  <%- %>:用于輸出數據,同時會將數據中包含的HTML字符轉換為實體形式(例如它會將雙引號轉換為&quot;形式),用于避免XSS攻擊。

  當我們希望將數據中的HTML作為文本顯示出來時,常常會使用<%- %>標簽。

  Underscore還允許你修改這3種標簽的形式,如果我們想使用{% %}、{%= %}、{%- %}作為標簽,可以通過修改templateSettings來實現,就像這樣:

[javascript]?view plain?copy

  1. _.templateSettings?=?{??
  2. ????evaluate:?/\{%([\s\S]+?)\%\}/g,??
  3. ????interpolate:?/\{%=([\s\S]+?)\%\}/g,??
  4. ????escape:?/\{%-([\s\S]+?)%\}/g??
  5. }??

在本例中,我們將模板內容和需要填充的數據傳遞給template方法,它會按以下順序進行處理:

?

  • 將模板內容解析為可執行的JavaScript(解析模板標簽)
  • 通過with語句將解析后的JavaScript作用域修改為我們傳遞的數據對象,這使我們能夠直接在模板中通過變量形式訪問數據對象的屬性
  • 執行解析后的JavaScript(將數據填充到模板)
  • 返回執行后的結果

?

?  我們經常會遇到一種情況:多次調用template方法將數據渲染到同一個模板。

  假設我們有一個分頁列表,列表中的每一條數據都通過模板渲染,當用戶進入下一頁,我們會獲取下一頁的數據并重新渲染,實際上每次渲染的模板都是同一個,但剛才描述的template所有處理過程總會被執行。

  其實Underscore的template方法提供了一種更高效的調用方式,我們將上面代碼中的最后兩句修改為:

[javascript]?view plain?copy

  1. //?解析模板,?返回解析后的內容??
  2. var?render?=?_.template(tpl);??
  3. var?html?=?render(data);??
  4. //?將解析后的內容填充到渲染元素??
  5. element.html(html);??

你會發現細微的差別:我們在調用template方法時只傳遞了模板內容,而沒有傳遞數據,此時template方法會解析模板內容,生成解析后的可執行JavaScript代碼,并返回一個函數,而函數體就是解析后的JavaScript,因此當我們調用該函數渲染數據時,就省去了模板解析的動作。

?  你應該將返回的函數存儲起來(就像我將它存儲在render變量中一樣),再通過調用該函數來渲染數據,特別是在同一個模板可能會被多次渲染的情況下,這樣做能提高執行效率(具體提升多少,應該根據你的模板長度和復雜度而定,但無論如何,這都是一個良好的習慣)。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/456820.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/456820.shtml
英文地址,請注明出處:http://en.pswp.cn/news/456820.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

POJ2190 HDU2714 ISBN

USACO 2003 Fall Orange 問題鏈接&#xff1a;POJ2190 HDU2714 ISBN。 問題簡述&#xff1a;參見上述鏈接。 問題分析&#xff1a; 單純的計算問題。需要注意以下幾點&#xff1a; 1.如果是末尾數&#xff0c;則輸出為‘X’&#xff1b; 2.如果能找到對應的值則輸出&#xff1b…

Django-安裝xadmin的方法及主要配置方法

歷經千辛萬苦&#xff0c;終于實現了django2.1中xadmin的使用 被論壇里各路神仙帶跑N次 準確說是幾個小時 直接colne https://github.com/Liu0330/xadmin 工作系統環境&#xff1a;win10Python3.6.xDjango2.1.xXadmin2.0&#xff08;注意2.2版本就不行&#xff01;&#xff…

大數據集群搭建之Linux的安裝(一)

1、準備工具 VMWare、centos mimal版本系統文件。 2、工具安裝 1、安裝vmware軟件 安裝軟件地址&#xff1a; VMWare&#xff1a;http://pan.baidu.com/s/1qYnySrE 密碼&#xff1a;3t3r centos mimal版本&#xff1a;http://pan.baidu.com/s/1dE5LY6H 密碼&#xff1a…

阻止事件冒泡兩種方式:event.stopPropagation();和return false;

jQuery提供了兩種方式來阻止事件冒泡。 方式一&#xff1a;event.stopPropagation(); $("#div1").mousedown(function (event) {event.stopPropagation(); }); 方式一&#xff1a;return false; $("#div1").mousedown(function (event) {return false; });…

關于電腦的基礎單詞筆記

chapter01 mouse 鼠標. keyboard 鍵盤. notepad 記事本 . sava 保存. chapter02 word 文本文檔. office 辦公軟件. copy 復制. past 粘貼. find 復制. table 表格. page 頁. picture 圖片. chapter03 sheet 工作薄. cell 單元格. number 數字. true 真. …

Python3.6+Django2.0+Xadmin2.0學生信息管理系統

一、創建模型 模型是表示我們的數據庫表或集合類&#xff0c;并且其中所述類的每個屬性是表或集合的字段&#xff0c;在 app/models.py 中定義。 1、首先&#xff0c;導入models模塊 from django.db import models 接下來創建個學生信息類&#xff0c;其中包含學生姓名、性別…

升級 pip版本

安裝第三方庫&#xff1a;pip install Pillow 出現 You are using pip version 7.1.2, however version 9.0.1 is available. You should consider upgrading via the python -m pip install --upgrade pip comm and. 解決方法1&#xff1a; 輸入“python -m pip install -U pi…

大數據集群搭建之節點的網絡配置過程(二)

緊接著上一章來設置windows的vmnet8的ip地址和虛擬機中centos的ip地址。 NAT虛擬網絡的配置圖如下圖所示&#xff1a; 1、這里根據VMware中得到的網關地址去設置vmnet8的ip地址。 網關地址查看&#xff1a; 2、得到的網關地址后去設置vmnet8&#xff0c;將網關地址設置為v…

Python3.6+Django2.0+Xadmin2.0學生信息管理系統-2

1、上傳圖片/文件等資源 有時候需要添加一些附件&#xff0c;例如&#xff0c;新生剛入學&#xff0c;大家相互之間還不熟悉&#xff0c;希望能通過照片來加深印象&#xff0c;并且方便教學管理。 首先&#xff0c;對demo/urls.py文件進行改造&#xff0c;給urlpatterns添加s…

vim自帶的練習教程(vimtutor)

聲明&#xff1a;本文源于Centos 7.2系統vim自帶的練習教程--vimtutor歡迎閱 讀《 V I M 教 程 》 - 版本 1.7 Vim 是一個具有很多命令的功能非常強大的編輯器。限于篇幅&#xff0c;在本教程當中就不詳細介紹了。本教程的設計目標是講述一些必要的基本命令&#xff0c;而掌握…

pycharm之no python interpreter configured for project的解決辦法

今天由于重裝了系統&#xff0c;所以必須得重新配置一些軟件&#xff0c;在打開pycharm運行程序時顯示“no python interpreter configured for project”提示。根據字面意思是“python沒有解釋器”。 解決辦法&#xff1a; 找到你之前下載python環境支持庫如下圖所示&#x…

Python是非常優美的語言,那到底如何個美呢?

我把Python里面非常有名的簡潔&#xff0c;高效&#xff0c;方便的代碼整理出來&#xff0c;讓我們來一睹她的風采。其實每個主題展開講都是很大的篇幅&#xff0c;今天我們先overview一下 看完之后&#xff0c;相信初學者會更快的喜歡上python. 1.列表推導 要說Python里面最…

js生成驗證碼并且驗證

<html> <head> <title>驗證碼</title> <style type"text/css"> #code { font-family:Arial; font-style:italic; font-weight:bold; border:0; letter-spacing:2px; color:blue; } </style> <script type &qu…

大數據集群搭建之hadoop、tomcat、jdk等工具的安裝(三)

目錄一、準備的資源&#xff1a;二、安裝配置過程 目錄 本章就說下各種軟件的安裝和配置。 一、準備的資源&#xff1a; 1、tomcat(如用于在網頁上查看HDFS的存儲等) 地址&#xff1a;http://pan.baidu.com/s/1miC93ny 密碼&#xff1a;52dd 2、jdk 地址&#xff1a;ht…

pycharm 快捷鍵大全

1、編輯&#xff08;Editing&#xff09; Ctrl Space 基本的代碼完成&#xff08;類、方法、屬性&#xff09; Ctrl Alt Space 快速導入任意類 Ctrl Shift Enter 語句完成 Ctrl P 參數信息&#xff08;在方法中調用參數&#xff09; Ctrl Q 快速查看文檔 F1 Web幫…

轉載 Spark性能優化指南——基礎篇

前言 在大數據計算領域&#xff0c;Spark已經成為了越來越流行、越來越受歡迎的計算平臺之一。Spark的功能涵蓋了大數據領域的離線批處理、SQL類處理、流式/實時計算、機器學習、圖計算等各種不同類型的計算操作&#xff0c;應用范圍與前景非常廣泛。在美團?大眾點評&#xff…

JavaScript 判斷變量是否為數組Array的方法

1. 不能用typeof &#xff0c;因為typeof 只能判斷基本類型&#xff0c;不能判斷引用類型 var ary [1,23,4];console.log(typeof ary); //輸出結果是Object上面的辦法并不能實時的檢測出是否是數組&#xff0c;只能判斷其類型&#xff0c;所以說typeof判斷基本類型數據還是挺好…

require.js用法簡介

一、為什么要用require.js&#xff1f; 最早的時候&#xff0c;所有Javascript代碼都寫在一個文件里面&#xff0c;只要加載這一個文件就夠了。后來&#xff0c;代碼越來越多&#xff0c;一個文件不夠了&#xff0c;必須分成多個文件&#xff0c;依次加載。下面的網頁代碼&…

Pycharm新建文件時自動添加基礎信息

# -*- coding: utf-8 -*- # Time : ${DATE} ${TIME} # Author : Liu # File : ${NAME}.py 如下圖所示 再建一個py文件時就會自動添加信息&#xff1a; # -*- coding: utf-8 -*- # Time : 2019/05/05 11:46 # Author : Liu # File : DOUBAN.py

JTLParser-linux上jmeter的jtl文件二次分析

解析JMeter的JTL文件 2013年01月30日 ? 綜合 ? 共 1452字 ? 字號 小 中 大 ? 評論關閉http://code.google.com/p/xtoolkit/wiki/JTLParser Introduction 當把JMeter使用命令行運行后&#xff0c;JMeter會把結果保存到一個指定文件中&#xff08;使用 -l 參數指定&#xff0…