Underscore.js常用方法介紹

Underscore.js是一個很精干的庫,壓縮后只有4KB。它提供了幾十種函數式編程的方法,彌補了標準庫的不足,大大方便了JavaScript的編程。MVC框架Backbone.js就將這個庫作為自己的工具庫。除了可以在瀏覽器環境使用,Underscore.js還可以用于Node.js。

Underscor.js定義了一個下劃線(_)對象,函數庫的所有方法都屬于這個對象。這些方法大致上可以分成:集合(collection)、數組(array)、函數(function)、對象(object)和工具(utility)五大類。

這里介紹部分的常用方法,詳細請API文檔?http://www.css88.com/doc/underscore/

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

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

1 Underscore對象封裝

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

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

javascript 代碼:
  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();

2 優先調用JavaScript 1.6內置方法

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

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

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

3 改變命名空間

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

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


html 代碼:
  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>

4 鏈式操作

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

javascript 代碼:
  1. $('a')
  2. .css('position', 'relative')
  3. .attr('href', '#')
  4. .show();

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


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

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

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

?

5 擴展Underscore

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


javascript 代碼:
  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對象都可以使用這些方法,它們享有和其它方法同樣的環境。

6 遍歷集合

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

javascript 代碼:
  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()方法的作用、參數相同,但它會將每次迭代函數返回的結果記錄到一個新的數組并返回。

7 函數節流

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

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

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

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

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

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

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


html 代碼:
  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 代碼:
  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 代碼:
  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 代碼:
  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 代碼:
  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/247537.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247537.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247537.shtml

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

相關文章

掌握ES6/ES2015核心內容

ECMAScript 6&#xff08;以下簡稱ES6&#xff09;是JavaScript語言的下一代標準。因為當前版本的ES6是在2015年發布的&#xff0c;所以又稱ECMAScript 2015。 也就是說&#xff0c;ES6就是ES2015。 雖然目前并不是所有瀏覽器都能兼容ES6全部特性&#xff0c;但越來越多的程序員…

express-generator——Express應用生成器賊快!

通過應用生成器工具 express 可以快速創建一個應用的骨架。 通過如下命令安裝&#xff1a; $ npm install express-generator -g-h 選項可以列出所有可用的命令行選項&#xff1a; $ express -hUsage: express [options] [dir]Options:-h, --help output usage inform…

轉:canvas--放大鏡效果

<!DOCTYPE html><html><head><meta charset"UTF-8"><title>鼠標事件</title></head><body><canvas id"canvas"></canvas><canvas id"offCanvas" style" display: none;&qu…

MON

早上5點,咪咪牛就醒了,開始跳到我邊上,用白毛毛把我弄醒,在我身上走來走去,把她按住撫摸也不能讓她停止.....只能拎起來扔到邊上了 ;)看起來還的確是很調皮的貓咪呢昨天晚上就開始不太怕我了,走到我的椅子邊上喵喵叫,直到把她放在身上,才慢慢睡覺,滿可愛的早上出門叫車,一車正停…

CSS做個Switch開關

Switch開關&#xff1a;根據需求可知&#xff0c;Switch開關只有兩種選擇&#xff0c;true或false。所以我們想到HTML的checkbox控件&#xff0c;用它來做。  <input id"switch" type"checkbox" class"switch" />但是在瀏覽器中&#xf…

vue小記錄1

1.入口index.html文件 做reset.css初始化&#xff0c;視口viewport設置 2.規范化eslint配置&#xff08;常用&#xff09; &#xff08;1&#xff09;rules -->"semi"分號 "semi":[error,alway], &#xff08;2&#xff09;indent 空格 "inde…

解決虛擬機能ping通宿主機,而宿主機不能ping通虛擬機

解決虛擬機能ping通宿主機&#xff0c;而宿主機不能ping通虛擬機 首先&#xff0c;查看宿主機的網卡狀態 如果沒有&#xff0c;打開虛擬機&#xff0c;選擇編輯 打開虛擬網絡編輯器&#xff0c;并選擇更改設置 勾選將設備適配器連接此網絡 完成&#xff0c;這樣宿主機便可以pin…

mongo使用學習FAQ

1:mongo的集合和database區分大小寫么? 在 MongoDB 中&#xff0c;數據庫和集合的名稱是區分大小寫的。這意味著&#xff0c;數據庫 MyDatabase 和 mydatabase 或集合 MyCollection 和 mycollection 會被視為不同的數據庫或集合。因此&#xff0c;在操作數據庫和集合時&#…

前端下載的實現

前端很多項目中&#xff0c;都有文件下載的需求&#xff0c;特別是JS生成文件內容&#xff0c;然后讓瀏覽器執行下載操作&#xff08;例如在線圖片編輯、在線代碼編輯、iPresst等&#xff09;。但受限于瀏覽器&#xff0c;很多情況下我們都只能給出個鏈接&#xff0c;讓用戶點擊…

V記錄2(文檔)Vue.extend構造器

1.簡單介紹 Vue.extend(options) 參數&#xff1a;對象 用法&#xff1a;使用Vue構造器&#xff0c;創建一個“子類”&#xff0c;參數是一個包含組件選項的對象&#xff0c;其中,data選項中必須是函數 描述&#xff1a;Vue.extend返回的是一個“擴展實例構造器”&#xff0c;也…

在javascript中,如何判斷一個被多次encode 的url 已經被decode到原來的格式?

% 而不能被無限次decodeURIComponent 可以用%來進行判斷 轉載于:https://www.cnblogs.com/zhouyideboke/p/11169705.html

推薦base.css

學習《編寫高質量代碼--Web前端開發修煉之道》 /* CSS Document */ /*css reset*/ body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;} table{ border-collapse:collapse;border-spacing:0;} fieldest,i…

如何通過RFID開發來迎接第四次工業革命(轉)

我們都經歷了革命性的沖擊&#xff0c;自上世紀90年代初的互聯網沖擊了文化和商業&#xff0c;但很少人知道如何完成RFID開發來迎接第四次工業革命&#xff0c;在接下來的二十年里&#xff0c;智能工廠的出現將成為一個重要組成部分。制造業作為我國工業的主體&#xff0c;面臨…

對js數組去重的研究

1.利用es5 let arr [1, 2, 3, 4, 5, 6, 7, 1, 2, 3] const uniquearr>{ return Array.from(new Set(arr)) } console.log(unique(arr))2.通過雙層循環使用splice刪除 let arr [1, 2, 3, 4, 5, 6, 7, 1, 2, 3] const uniquearr>{ // return Array.from(new Se…

一些前端開發經典書籍推薦和下載鏈接分享

下面的這些書都是我曾看過或了解過的&#xff1a; 一.HTML 1.《HTML5權威指南》 非常全面的書&#xff0c;內容也很新&#xff0c;包含了HTML5CSS3JS DOM。 下載鏈接&#xff1a;http://pan.baidu.com/s/1qYGn1qW HTML我暫時沒看什么書&#xff0c;學會了大部分的標簽后我…

RFID圖書管理系統程序源代碼(轉)

RFID圖書管理系統程序源代碼https://wenku.baidu.com/view/5f4e47f0c9d376eeaeaad1f34693daef5ef713d9.html

UOJ310 黎明前的巧克力 FWT

傳送門 我們要求的是\([x^0]\prod\limits_{i1}^n (2x^{a_i}1)\)&#xff0c;其中乘積定義為集合對稱差卷積。 這個直接做復雜度太高了&#xff0c;考慮優化。注意到在FWT之后&#xff0c;每一個序列中的值要么是\(3\)&#xff0c;要么是\(-1\)&#xff0c;而且這個只跟\(a_i\)有…

vue調用百度地圖API

安裝 $ npm install vue-baidu-map --save 全局注冊 在main.js 里面引入以下代碼 import BaiduMap from vue-baidu-mapVue.use(BaiduMap, {ak: 百度地圖密鑰AK }) 使用方法 <doc-preview><baidu-map class"map" style"display: flex; flex-direct…

mysql show processlist命令 詳解

SHOW PROCESSLIST顯示哪些線程正在運行。您也可以使用mysqladmin processlist語句得到此信息。如果您有SUPER權限&#xff0c;您可以看到所有線程。否則&#xff0c;您只能看到您自己的線程&#xff08;也就是&#xff0c;與您正在使用的MySQL賬戶相關的線程&#xff09;。請參…

JS 數據處理技巧及小算法匯總(轉載)

1、根據屬性來更新一個數組中的對象 const arr [ {id: 1, score: 1}, {id: 2, score: 2}, {id: 3, score: 4}]; //更新的值 const newValue {id: 3, score: 3} 更新數組中id為3的score值。 Es6 裝逼寫法如下&#xff1a; const result initial.map(x > x.id newValue.i…