1 Underscore.js 2 3 Underscore 是一個 JavaScript 工具庫,它提供了一整套函數式編程的實用功能,可是沒有擴展任何 JavaScript 內置對象。 他解決了這個問題:「若是我面對一個空白的 HTML 頁面,並但願當即開始工做,我須要什麼?」 他彌補了 jQuery 沒有實現的功能,同時又是 Backbone 必不可少的部分。 4 5 Underscore 提供了100多個函數,包括經常使用的:map、filter、invoke — 固然還有更多專業的輔助函數,如:函數綁定、JavaScript 模板功能、建立快速索引、強類型相等測試等等。 6 7 爲了你能仔細研讀,這裏包含了一個完整的測試套件。 8 9 你還能夠通讀帶有註釋的源碼。 10 11 享受 Underscore 所帶來的便利吧。若是你但願得到更多有用的功能,能夠試試 Underscore-contrib。 12 13 本項目 託管在 GitHub 上。 你能夠在 issues page 或 Freenode 上的 #documentcloud 頻道內報告 bug 以及參與特性討論。 14 15 Underscore 是 DocumentCloud 的一個開源組件。 16 下載 (點擊右鍵「另存爲」) 17 開發版本 (1.7.0) 46kb,未壓縮,包含大量註釋 18 生產環境版本 (1.7.0) 5.2kb,去除註釋並壓縮 (Source Map) 19 不穩定版本 不發佈,當前 master 代碼分支,風險自負。 20 安裝 21 22 Node.js npm install underscore 23 Meteor.js meteor add underscore 24 Require.js require(["underscore"], ... 25 Bower bower install underscore 26 Component component install jashkenas/underscore 27 28 稽覈函數(數組或對象) 29 30 each_.each(list, iteratee, [context]) 別名: forEach 31 遍歷list中的全部元素,按順序用遍歷輸出每一個元素。若是傳遞了context參數,則把iteratee綁定到context對象上。每次調用iteratee都會傳遞三個參數:(element, index, list)。若是list是個JavaScript對象,iteratee的參數是 (value, key, list))。返回list以方便鏈式調用。(注:若是存在原生的forEach方法,Underscore就使用它代替。) 32 33 _.each([1, 2, 3], alert); 34 => alerts each number in turn... 35 _.each({one: 1, two: 2, three: 3}, alert); 36 => alerts each number value in turn... 37 38 注意:集合函數能在數組,對象,和類數組對象,好比arguments, NodeList和相似的數據類型上正常工做。 可是它經過鴨子類型工做,因此要避免傳遞一個不固定length屬性的對象(注:對象或數組的長度(length)屬性要固定的)。每一個循環不能被破壞 - 打破, 使用_.find代替,這也是很好的注意。 39 40 map_.map(list, iteratee, [context]) 別名: collect 41 經過變換函數(iteratee迭代器)把list中的每一個值映射到一個新的數組中(注:產生一個新的數組)。若是存在原生的map方法,就用原生map方法來代替。若是list是個JavaScript對象,iteratee的參數是(value, key, list)。 42 43 _.map([1, 2, 3], function(num){ return num * 3; }); 44 => [3, 6, 9] 45 _.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); 46 => [3, 6, 9] 47 48 reduce_.reduce(list, iteratee, [memo], [context]) Aliases: inject, foldl 49 別名爲 inject 和 foldl, reduce方法把list中元素歸結爲一個單獨的數值。Memo是reduce函數的初始值,reduce的每一步都須要由iteratee返回。這個迭代傳遞4個參數:memo, value 和 迭代的index(或者 key)和最後一個引用的整個 list。 50 51 若是沒有memo傳遞給reduce的初始調用,iteratee不會被列表中的第一個元素調用。第一個元素將取代 傳遞給列表中下一個元素調用iteratee的memo參數, 52 53 var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0); 54 => 6 55 56 reduceRight_.reduceRight(list, iteratee, memo, [context]) 別名: foldr 57 reducRight是從右側開始組合的元素的reduce函數,若是存在JavaScript 1.8版本的reduceRight,則用其代替。Foldr在javascript中不像其它有懶計算的語言那麼有用(注:lazy evaluation:一種求值策略,只有當表達式的值真正須要時纔對表達式進行計算)。 58 59 var list = [[0, 1], [2, 3], [4, 5]]; 60 var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); 61 => [4, 5, 2, 3, 0, 1] 62 63 find_.find(list, predicate, [context]) 別名: detect 64 在list中逐項查找,返回第一個經過predicate迭代函數真值檢測的元素值,若是沒有值傳遞給測試迭代器將返回undefined。 若是找到匹配的元素,函數將當即返回,不會遍歷整個list。 65 66 var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); 67 => 2 68 69 filter_.filter(list, predicate, [context]) 別名: select 70 遍歷list中的每一個值,返回包含全部經過predicate真值檢測的元素值。(注:若是存在原生filter方法,則用原生的filter方法。) 71 72 var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); 73 => [2, 4, 6] 74 75 where_.where(list, properties) 76 遍歷list中的每個值,返回一個數組,這個數組包含包含properties所列出的屬性的全部的鍵 - 值對。 77 78 _.where(listOfPlays, {author: "Shakespeare", year: 1611}); 79 => [{title: "Cymbeline", author: "Shakespeare", year: 1611}, 80 {title: "The Tempest", author: "Shakespeare", year: 1611}] 81 82 findWhere_.findWhere(list, properties) 83 遍歷list中的每個值,返回匹配properties所列出的屬性的全部的鍵 - 值對的第一個值。 84 85 若是沒有找到匹配的屬性,或者list是空的,那麼將返回undefined。 86 87 _.findWhere(publicServicePulitzers, {newsroom: "The New York Times"}); 88 => {year: 1918, newsroom: "The New York Times", 89 reason: "For its public service in publishing in full so many official reports, 90 documents and speeches by European statesmen relating to the progress and 91 conduct of the war."} 92 93 reject_.reject(list, predicate, [context]) 94 返回list中沒有經過predicate真值檢測的元素集合,與filter相反。 95 96 var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; }); 97 => [1, 3, 5] 98 99 every_.every(list, [predicate], [context]) 別名: all 100 若是list中的全部元素都經過predicate的真值檢測就返回true。(注:若是存在原生的every方法,就使用原生的every。) 101 102 _.every([true, 1, null, 'yes'], _.identity); 103 => false 104 105 some_.some(list, [predicate], [context]) 別名: any 106 若是list中有任何一個元素經過 predicate 的真值檢測就返回true。一旦找到了符合條件的元素, 就直接中斷對list的遍歷. (注:若是存在原生的some方法,就使用原生的some。) 107 108 _.some([null, 0, 'yes', false]); 109 => true 110 111 contains_.contains(list, value) 別名: include 112 若是list包含指定的value則返回true(注:使用===檢測)。若是list 是數組,內部使用indexOf判斷。 113 114 _.contains([1, 2, 3], 3); 115 => true 116 117 invoke_.invoke(list, methodName, *arguments) 118 在list的每一個元素上執行methodName方法。 任何傳遞給invoke的額外參數,invoke都會在調用methodName方法的時候傳遞給它。 119 120 _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); 121 => [[1, 5, 7], [1, 2, 3]] 122 123 pluck_.pluck(list, propertyName) 124 pluck也許是map最常使用的用例模型的簡化版本,即萃取對象數組中某屬性值,返回一個數組。 125 126 var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 127 _.pluck(stooges, 'name'); 128 => ["moe", "larry", "curly"] 129 130 max_.max(list, [iteratee], [context]) 131 返回list中的最大值。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。若是list爲空,將返回-Infinity,因此你可能須要事先用isEmpty檢查 list 。 132 133 var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 134 _.max(stooges, function(stooge){ return stooge.age; }); 135 => {name: 'curly', age: 60}; 136 137 min_.min(list, [iteratee], [context]) 138 返回list中的最小值。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。若是list爲空,將返回-Infinity,因此你可能須要事先用isEmpty檢查 list 。 139 140 var numbers = [10, 5, 100, 2, 1000]; 141 _.min(numbers); 142 => 2 143 144 sortBy_.sortBy(list, iteratee, [context]) 145 返回一個排序後的list拷貝副本。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。迭代器也能夠是字符串的屬性的名稱進行排序的(好比 length)。 146 147 _.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); }); 148 => [5, 4, 6, 3, 1, 2] 149 150 groupBy_.groupBy(list, iteratee, [context]) 151 把一個集合分組爲多個集合,經過 iterator 返回的結果進行分組. 若是 iterator 是一個字符串而不是函數, 那麼將使用 iterator 做爲各元素的屬性名來對比進行分組. 152 153 _.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); }); 154 => {1: [1.3], 2: [2.1, 2.4]} 155 156 _.groupBy(['one', 'two', 'three'], 'length'); 157 => {3: ["one", "two"], 5: ["three"]} 158 159 indexBy_.indexBy(list, iteratee, [context]) 160 給定一個list,和 一個用來返回一個在列表中的每一個元素鍵 的iterator 函數(或屬性名), 返回一個每一項索引的對象。和groupBy很是像,可是當你知道你的鍵是惟一的時候可使用indexBy 。 161 162 var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 163 _.indexBy(stooges, 'age'); 164 => { 165 "40": {name: 'moe', age: 40}, 166 "50": {name: 'larry', age: 50}, 167 "60": {name: 'curly', age: 60} 168 } 169 170 countBy_.countBy(list, iteratee, [context]) 171 排序一個列表組成一個組,而且返回各組中的對象的數量的計數。相似groupBy,可是不是返回列表的值,而是返回在該組中值的數目。 172 173 _.countBy([1, 2, 3, 4, 5], function(num) { 174 return num % 2 == 0 ? 'even': 'odd'; 175 }); 176 => {odd: 3, even: 2} 177 178 shuffle_.shuffle(list) 179 返回一個隨機亂序的 list 副本, 使用 Fisher-Yates shuffle 來進行隨機亂序. 180 181 _.shuffle([1, 2, 3, 4, 5, 6]); 182 => [4, 1, 6, 3, 5, 2] 183 184 sample_.sample(list, [n]) 185 從 list中產生一個隨機樣本。傳遞一個數字表示從list中返回n個隨機元素。不然將返回一個單一的隨機項。 186 187 _.sample([1, 2, 3, 4, 5, 6]); 188 => 4 189 190 _.sample([1, 2, 3, 4, 5, 6], 3); 191 => [1, 6, 2] 192 193 toArray_.toArray(list) 194 把list(任何能夠迭代的對象)轉換成一個數組,在轉換 arguments 對象時很是有用。 195 196 (function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); 197 => [2, 3, 4] 198 199 size_.size(list) 200 返回list的長度。 201 202 _.size({one: 1, two: 2, three: 3}); 203 => 3 204 205 partition_.partition(array, predicate) 206 拆分一個數組(array)爲兩個數組: 第一個數組其元素都知足predicate迭代函數, 而第二個的全部元素均不能知足predicate迭代函數。 207 208 _.partition([0, 1, 2, 3, 4, 5], isOdd); 209 => [[1, 3, 5], [0, 2, 4]] 210 211 數組函數(Array Functions) 212 213 注: arguments(參數) 對象將在全部數組函數中工做 。然而, Underscore 函數的設計並不僅是針對稀疏("sparse" )數組的. 214 215 first_.first(array, [n]) 別名: head, take 216 返回array(數組)的第一個元素。傳遞 n參數將返回數組中從第一個元素開始的n個元素(注:返回數組中前 n 個元素.)。 217 218 _.first([5, 4, 3, 2, 1]); 219 => 5 220 221 initial_.initial(array, [n]) 222 返回數組中除了最後一個元素外的其餘所有元素。 在arguments對象上特別有用。傳遞 n參數將從結果中排除從最後一個開始的n個元素(注:排除數組後面的 n 個元素)。 223 224 _.initial([5, 4, 3, 2, 1]); 225 => [5, 4, 3, 2] 226 227 last_.last(array, [n]) 228 返回array(數組)的最後一個元素。傳遞 n參數將返回數組中從最後一個元素開始的n個元素(注:返回數組裏的後面的n個元素)。 229 230 _.last([5, 4, 3, 2, 1]); 231 => 1 232 233 rest_.rest(array, [index]) 別名: tail, drop 234 返回數組中除了第一個元素外的其餘所有元素。傳遞 index 參數將返回從index開始的剩餘全部元素 。(感謝@德德德德擼 指出錯誤) 235 236 _.rest([5, 4, 3, 2, 1]); 237 => [4, 3, 2, 1] 238 239 compact_.compact(array) 240 返回一個除去全部false值的 array副本。 在javascript中, false, null, 0, "", undefined 和 NaN 都是false值. 241 242 _.compact([0, 1, false, 2, '', 3]); 243 => [1, 2, 3] 244 245 flatten_.flatten(array, [shallow]) 246 將一個嵌套多層的數組 array(數組) (嵌套能夠是任何層數)轉換爲只有一層的數組。 若是你傳遞 shallow參數,數組將只減小一維的嵌套。 247 248 _.flatten([1, [2], [3, [[4]]]]); 249 => [1, 2, 3, 4]; 250 251 _.flatten([1, [2], [3, [[4]]]], true); 252 => [1, 2, 3, [[4]]]; 253 254 without_.without(array, *values) 255 返回一個刪除全部values值後的 array副本。(注:使用===表達式作相等測試。) 256 257 _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); 258 => [2, 3, 4] 259 260 union_.union(*arrays) 261 返回傳入的 arrays(數組)並集:按順序返回,返回數組的元素是惟一的,能夠傳入一個或多個 arrays(數組)。 262 263 _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); 264 => [1, 2, 3, 101, 10] 265 266 intersection_.intersection(*arrays) 267 返回傳入 arrays(數組)交集。結果中的每一個值是存在於傳入的每一個arrays(數組)裏。 268 269 _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); 270 => [1, 2] 271 272 difference_.difference(array, *others) 273 相似於without,但返回的值來自array參數數組,而且不存在於other 數組. 274 275 _.difference([1, 2, 3, 4, 5], [5, 2, 10]); 276 => [1, 3, 4] 277 278 uniq_.uniq(array, [isSorted], [iteratee]) 別名: unique 279 返回 array去重後的副本, 使用 === 作相等測試. 若是您肯定 array 已經排序, 那麼給 isSorted 參數傳遞 true值, 此函數將運行的更快的算法. 若是要處理對象元素, 傳參 iterator 來獲取要對比的屬性. 280 281 _.uniq([1, 2, 1, 3, 1, 4]); 282 => [1, 2, 3, 4] 283 284 zip_.zip(*arrays) 285 將 每一個arrays中相應位置的值合併在一塊兒。在合併分開保存的數據時頗有用. 若是你用來處理矩陣嵌套數組時, _.zip.apply 能夠作相似的效果。 286 287 _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); 288 => [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]] 289 290 _.zip.apply(_, arrayOfRowsOfData); 291 => arrayOfColumnsOfData 292 293 object_.object(list, [values]) 294 將數組轉換爲對象。傳遞任何一個單獨[key, value]對的列表,或者一個鍵的列表和一個值得列表。 若是存在重複鍵,最後一個值將被返回。 295 296 _.object(['moe', 'larry', 'curly'], [30, 40, 50]); 297 => {moe: 30, larry: 40, curly: 50} 298 299 _.object([['moe', 30], ['larry', 40], ['curly', 50]]); 300 => {moe: 30, larry: 40, curly: 50} 301 302 indexOf_.indexOf(array, value, [isSorted]) 303 返回value在該 array 中的索引值,若是value不存在 array中就返回-1。使用原生的indexOf 函數,除非它失效。若是您正在使用一個大數組,你知道數組已經排序,傳遞true給isSorted將更快的用二進制搜索..,或者,傳遞一個數字做爲第三個參數,爲了在給定的索引的數組中尋找第一個匹配值。 304 305 _.indexOf([1, 2, 3], 2); 306 => 1 307 308 lastIndexOf_.lastIndexOf(array, value, [fromIndex]) 309 返回value在該 array 中的從最後開始的索引值,若是value不存在 array中就返回-1。若是支持原生的lastIndexOf,將使用原生的lastIndexOf函數。 傳遞fromIndex將從你給定的索性值開始搜索。 310 311 _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); 312 => 4 313 314 sortedIndex_.sortedIndex(list, value, [iteratee], [context]) 315 使用二分查找肯定value在list中的位置序號,value按此序號插入能保持list原有的排序。 若是提供iterator函數,iterator將做爲list排序的依據,包括你傳遞的value 。 iterator也能夠是字符串的屬性名用來排序(好比length)。 316 317 _.sortedIndex([10, 20, 30, 40, 50], 35); 318 => 3 319 320 var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}]; 321 _.sortedIndex(stooges, {name: 'larry', age: 50}, 'age'); 322 => 1 323 324 range_.range([start], stop, [step]) 325 一個用來建立整數靈活編號的列表的函數,便於each 和 map循環。若是省略start則默認爲 0;step 默認爲 1.返回一個從start 到stop的整數的列表,用step來增長 (或減小)獨佔。值得注意的是,若是stop值在start前面(也就是stop值小於start值),那麼值域會被認爲是零長度,而不是負增加。-若是你要一個負數的值域 ,請使用負數step. 326 327 _.range(10); 328 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 329 _.range(1, 11); 330 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 331 _.range(0, 30, 5); 332 => [0, 5, 10, 15, 20, 25] 333 _.range(0, -10, -1); 334 => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] 335 _.range(0); 336 => [] 337 338 與函數有關的函數(Function (uh, ahem) Functions) 339 340 bind_.bind(function, object, *arguments) 341 綁定函數 function 到對象 object 上, 也就是不管什麼時候調用函數, 函數裏的 this 都指向這個 object. 任意可選參數 arguments 能夠傳遞給函數 function , 能夠填充函數所須要的參數, 這也被稱爲 partial application。對於沒有結合上下文的partial application綁定,請使用partial。 342 (注:partial application翻譯成「部分應用」或者「偏函數應用」。partial application能夠被描述爲一個函數,它接受必定數目的參數,綁定值到一個或多個這些參數,並返回一個新的函數,這個返回函數只接受剩餘未綁定值的參數。參見:http://en.wikipedia.org/wiki/Partial_application。感謝@一任風月憶秋年的建議)。 343 344 var func = function(greeting){ return greeting + ': ' + this.name }; 345 func = _.bind(func, {name: 'moe'}, 'hi'); 346 func(); 347 => 'hi: moe' 348 349 bindAll_.bindAll(object, *methodNames) 350 把methodNames參數指定的一些方法綁定到object上,這些方法就會在對象的上下文環境中執行。綁定函數用做事件處理函數時很是便利,不然函數被調用時this一點用也沒有。methodNames參數是必須的。 351 352 var buttonView = { 353 label : 'underscore', 354 onClick: function(){ alert('clicked: ' + this.label); }, 355 onHover: function(){ console.log('hovering: ' + this.label); } 356 }; 357 _.bindAll(buttonView, 'onClick', 'onHover'); 358 // When the button is clicked, this.label will have the correct value. 359 jQuery('#underscore_button').bind('click', buttonView.onClick); 360 361 partial_.partial(function, *arguments) 362 局部應用一個函數填充在任意個數的 參數,不改變其動態this值。和bind方法很相近。你能夠在你的參數列表中傳遞_來指定一個參數 ,不該該被預先填充, but left open to supply at call-time. You may pass _ in your list of arguments to specify an argument that should not be pre-filled, but left open to supply at call-time.(翻譯很差,求好的翻譯) 363 364 var add = function(a, b) { return a + b; }; 365 add5 = _.partial(add, 5); 366 add5(10); 367 => 15 368 369 memoize_.memoize(function, [hashFunction]) 370 Memoizes方法能夠緩存某函數的計算結果。對於耗時較長的計算是頗有幫助的。若是傳遞了 hashFunction 參數,就用 hashFunction 的返回值做爲key存儲函數的計算結果。 hashFunction 默認使用function的第一個參數做爲key。memoized值的緩存 可做爲 返回函數的cache屬性。 371 372 var fibonacci = _.memoize(function(n) { 373 return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2); 374 }); 375 376 delay_.delay(function, wait, *arguments) 377 相似setTimeout,等待wait毫秒後調用function。若是傳遞可選的參數arguments,當函數function執行時, arguments 會做爲參數傳入。 378 379 var log = _.bind(console.log, console); 380 _.delay(log, 1000, 'logged later'); 381 => 'logged later' // Appears after one second. 382 383 defer_.defer(function, *arguments) 384 延遲調用function直到當前調用棧清空爲止,相似使用延時爲0的setTimeout方法。對於執行開銷大的計算和無阻塞UI線程的HTML渲染時候很是有用。 若是傳遞arguments參數,當函數function執行時, arguments 會做爲參數傳入。 385 386 _.defer(function(){ alert('deferred'); }); 387 // Returns from the function before the alert runs. 388 389 throttle_.throttle(function, wait, [options]) 390 建立並返回一個像節流閥同樣的函數,當重複調用函數的時候,最多每隔 wait毫秒調用一次該函數。對於想控制一些觸發頻率較高的事件有幫助。(注:詳見:javascript函數的throttle和debounce) 391 392 默認狀況下,throttle將在你調用的第一時間儘快執行這個function,而且,若是你在wait週期內調用任意次數的函數,都將盡快的被覆蓋。若是你想禁用第一次首先執行的話,傳遞{leading: false},還有若是你想禁用最後一次執行的話,傳遞{trailing: false}。 393 394 var throttled = _.throttle(updatePosition, 100); 395 $(window).scroll(throttled); 396 397 debounce_.debounce(function, wait, [immediate]) 398 返回 function 函數的防反跳版本, 將延遲函數的執行(真正的執行)在函數最後一次調用時刻的 wait 毫秒以後. 對於必須在一些輸入(可能是一些用戶操做)中止到達以後執行的行爲有幫助。 例如: 渲染一個Markdown格式的評論預覽, 當窗口中止改變大小以後從新計算佈局, 等等. 399 400 傳參 immediate 爲 true, debounce會在 wait 時間間隔的開始調用這個函數 。(注:而且在 waite 的時間以內,不會再次調用。)在相似不當心點了提交按鈕兩下而提交了兩次的狀況下頗有用。 (感謝 @ProgramKid 的翻譯建議) 401 402 var lazyLayout = _.debounce(calculateLayout, 300); 403 $(window).resize(lazyLayout); 404 405 once_.once(function) 406 建立一個只能調用一次的函數。重複調用改進的方法也沒有效果,只會返回第一次執行時的結果。 做爲初始化函數使用時很是有用, 不用再設一個boolean值來檢查是否已經初始化完成. 407 408 var initialize = _.once(createApplication); 409 initialize(); 410 initialize(); 411 // Application is only created once. 412 413 after_.after(count, function) 414 建立一個函數, 只有在運行了 count 次以後纔有效果. 在處理同組異步請求返回結果時, 若是你要確保同組裏全部異步請求完成以後才 執行這個函數, 這將很是有用。 415 416 var renderNotes = _.after(notes.length, render); 417 _.each(notes, function(note) { 418 note.asyncSave({success: renderNotes}); 419 }); 420 // renderNotes is run once, after all notes have saved. 421 422 before_.before(count, function) 423 建立一個函數,調用不超過count 次。 當count已經達到時,最後一個函數調用的結果 是被記住並返回 。 424 425 var monthlyMeeting = _.before(3, askForRaise); 426 monthlyMeeting(); 427 monthlyMeeting(); 428 monthlyMeeting(); 429 // the result of any subsequent calls is the same as the second call 430 431 wrap_.wrap(function, wrapper) 432 將第一個函數 function 封裝到函數 wrapper 裏面, 並把函數 function 做爲第一個參數傳給 wrapper. 這樣可讓 wrapper 在 function 運行以前和以後 執行代碼, 調整參數而後附有條件地執行. 433 434 var hello = function(name) { return "hello: " + name; }; 435 hello = _.wrap(hello, function(func) { 436 return "before, " + func("moe") + ", after"; 437 }); 438 hello(); 439 => 'before, hello: moe, after' 440 441 negate_.negate(predicate) 442 返回一個新的predicate函數的否認版本。 443 444 var isFalsy = _.negate(Boolean); 445 _.find([-2, -1, 0, 1, 2], isFalsy); 446 => 0 447 448 compose_.compose(*functions) 449 返回函數集 functions 組合後的複合函數, 也就是一個函數執行完以後把返回的結果再做爲參數賦給下一個函數來執行. 以此類推. 在數學裏, 把函數 f(), g(), 和 h() 組合起來能夠獲得複合函數 f(g(h()))。 450 451 var greet = function(name){ return "hi: " + name; }; 452 var exclaim = function(statement){ return statement.toUpperCase() + "!"; }; 453 var welcome = _.compose(greet, exclaim); 454 welcome('moe'); 455 => 'hi: MOE!' 456 457 對象函數(Object Functions) 458 459 keys_.keys(object) 460 獲取object對象全部的屬性名稱。 461 462 _.keys({one: 1, two: 2, three: 3}); 463 => ["one", "two", "three"] 464 465 values_.values(object) 466 返回object對象全部的屬性值。 467 468 _.values({one: 1, two: 2, three: 3}); 469 => [1, 2, 3] 470 471 pairs_.pairs(object) 472 把一個對象轉變爲一個[key, value]形式的數組。 473 474 _.pairs({one: 1, two: 2, three: 3}); 475 => [["one", 1], ["two", 2], ["three", 3]] 476 477 invert_.invert(object) 478 返回一個object副本,使其鍵(keys)和值(values)對換。對於這個操做,必須確保object裏全部的值都是惟一的且能夠序列號成字符串. 479 480 _.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"}); 481 => {Moses: "Moe", Louis: "Larry", Jerome: "Curly"}; 482 483 functions_.functions(object) 別名: methods 484 返回一個對象裏全部的方法名, 並且是已經排序的 — 也就是說, 對象裏每一個方法(屬性值是一個函數)的名稱. 485 486 _.functions(_); 487 => ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ... 488 489 extend_.extend(destination, *sources) 490 複製source對象中的全部屬性覆蓋到destination對象上,而且返回 destination 對象. 複製是按順序的, 因此後面的對象屬性會把前面的對象屬性覆蓋掉(若是有重複). 491 492 _.extend({name: 'moe'}, {age: 50}); 493 => {name: 'moe', age: 50} 494 495 pick_.pick(object, *keys) 496 返回一個object副本,只過濾出keys(有效的鍵組成的數組)參數指定的屬性值。或者接受一個判斷函數,指定挑選哪一個key。 497 498 _.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age'); 499 => {name: 'moe', age: 50} 500 _.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) { 501 return _.isNumber(value); 502 }); 503 => {age: 50} 504 505 omit_.omit(object, *keys) 506 返回一個object副本,只過濾出除去keys(有效的鍵組成的數組)參數指定的屬性值。 或者接受一個判斷函數,指定忽略哪一個key。 507 508 _.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid'); 509 => {name: 'moe', age: 50} 510 _.omit({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) { 511 return _.isNumber(value); 512 }); 513 => {name: 'moe', userid: 'moe1'} 514 515 defaults_.defaults(object, *defaults) 516 用defaults對象填充object 中的undefined屬性。 而且返回這個object。一旦這個屬性被填充,再使用defaults方法將不會有任何效果。(感謝@一任風月憶秋年的拍磚) 517 518 var iceCream = {flavor: "chocolate"}; 519 _.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"}); 520 => {flavor: "chocolate", sprinkles: "lots"} 521 522 clone_.clone(object) 523 建立 一個淺複製(淺拷貝)的克隆object。任何嵌套的對象或數組都經過引用拷貝,不會複製。 524 525 _.clone({name: 'moe'}); 526 => {name: 'moe'}; 527 528 tap_.tap(object, interceptor) 529 用 object做爲參數來調用函數interceptor,而後返回object。這種方法的主要意圖是做爲函數鏈式調用 的一環, 爲了對此對象執行操做並返回對象自己。 530 531 _.chain([1,2,3,200]) 532 .filter(function(num) { return num % 2 == 0; }) 533 .tap(alert) 534 .map(function(num) { return num * num }) 535 .value(); 536 => // [2, 200] (alerted) 537 => [4, 40000] 538 539 has_.has(object, key) 540 對象是否包含給定的鍵嗎?等同於object.hasOwnProperty(key),可是使用hasOwnProperty 函數的一個安全引用,以防意外覆蓋。 541 542 _.has({a: 1, b: 2, c: 3}, "b"); 543 => true 544 545 property_.property(key) 546 返回一個函數,這個函數返回任何傳入的對象的key 屬性。 547 548 var moe = {name: 'moe'}; 549 'moe' === _.property('name')(moe); 550 => true 551 552 matches_.matches(attrs) 553 返回一個斷言函數,這個函數會給你一個斷言 能夠用來辨別 給定的對象是否匹配attrs指定鍵/值屬性。 554 555 var ready = _.matches({selected: true, visible: true}); 556 var readyToGoList = _.filter(list, ready); 557 558 isEqual_.isEqual(object, other) 559 執行兩個對象之間的優化深度比較,肯定他們是否應被視爲相等。 560 561 var moe = {name: 'moe', luckyNumbers: [13, 27, 34]}; 562 var clone = {name: 'moe', luckyNumbers: [13, 27, 34]}; 563 moe == clone; 564 => false 565 _.isEqual(moe, clone); 566 => true 567 568 isEmpty_.isEmpty(object) 569 若是object 不包含任何值(沒有可枚舉的屬性),返回true。 對於字符串和類數組(array-like)對象,若是length屬性爲0,那麼_.isEmpty檢查返回true。 570 571 _.isEmpty([1, 2, 3]); 572 => false 573 _.isEmpty({}); 574 => true 575 576 isElement_.isElement(object) 577 若是object是一個DOM元素,返回true。 578 579 _.isElement(jQuery('body')[0]); 580 => true 581 582 isArray_.isArray(object) 583 若是object是一個數組,返回true。 584 585 (function(){ return _.isArray(arguments); })(); 586 => false 587 _.isArray([1,2,3]); 588 => true 589 590 isObject_.isObject(value) 591 若是object是一個對象,返回true。須要注意的是JavaScript數組和函數是對象,字符串和數字不是。 592 593 _.isObject({}); 594 => true 595 _.isObject(1); 596 => false 597 598 isArguments_.isArguments(object) 599 若是object是一個參數對象,返回true。 600 601 (function(){ return _.isArguments(arguments); })(1, 2, 3); 602 => true 603 _.isArguments([1,2,3]); 604 => false 605 606 isFunction_.isFunction(object) 607 若是object是一個函數(Function),返回true。 608 609 _.isFunction(alert); 610 => true 611 612 isString_.isString(object) 613 若是object是一個字符串,返回true。 614 615 _.isString("moe"); 616 => true 617 618 isNumber_.isNumber(object) 619 若是object是一個數值,返回true (包括 NaN)。 620 621 _.isNumber(8.4 * 5); 622 => true 623 624 isFinite_.isFinite(object) 625 若是object是一個有限的數字,返回true。 626 627 _.isFinite(-101); 628 => true 629 630 _.isFinite(-Infinity); 631 => false 632 633 isBoolean_.isBoolean(object) 634 若是object是一個布爾值,返回true。 Returns true if object is either true or false. 635 636 _.isBoolean(null); 637 => false 638 639 isDate_.isDate(object) 640 若是object是一個Date類型(日期時間),返回true。 641 642 _.isDate(new Date()); 643 => true 644 645 isRegExp_.isRegExp(object) 646 若是object是一個正則表達式,返回true。 647 648 _.isRegExp(/moe/); 649 => true 650 651 isNaN_.isNaN(object) 652 若是object是 NaN,返回true。 653 注意: 這和原生的isNaN 函數不同,若是變量是undefined,原生的isNaN 函數也會返回 true 。 654 655 _.isNaN(NaN); 656 => true 657 isNaN(undefined); 658 => true 659 _.isNaN(undefined); 660 => false 661 662 isNull_.isNull(object) 663 若是object的值是 null,返回true。 664 665 _.isNull(null); 666 => true 667 _.isNull(undefined); 668 => false 669 670 isUndefined_.isUndefined(value) 671 若是value是undefined,返回true。 672 673 _.isUndefined(window.missingVariable); 674 => true 675 676 實用功能(Utility Functions) 677 678 noConflict_.noConflict() 679 放棄Underscore 的控制變量"_"。返回Underscore 對象的引用。 680 681 var underscore = _.noConflict(); 682 683 identity_.identity(value) 684 返回與傳入參數相等的值. 至關於數學裏的: f(x) = x 685 這個函數看似無用, 可是在Underscore裏被用做默認的迭代器iterator. 686 687 var moe = {name: 'moe'}; 688 moe === _.identity(moe); 689 => true 690 691 constant_.constant(value) 692 建立一個函數,這個函數 返回相同的值 用來做爲_.constant的參數。 693 694 var moe = {name: 'moe'}; 695 moe === _.constant(moe)(); 696 => true 697 698 noop_.noop() 699 返回undefined,不論傳遞給它的是什麼參數。 能夠用做默承認選的回調參數。 700 701 obj.initialize = _.noop; 702 703 times_.times(n, iteratee, [context]) 704 調用給定的迭代函數n次,每一次調用iteratee傳遞index參數。生成一個返回值的數組。 705 注意: 本例使用 鏈式語法。 706 707 _(3).times(function(n){ genie.grantWishNumber(n); }); 708 709 random_.random(min, max) 710 返回一個min 和 max之間的隨機整數。若是你只傳遞一個參數,那麼將返回0和這個參數之間的整數。 711 712 _.random(0, 100); 713 => 42 714 715 mixin_.mixin(object) 716 容許用您本身的實用程序函數擴展Underscore。傳遞一個 {name: function}定義的哈希添加到Underscore對象,以及面向對象封裝。 717 718 _.mixin({ 719 capitalize: function(string) { 720 return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase(); 721 } 722 }); 723 _("fabio").capitalize(); 724 => "Fabio" 725 726 iteratee_.iteratee(value, [context], [argCount]) 727 一個重要的內部函數用來生成可應用到集合中每一個元素的回調, 返回想要的結果 - 不管是等式,任意回調,屬性匹配,或屬性訪問。 728 經過_.iteratee轉換判斷的Underscore 方法的完整列表是 map, find, filter, reject, every, some, max, min, sortBy, groupBy, indexBy, countBy, sortedIndex, partition, 和 unique. 729 730 var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; 731 _.map(stooges, _.iteratee('age')); 732 => [25, 21, 23]; 733 734 uniqueId_.uniqueId([prefix]) 735 爲須要的客戶端模型或DOM元素生成一個全局惟一的id。若是prefix參數存在, id 將附加給它。 736 737 _.uniqueId('contact_'); 738 => 'contact_104' 739 740 escape_.escape(string) 741 轉義HTML字符串,替換&, <, >, ", ', 和 /字符。 742 743 _.escape('Curly, Larry & Moe'); 744 => "Curly, Larry & Moe" 745 746 unescape_.unescape(string) 747 和escape相反。轉義HTML字符串,替換&, <, >, ", `, 和 /字符。 748 749 _.unescape('Curly, Larry & Moe'); 750 => "Curly, Larry & Moe" 751 752 result_.result(object, property) 753 若是對象 object 中的屬性 property 是函數, 則調用它, 不然, 返回它。 754 755 var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }}; 756 _.result(object, 'cheese'); 757 => "crumpets" 758 _.result(object, 'stuff'); 759 => "nonsense" 760 761 now_.now() 762 一個優化的方式來得到一個當前時間的整數時間戳。 可用於實現定時/動畫功能。 763 764 _.now(); 765 => 1392066795351 766 767 template_.template(templateString, [settings]) 768 將 JavaScript 模板編譯爲能夠用於頁面呈現的函數, 對於經過JSON數據源生成複雜的HTML並呈現出來的操做很是有用。 模板函數可使用 <%= … %>插入變量, 也能夠用<% … %>執行任意的 JavaScript 代碼。 若是您但願插入一個值, 並讓其進行HTML轉義,請使用<%- … %>。 當你要給模板函數賦值的時候,能夠傳遞一個含有與模板對應屬性的data對象 。 若是您要寫一個一次性的, 您能夠傳對象 data 做爲第二個參數給模板 template 來直接呈現, 這樣頁面會當即呈現而不是返回一個模板函數. 參數 settings 是一個哈希表包含任何能夠覆蓋的設置 _.templateSettings. 769 770 var compiled = _.template("hello: <%= name %>"); 771 compiled({name: 'moe'}); 772 => "hello: moe" 773 774 var template = _.template("<b><%- value %></b>"); 775 template({value: '<script>'}); 776 => "<b><script></b>" 777 778 您也能夠在JavaScript代碼中使用 print. 有時候這會比使用 <%= ... %> 更方便. 779 780 var compiled = _.template("<% print('Hello ' + epithet); %>"); 781 compiled({epithet: "stooge"}); 782 => "Hello stooge" 783 784 若是ERB式的分隔符您不喜歡, 您能夠改變Underscore的模板設置, 使用別的符號來嵌入代碼. 定義一個 interpolate 正則表達式來逐字匹配 嵌入代碼的語句, 若是想插入轉義後的HTML代碼 則須要定義一個 escape 正則表達式來匹配, 還有一個 evaluate 正則表達式來匹配 您想要直接一次性執行程序而不須要任何返回值的語句. 您能夠定義或省略這三個的任意一個. 例如, 要執行 Mustache.js 類型的模板: 785 786 _.templateSettings = { 787 interpolate: /\{\{(.+?)\}\}/g 788 }; 789 790 var template = _.template("Hello {{ name }}!"); 791 template({name: "Mustache"}); 792 => "Hello Mustache!" 793 794 默認的, template 經過 with 語句 來取得 data 全部的值. 固然, 您也能夠在 variable 設置裏指定一個變量名. 這樣能顯著提高模板的渲染速度. 795 796 _.template("Using 'with': <%= data.answer %>", {variable: 'data'})({answer: 'no'}); 797 => "Using 'with': no" 798 799 預編譯模板對調試不可重現的錯誤頗有幫助. 這是由於預編譯的模板能夠提供錯誤的代碼行號和堆棧跟蹤, 有些模板在客戶端(瀏覽器)上是不能經過編譯的 在編譯好的模板函數上, 有 source 屬性能夠提供簡單的預編譯功能. 800 801 <script> 802 JST.project = <%= _.template(jstText).source %>; 803 </script> 804 805 鏈式語法(Chaining) 806 807 您能夠在面向對象或者函數的風格下使用Underscore, 這取決於您的我的偏好. 如下兩行代碼均可以 把一個數組裏的全部數字乘以2. 808 809 _.map([1, 2, 3], function(n){ return n * 2; }); 810 _([1, 2, 3]).map(function(n){ return n * 2; }); 811 812 對一個對象使用 chain 方法, 會把這個對象封裝並 讓之後每次方法的調用結束後都返回這個封裝的對象, 當您完成了計算, 可使用 value 函數來取得最終的值. 如下是一個同時使用了 map/flatten/reduce 的鏈式語法例子, 目的是計算一首歌的歌詞裏每個單詞出現的次數. 813 814 var lyrics = [ 815 {line: 1, words: "I'm a lumberjack and I'm okay"}, 816 {line: 2, words: "I sleep all night and I work all day"}, 817 {line: 3, words: "He's a lumberjack and he's okay"}, 818 {line: 4, words: "He sleeps all night and he works all day"} 819 ]; 820 821 _.chain(lyrics) 822 .map(function(line) { return line.words.split(' '); }) 823 .flatten() 824 .reduce(function(counts, word) { 825 counts[word] = (counts[word] || 0) + 1; 826 return counts; 827 }, {}) 828 .value(); 829 830 => {lumberjack: 2, all: 4, night: 2 ... } 831 832 此外, 數組原型方法 也經過代理加入到了鏈式封裝的Underscore對象, 因此您能夠 在鏈式語法中直接使用 reverse 或 push 方法, 而後再接着其餘的語句. 833 834 chain_.chain(obj) 835 返回一個封裝的對象. 在封裝的對象上調用方法會返回封裝的對象自己, 直道 value 方法調用爲止. 836 837 var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}]; 838 var youngest = _.chain(stooges) 839 .sortBy(function(stooge){ return stooge.age; }) 840 .map(function(stooge){ return stooge.name + ' is ' + stooge.age; }) 841 .first() 842 .value(); 843 => "moe is 21" 844 845 value_(obj).value() 846 獲取封裝對象的最終值. 847 848 _([1, 2, 3]).value(); 849 => [1, 2, 3]