Underscore

Underscore一個JavaScript實用庫,提供了一整套函數式編程的實用功能,可是沒有擴展任何JavaScript內置對象。它是這個問題的答案:「若是我在一個空白的HTML頁面前坐下, 並但願當即開始工做, 我須要什麼?「...它彌補了部分jQuery沒有實現的功能,同時又是Backbone.js必不可少的部分。 (感謝@小鄧子daj 的翻譯建議)javascript

Underscore提供了100多個函數,包括經常使用的: map, filter, invoke — 固然還有更多專業的輔助函數,如:函數綁定, JavaScript模板功能,建立快速索引, 強類型相等測試, 等等.css

爲了你能仔細研讀,這裏包含了一個完整的測試套件html

您也能夠經過註釋閱讀源代碼java

享受Underscore,並但願得到更多的使用功能(感謝@Jaward華仔 的翻譯建議),能夠嘗試使用Underscore-contrib(愚人碼頭注:Underscore-contrib是一個Underscore的代碼貢獻庫)。node

該項目代碼託管在GitHub上,你能夠經過issues頁、Freenode的 #documentcloud 頻道、發送tweets給@documentcloud三個途徑報告bug以及參與特性討論。jquery

Underscore是DocumentCloud的一個開源組件。 git

下載 (右鍵另存爲)

開發版 (1.8.2) 51kb, 未壓縮版, 含大量註釋
生產版 (1.8.2) 5.7kb, 最簡化並用Gzip壓縮  (Source Map)
 
不穩定版 未發佈版本, 當前開發中的 master 分支, 若是使用此版本, 風險自負

安裝(Installation)

  • Node.js npm install underscore
  • Meteor.js meteor add underscore
  • Require.js require(["underscore"], ...
  • Bower bower install underscore
  • Component component install jashkenas/underscore

集合函數 (數組 或對象)

each_.each(list, iteratee, [context]) Alias: forEach
遍歷list中的全部元素,按順序用遍歷輸出每一個元素。若是傳遞了context參數,則把iteratee綁定到context對象上。每次調用iteratee都會傳遞三個參數:(element, index, list)。若是list是個JavaScript對象,iteratee的參數是 (value, key, list))。返回list以方便鏈式調用。
github

_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...

注意:集合函數能在數組,對象,和類數組對象,好比arguments, NodeList和相似的數據類型上正常工做。 可是它經過鴨子類型工做,因此要避免傳遞一個不固定length屬性的對象(愚人碼頭注:對象或數組的長度(length)屬性要固定的)。每一個循環不能被破壞 - 打破, 使用_.find代替,這也是很好的注意。 正則表達式

map_.map(list, iteratee, [context]) Alias: collect
經過轉換函數(iteratee迭代器)映射列表中的每一個值產生價值的新數組。iteratee傳遞三個參數:value,而後是迭代 index(或 key 愚人碼頭注:若是list是個JavaScript對象是,這個參數就是key),最後一個是引用指向整個list
算法

_.map([1, 2, 3], function(num){ return num * 3; });
=> [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]
_.map([[1, 2], [3, 4]], _.first);
=> [1, 3]

reduce_.reduce(list, iteratee, [memo], [context]) Aliases: inject, foldl
別名爲 injectfoldl, reduce方法把list中元素歸結爲一個單獨的數值。Memo是reduce函數的初始值,reduce的每一步都須要由iteratee返回。這個迭代傳遞4個參數:memo,value 和 迭代的index(或者 key)和最後一個引用的整個 list

若是沒有memo傳遞給reduce的初始調用,iteratee不會被列表中的第一個元素調用。第一個元素將取代 傳遞給列表中下一個元素調用iterateememo參數。

var sum = _.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
=> 6

reduceRight_.reduceRight(list, iteratee, memo, [context]) Alias: foldr
reducRight是從右側開始組合的元素的reduce函數,若是存在JavaScript 1.8版本的reduceRight,則用其代替。Foldr在javascript中不像其它有懶計算的語言那麼有用(愚人碼頭注:lazy evaluation:一種求值策略,只有當表達式的值真正須要時纔對表達式進行計算)。

var list = [[0, 1], [2, 3], [4, 5]];
var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
=> [4, 5, 2, 3, 0, 1]

find_.find(list, predicate, [context]) Alias: detect
list中逐項查找,返回第一個經過predicate迭代函數真值檢測的元素值,若是沒有值傳遞給測試迭代器將返回undefined。 若是找到匹配的元素,函數將當即返回,不會遍歷整個list。

var even = _.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> 2

filter_.filter(list, predicate, [context]) Alias: select
遍歷list中的每一個值,返回包含全部經過predicate真值檢測的元素值。(愚人碼頭注:若是存在原生filter方法,則用原生的filter方法。)

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]

where_.where(list, properties)
遍歷list中的每個值,返回一個數組,這個數組包含properties所列出的屬性的全部的 鍵 - 值對。

_.where(listOfPlays, {author: "Shakespeare", year: 1611});
=> [{title: "Cymbeline", author: "Shakespeare", year: 1611},
    {title: "The Tempest", author: "Shakespeare", year: 1611}]

findWhere_.findWhere(list, properties)
遍歷整個list,返回匹配 properties參數所列出的全部 鍵 - 值 對的第一個值。

若是沒有找到匹配的屬性,或者list是空的,那麼將返回undefined

_.findWhere(publicServicePulitzers, {newsroom: "The New York Times"});
=> {year: 1918, newsroom: "The New York Times",
  reason: "For its public service in publishing in full so many official reports,
  documents and speeches by European statesmen relating to the progress and
  conduct of the war."}

reject_.reject(list, predicate, [context])
返回list中沒有經過predicate真值檢測的元素集合,與filter相反。

var odds = _.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [1, 3, 5]

every_.every(list, [predicate], [context]) Alias: all
若是list中的全部元素都經過predicate的真值檢測就返回true。(愚人碼頭注:若是存在原生的every方法,就使用原生的every。)

_.every([true, 1, null, 'yes'], _.identity);
=> false

some_.some(list, [predicate], [context]) Alias: any
若是list中有任何一個元素經過 predicate 的真值檢測就返回true。一旦找到了符合條件的元素, 就直接中斷對list的遍歷. (愚人碼頭注:若是存在原生的some方法,就使用原生的some。)

_.some([null, 0, 'yes', false]);
=> true

contains_.contains(list, value, [fromIndex]) Alias: includes
若是list包含指定的value則返回true(愚人碼頭注:使用===檢測)。若是list 是數組,內部使用indexOf判斷。使用fromIndex來給定開始檢索的索引位置。

_.contains([1, 2, 3], 3);
=> true

invoke_.invoke(list, methodName, *arguments)
list的每一個元素上執行methodName方法。 任何傳遞給invoke的額外參數,invoke都會在調用methodName方法的時候傳遞給它。

_.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
=> [[1, 5, 7], [1, 2, 3]]

pluck_.pluck(list, propertyName)
pluck也許是map最常使用的用例模型的簡化版本,即萃取數組對象中某屬性值,返回一個數組。

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.pluck(stooges, 'name');
=> ["moe", "larry", "curly"]

max_.max(list, [iteratee], [context])
返回list中的最大值。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。若是list爲空,將返回-Infinity,因此你可能須要事先用isEmpty檢查 list

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.max(stooges, function(stooge){ return stooge.age; });
=> {name: 'curly', age: 60};

min_.min(list, [iteratee], [context])
返回list中的最小值。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。若是list爲空,將返回-Infinity,因此你可能須要事先用isEmpty檢查 list

var numbers = [10, 5, 100, 2, 1000];
_.min(numbers);
=> 2

sortBy_.sortBy(list, iteratee, [context])
返回一個排序後的list拷貝副本。若是傳遞iteratee參數,iteratee將做爲list中每一個值的排序依據。迭代器也能夠是字符串的屬性的名稱進行排序的(好比 length)。

_.sortBy([1, 2, 3, 4, 5, 6], function(num){ return Math.sin(num); });
=> [5, 4, 6, 3, 1, 2]

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.sortBy(stooges, 'name');
=> [{name: 'curly', age: 60}, {name: 'larry', age: 50}, {name: 'moe', age: 40}];

groupBy_.groupBy(list, iteratee, [context])
把一個集合分組爲多個集合,經過 iterator 返回的結果進行分組. 若是 iterator 是一個字符串而不是函數, 那麼將使用 iterator 做爲各元素的屬性名來對比進行分組.

_.groupBy([1.3, 2.1, 2.4], function(num){ return Math.floor(num); });
=> {1: [1.3], 2: [2.1, 2.4]}

_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}

indexBy_.indexBy(list, iteratee, [context])
給定一個list,和 一個用來返回一個在列表中的每一個元素鍵 的iterator 函數(或屬性名), 返回一個每一項索引的對象。和groupBy很是像,可是當你知道你的鍵是惟一的時候可使用indexBy

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.indexBy(stooges, 'age');
=> {
  "40": {name: 'moe', age: 40},
  "50": {name: 'larry', age: 50},
  "60": {name: 'curly', age: 60}
}

countBy_.countBy(list, iteratee, [context])
排序一個列表組成一個組,而且返回各組中的對象的數量的計數。相似groupBy,可是不是返回列表的值,而是返回在該組中值的數目。

_.countBy([1, 2, 3, 4, 5], function(num) {
  return num % 2 == 0 ? 'even': 'odd';
});
=> {odd: 3, even: 2}

shuffle_.shuffle(list)
返回一個隨機亂序的 list 副本, 使用 Fisher-Yates shuffle 來進行隨機亂序.

_.shuffle([1, 2, 3, 4, 5, 6]);
=> [4, 1, 6, 3, 5, 2]

sample_.sample(list, [n])
list中產生一個隨機樣本。傳遞一個數字表示從list中返回n個隨機元素。不然將返回一個單一的隨機項。

_.sample([1, 2, 3, 4, 5, 6]);
=> 4

_.sample([1, 2, 3, 4, 5, 6], 3);
=> [1, 6, 2]

toArray_.toArray(list)
list(任何能夠迭代的對象)轉換成一個數組,在轉換 arguments 對象時很是有用。

(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
=> [2, 3, 4]

size_.size(list)
返回list的長度。

_.size({one: 1, two: 2, three: 3});
=> 3

partition_.partition(array, predicate)
拆分一個數組(array)爲兩個數組:  第一個數組其元素都知足predicate迭代函數, 而第二個的全部元素均不能知足predicate迭代函數。

_.partition([0, 1, 2, 3, 4, 5], isOdd);
=> [[1, 3, 5], [0, 2, 4]]

數組函數(Array Functions)

注: arguments(參數) 對象將在全部數組函數中工做 。然而, Underscore 函數的設計並不僅是針對稀疏("sparse" )數組的.

first_.first(array, [n]) Alias: head, take
返回array(數組)的第一個元素。傳遞 n參數將返回數組中從第一個元素開始的n個元素(愚人碼頭注:返回數組中前 n 個元素.)。

_.first([5, 4, 3, 2, 1]);
=> 5

initial_.initial(array, [n])
返回數組中除了最後一個元素外的其餘所有元素。 在arguments對象上特別有用。傳遞 n參數將從結果中排除從最後一個開始的n個元素(愚人碼頭注:排除數組後面的 n 個元素)。

_.initial([5, 4, 3, 2, 1]);
=> [5, 4, 3, 2]

last_.last(array, [n])
返回array(數組)的最後一個元素。傳遞 n參數將返回數組中從最後一個元素開始的n個元素(愚人碼頭注:返回數組裏的後面的n個元素)。

_.last([5, 4, 3, 2, 1]);
=> 1

rest_.rest(array, [index]) Alias: tail, drop
返回數組中除了第一個元素外的其餘所有元素。傳遞 index 參數將返回從index開始的剩餘全部元素 。(感謝@德德德德擼 指出錯誤)

_.rest([5, 4, 3, 2, 1]);
=> [4, 3, 2, 1]

compact_.compact(array)
返回一個除去全部false值的 array副本。 在javascript中, false, null, 0, "", undefinedNaN 都是false值.

_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]

flatten_.flatten(array, [shallow])
將一個嵌套多層的數組 array(數組) (嵌套能夠是任何層數)轉換爲只有一層的數組。 若是你傳遞 shallow參數,數組將只減小一維的嵌套。

_.flatten([1, [2], [3, [[4]]]]);
=> [1, 2, 3, 4];

_.flatten([1, [2], [3, [[4]]]], true);
=> [1, 2, 3, [[4]]];

without_.without(array, *values)
返回一個刪除全部values值後的 array副本。(愚人碼頭注:使用===表達式作相等測試。)

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
=> [2, 3, 4]

union_.union(*arrays)
返回傳入的 arrays(數組)並集:按順序返回,返回數組的元素是惟一的,能夠傳入一個或多個 arrays(數組)

_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2, 3, 101, 10]

intersection_.intersection(*arrays)
返回傳入 arrays(數組)交集。結果中的每一個值是存在於傳入的每一個arrays(數組)裏。

_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]

difference_.difference(array, *others)
相似於without,但返回的值來自array參數數組,而且不存在於other 數組.

_.difference([1, 2, 3, 4, 5], [5, 2, 10]);
=> [1, 3, 4]

uniq_.uniq(array, [isSorted], [iteratee]) Alias: unique
返回 array去重後的副本, 使用 === 作相等測試. 若是您肯定 array 已經排序, 那麼給 isSorted 參數傳遞 true值, 此函數將運行的更快的算法. 若是要處理對象元素, 傳遞 iteratee函數來獲取要對比的屬性.

_.uniq([1, 2, 1, 3, 1, 4]);
=> [1, 2, 3, 4]

zip_.zip(*arrays)
將 每一個arrays中相應位置的值合併在一塊兒。在合併分開保存的數據時頗有用. 若是你用來處理矩陣嵌套數組時, _.zip.apply 能夠作相似的效果。

_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
=> [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

unzip_.unzip(*arrays)
zip功能相反的函數,給定若干arrays,返回一串聯的新數組,其第一元素個包含全部的輸入數組的第一元素,其第二包含了全部的第二元素,依此類推。經過apply用於傳遞數組的數組。 (感謝 @周文彬1986@未定的終點 指出示例錯誤)

_.unzip([['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]])
=> ["moe", 30, true], ["larry", 40, false], ["curly", 50, false]

object_.object(list, [values])
將數組轉換爲對象。傳遞任何一個單獨[key, value]對的列表,或者一個鍵的列表和一個值得列表。 若是存在重複鍵,最後一個值將被返回。

_.object(['moe', 'larry', 'curly'], [30, 40, 50]);
=> {moe: 30, larry: 40, curly: 50}

_.object([['moe', 30], ['larry', 40], ['curly', 50]]);
=> {moe: 30, larry: 40, curly: 50}

indexOf_.indexOf(array, value, [isSorted])
返回value在該 array 中的索引值,若是value不存在 array中就返回-1。使用原生的indexOf 函數,除非它失效。若是您正在使用一個大數組,你知道數組已經排序,傳遞trueisSorted將更快的用二進制搜索..,或者,傳遞一個數字做爲第三個參數,爲了在給定的索引的數組中尋找第一個匹配值。

_.indexOf([1, 2, 3], 2);
=> 1

lastIndexOf_.lastIndexOf(array, value, [fromIndex])
返回value在該 array 中的從最後開始的索引值,若是value不存在 array中就返回-1。若是支持原生的lastIndexOf,將使用原生的lastIndexOf函數。傳遞fromIndex將從你給定的索性值開始搜索。

_.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
=> 4

sortedIndex_.sortedIndex(list, value, [iteratee], [context])
使用二分查找肯定valuelist中的位置序號,value按此序號插入能保持list原有的排序。若是提供iterator函數,iterator將做爲list排序的依據,包括你傳遞的valueiterator也能夠是字符串的屬性名用來排序(好比length)。

_.sortedIndex([10, 20, 30, 40, 50], 35);
=> 3

var stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}];
_.sortedIndex(stooges, {name: 'larry', age: 50}, 'age');
=> 1

findIndex_.findIndex(array, predicate, [context])
相似於_.indexOf,當predicate經過真檢查時,返回第一個索引值;不然返回-1

_.findIndex([4, 6, 8, 12], isPrime);
=> -1 // not found
_.findIndex([4, 6, 7, 12], isPrime);
=> 2

findLastIndex_.findLastIndex(array, predicate, [context])
_.findIndex相似,但反向迭代數組,當predicate經過真檢查時,最接近末端的索引值將被返回。

var users = [{'id': 1, 'name': 'Bob', 'last': 'Brown'},
             {'id': 2, 'name': 'Ted', 'last': 'White'},
             {'id': 3, 'name': 'Frank', 'last': 'James'},
             {'id': 4, 'name': 'Ted', 'last': 'Jones'}];
_.findLastIndex(users, {
  name: 'Ted'
});
=> 3

range_.range([start], stop, [step])
一個用來建立整數靈活編號的列表的函數,便於eachmap循環。若是省略start則默認爲 0step 默認爲 1.返回一個從startstop的整數的列表,用step來增長 (或減小)獨佔。值得注意的是,若是stop值在start前面(也就是stop值小於start值),那麼值域會被認爲是零長度,而不是負增加。-若是你要一個負數的值域 ,請使用負數step.

_.range(10);
=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_.range(1, 11);
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
_.range(0, 30, 5);
=> [0, 5, 10, 15, 20, 25]
_.range(0, -10, -1);
=> [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
_.range(0);
=> []

與函數有關的函數(Function (uh, ahem) Functions)

bind_.bind(function, object, *arguments)
綁定函數 function 到對象 object 上, 也就是不管什麼時候調用函數, 函數裏的 this 都指向這個 object.任意可選參數 arguments 能夠傳遞給函數 function , 能夠填充函數所須要的參數,這也被稱爲 partial application。對於沒有結合上下文的partial application綁定,請使用partial
(愚人碼頭注:partial application翻譯成「部分應用」或者「偏函數應用」。partial application能夠被描述爲一個函數,它接受必定數目的參數,綁定值到一個或多個這些參數,並返回一個新的函數,這個返回函數只接受剩餘未綁定值的參數。參見:http://en.wikipedia.org/wiki/Partial_application。感謝@一任風月憶秋年的建議)。

var func = function(greeting){ return greeting + ': ' + this.name };
func = _.bind(func, {name: 'moe'}, 'hi');
func();
=> 'hi: moe'

bindAll_.bindAll(object, *methodNames)
methodNames參數指定的一些方法綁定到object上,這些方法就會在對象的上下文環境中執行。綁定函數用做事件處理函數時很是便利,不然函數被調用時this一點用也沒有。methodNames參數是必須的。

var buttonView = {
  label  : 'underscore',
  onClick: function(){ alert('clicked: ' + this.label); },
  onHover: function(){ console.log('hovering: ' + this.label); }
};
_.bindAll(buttonView, 'onClick', 'onHover');
// When the button is clicked, this.label will have the correct value.
jQuery('#underscore_button').bind('click', buttonView.onClick);

partial_.partial(function, *arguments)
局部應用一個函數填充在任意個數的 arguments改變其動態this值。和bind方法很相近。你能夠傳遞_arguments列表來指定一個不預先填充,但在調用時提供的參數。

var subtract = function(a, b) { return b - a; };
sub5 = _.partial(subtract, 5);
sub5(20);
=> 15

// Using a placeholder
subFrom20 = _.partial(subtract, _, 20);
subFrom20(5);
=> 15

memoize_.memoize(function, [hashFunction])
Memoizes方法能夠緩存某函數的計算結果。對於耗時較長的計算是頗有幫助的。若是傳遞了 hashFunction 參數,就用 hashFunction 的返回值做爲key存儲函數的計算結果。hashFunction 默認使用function的第一個參數做爲key。memoized值的緩存可做爲返回函數的cache屬性。

var fibonacci = _.memoize(function(n) {
  return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
});

delay_.delay(function, wait, *arguments)
相似setTimeout,等待wait毫秒後調用function。若是傳遞可選的參數arguments,當函數function執行時, arguments 會做爲參數傳入。

var log = _.bind(console.log, console);
_.delay(log, 1000, 'logged later');
=> 'logged later' // Appears after one second.

defer_.defer(function, *arguments)
延遲調用function直到當前調用棧清空爲止,相似使用延時爲0的setTimeout方法。對於執行開銷大的計算和無阻塞UI線程的HTML渲染時候很是有用。 若是傳遞arguments參數,當函數function執行時, arguments 會做爲參數傳入。

_.defer(function(){ alert('deferred'); });
// Returns from the function before the alert runs.

throttle_.throttle(function, wait, [options])
建立並返回一個像節流閥同樣的函數,當重複調用函數的時候,至少每隔 wait毫秒調用一次該函數。對於想控制一些觸發頻率較高的事件有幫助。(愚人碼頭注:詳見:javascript函數的throttle和debounce,感謝 @澳利澳先生 的翻譯建議)

默認狀況下,throttle將在你調用的第一時間儘快執行這個function,而且,若是你在wait週期內調用任意次數的函數,都將盡快的被覆蓋。若是你想禁用第一次首先執行的話,傳遞{leading: false},還有若是你想禁用最後一次執行的話,傳遞{trailing: false}

var throttled = _.throttle(updatePosition, 100);
$(window).scroll(throttled);

debounce_.debounce(function, wait, [immediate])
返回 function 函數的防反跳版本, 將延遲函數的執行(真正的執行)在函數最後一次調用時刻的 wait 毫秒以後. 對於必須在一些輸入(可能是一些用戶操做)中止到達以後執行的行爲有幫助。 例如: 渲染一個Markdown格式的評論預覽, 當窗口中止改變大小以後從新計算佈局, 等等.

傳參 immediatetruedebounce會在 wait 時間間隔的開始調用這個函數 。(愚人碼頭注:而且在 waite 的時間以內,不會再次調用。)在相似不當心點了提交按鈕兩下而提交了兩次的狀況下頗有用。 (感謝 @ProgramKid 的翻譯建議)

var lazyLayout = _.debounce(calculateLayout, 300);
$(window).resize(lazyLayout);

once_.once(function)
建立一個只能調用一次的函數。重複調用改進的方法也沒有效果,只會返回第一次執行時的結果。 做爲初始化函數使用時很是有用, 不用再設一個boolean值來檢查是否已經初始化完成.

var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.

after_.after(count, function)
建立一個函數, 只有在運行了 count 次以後纔有效果. 在處理同組異步請求返回結果時, 若是你要確保同組裏全部異步請求完成以後才 執行這個函數, 這將很是有用。

var renderNotes = _.after(notes.length, render);
_.each(notes, function(note) {
  note.asyncSave({success: renderNotes});
});
// renderNotes is run once, after all notes have saved.

before_.before(count, function)
建立一個函數,調用不超過count 次。 當count已經達到時,最後一個函數調用的結果將被記住並返回。

var monthlyMeeting = _.before(3, askForRaise);
monthlyMeeting();
monthlyMeeting();
monthlyMeeting();
// the result of any subsequent calls is the same as the second call

wrap_.wrap(function, wrapper)
將第一個函數 function 封裝到函數 wrapper 裏面, 並把函數 function 做爲第一個參數傳給 wrapper. 這樣可讓 wrapperfunction 運行以前和以後 執行代碼, 調整參數而後附有條件地執行.

var hello = function(name) { return "hello: " + name; };
hello = _.wrap(hello, function(func) {
  return "before, " + func("moe") + ", after";
});
hello();
=> 'before, hello: moe, after'

negate_.negate(predicate)
返回一個新的predicate函數的否認版本。

var isFalsy = _.negate(Boolean);
_.find([-2, -1, 0, 1, 2], isFalsy);
=> 0

compose_.compose(*functions)
返回函數集 functions 組合後的複合函數, 也就是一個函數執行完以後把返回的結果再做爲參數賦給下一個函數來執行. 以此類推. 在數學裏, 把函數 f(), g(), 和 h() 組合起來能夠獲得複合函數 f(g(h()))

var greet    = function(name){ return "hi: " + name; };
var exclaim  = function(statement){ return statement.toUpperCase() + "!"; };
var welcome = _.compose(greet, exclaim);
welcome('moe');
=> 'hi: MOE!'

對象函數(Object Functions)

keys_.keys(object)
檢索object擁有的全部可枚舉屬性的名稱。

_.keys({one: 1, two: 2, three: 3});
=> ["one", "two", "three"]

allKeys_.allKeys(object)
檢索object擁有的和繼承的全部屬性的名稱。

function Stooge(name) {
  this.name = name;
}
Stooge.prototype.silly = true;
_.allKeys(new Stooge("Moe"));
=> ["name", "silly"]

values_.values(object)
返回object對象全部的屬性值。

_.values({one: 1, two: 2, three: 3});
=> [1, 2, 3]

mapObject_.mapObject(object, iteratee, [context])
它相似於map,可是這用於對象。轉換每一個屬性的值。

_.mapObject({start: 5, end: 12}, function(val, key) {
  return val + 5;
});
=> {start: 10, end: 17}

pairs_.pairs(object)
把一個對象轉變爲一個[key, value]形式的數組。

_.pairs({one: 1, two: 2, three: 3});
=> [["one", 1], ["two", 2], ["three", 3]]

invert_.invert(object)
返回一個object副本,使其鍵(keys)和值(values)對換。對於這個操做,必須確保object裏全部的值都是惟一的且能夠序列號成字符串.

_.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"});
=> {Moses: "Moe", Louis: "Larry", Jerome: "Curly"};

create_.create(prototype, props)
建立具備給定原型的新對象, 可選附加props 做爲 own的屬性。 基本上,和Object.create同樣, 可是沒有全部的屬性描述符。

var moe = _.create(Stooge.prototype, {name: "Moe"});

functions_.functions(object) Alias: methods
返回一個對象裏全部的方法名, 並且是已經排序的 — 也就是說, 對象裏每一個方法(屬性值是一個函數)的名稱.

_.functions(_);
=> ["all", "any", "bind", "bindAll", "clone", "compact", "compose" ...

findKey_.findKey(object, predicate, [context])
Similar to _.findIndex but for keys in objects. Returns the key where the predicate truth test passes or undefined.

extend_.extend(destination, *sources)
複製source對象中的全部屬性覆蓋到destination對象上,而且返回 destination 對象. 複製是按順序的, 因此後面的對象屬性會把前面的對象屬性覆蓋掉(若是有重複).

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}

extendOwn_.extendOwn(destination, *sources) Alias: assign
相似於 extend, 但只複製本身的屬性覆蓋到目標對象。(愚人碼頭注:不包括繼承過來的屬性)

pick_.pick(object, *keys)
返回一個object副本,只過濾出keys(有效的鍵組成的數組)參數指定的屬性值。或者接受一個判斷函數,指定挑選哪一個key。

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
=> {name: 'moe', age: 50}
_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {age: 50}

omit_.omit(object, *keys)
返回一個object副本,只過濾出除去keys(有效的鍵組成的數組)參數指定的屬性值。 或者接受一個判斷函數,指定忽略哪一個key。

_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
=> {name: 'moe', age: 50}
_.omit({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
  return _.isNumber(value);
});
=> {name: 'moe', userid: 'moe1'}

defaults_.defaults(object, *defaults)
defaults對象填充object 中的undefined屬性。 而且返回這個object。一旦這個屬性被填充,再使用defaults方法將不會有任何效果。(感謝@一任風月憶秋年的拍磚)

var iceCream = {flavor: "chocolate"};
_.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"});
=> {flavor: "chocolate", sprinkles: "lots"}

clone_.clone(object)
建立 一個淺複製(淺拷貝)的克隆object。任何嵌套的對象或數組都經過引用拷貝,不會複製。

_.clone({name: 'moe'});
=> {name: 'moe'};

tap_.tap(object, interceptor)
object做爲參數來調用函數interceptor,而後返回object。這種方法的主要意圖是做爲函數鏈式調用 的一環, 爲了對此對象執行操做並返回對象自己。

_.chain([1,2,3,200])
  .filter(function(num) { return num % 2 == 0; })
  .tap(alert)
  .map(function(num) { return num * num })
  .value();
=> // [2, 200] (alerted)
=> [4, 40000]

has_.has(object, key)
對象是否包含給定的鍵嗎?等同於object.hasOwnProperty(key),可是使用hasOwnProperty 函數的一個安全引用,以防意外覆蓋

_.has({a: 1, b: 2, c: 3}, "b");
=> true

property_.property(key)
返回一個函數,這個函數返回任何傳入的對象的key屬性。

var stooge = {name: 'moe'};
'moe' === _.property('name')(stooge);
=> true

propertyOf_.propertyOf(object)
_.property相反。須要一個對象,並返回一個函數,這個函數將返回一個提供的屬性的值。

var stooge = {name: 'moe'};
_.propertyOf(stooge)('name');
=> 'moe'

matcher_.matcher(attrs)
返回一個斷言函數,這個函數會給你一個斷言能夠用來辨別給定的對象是否匹配attrs指定鍵/值屬性。

var ready = _.matcher({selected: true, visible: true});
var readyToGoList = _.filter(list, ready);

isEqual_.isEqual(object, other)
執行兩個對象之間的優化深度比較,肯定他們是否應被視爲相等。

var stooge = {name: 'moe', luckyNumbers: [13, 27, 34]};
var clone  = {name: 'moe', luckyNumbers: [13, 27, 34]};
stooge == clone;
=> false
_.isEqual(stooge, clone);
=> true

isMatch_.isMatch(object, properties)
告訴你properties中的鍵和值是否包含在object中。

var stooge = {name: 'moe', age: 32};
_.isMatch(stooge, {age: 32});
=> true

isEmpty_.isEmpty(object)
若是object 不包含任何值(沒有可枚舉的屬性),返回true。 對於字符串和類數組(array-like)對象,若是length屬性爲0,那麼_.isEmpty檢查返回true

_.isEmpty([1, 2, 3]);
=> false
_.isEmpty({});
=> true

isElement_.isElement(object)
若是object是一個DOM元素,返回true

_.isElement(jQuery('body')[0]);
=> true

isArray_.isArray(object)
若是object是一個數組,返回true

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

isObject_.isObject(value)
若是object是一個對象,返回true。須要注意的是JavaScript數組和函數是對象,字符串和數字不是。

_.isObject({});
=> true
_.isObject(1);
=> false

isArguments_.isArguments(object)
若是object是一個參數對象,返回true

(function(){ return _.isArguments(arguments); })(1, 2, 3);
=> true
_.isArguments([1,2,3]);
=> false

isFunction_.isFunction(object)
若是object是一個函數(Function),返回true

_.isFunction(alert);
=> true

isString_.isString(object)
若是object是一個字符串,返回true

_.isString("moe");
=> true

isNumber_.isNumber(object)
若是object是一個數值,返回true (包括 NaN)。

_.isNumber(8.4 * 5);
=> true

isFinite_.isFinite(object)
若是object是一個有限的數字,返回true

_.isFinite(-101);
=> true

_.isFinite(-Infinity);
=> false

isBoolean_.isBoolean(object)
若是object是一個布爾值,返回true,不然返回false

_.isBoolean(null);
=> false

isDate_.isDate(object)
Returns true if object is a Date.

_.isDate(new Date());
=> true

isRegExp_.isRegExp(object)
若是object是一個正則表達式,返回true

_.isRegExp(/moe/);
=> true

isError_.isError(object)
若是object繼承至 Error 對象,那麼返回 true

try {
  throw new TypeError("Example");
} catch (o_O) {
  _.isError(o_O)
}
=> true

isNaN_.isNaN(object)
若是objectNaN,返回true
注意: 這和原生的isNaN 函數不同,若是變量是undefined,原生的isNaN 函數也會返回 true

_.isNaN(NaN);
=> true
isNaN(undefined);
=> true
_.isNaN(undefined);
=> false

isNull_.isNull(object)
若是object的值是 null,返回true

_.isNull(null);
=> true
_.isNull(undefined);
=> false

isUndefined_.isUndefined(value)
若是valueundefined,返回true

_.isUndefined(window.missingVariable);
=> true

實用功能(Utility Functions)

noConflict_.noConflict()
放棄Underscore 的控制變量"_"。返回Underscore 對象的引用。

var underscore = _.noConflict();

identity_.identity(value)
返回與傳入參數相等的值. 至關於數學裏的: f(x) = x
這個函數看似無用, 可是在Underscore裏被用做默認的迭代器iterator.

var stooge = {name: 'moe'};
stooge === _.identity(stooge);
=> true

constant_.constant(value)
建立一個函數,這個函數 返回相同的值 用來做爲_.constant的參數。

var stooge = {name: 'moe'};
stooge === _.constant(stooge)();
=> true

noop_.noop()
返回undefined,不論傳遞給它的是什麼參數。 能夠用做默承認選的回調參數。

obj.initialize = _.noop;

times_.times(n, iteratee, [context])
調用給定的迭代函數n次,每一次調用iteratee傳遞index參數。生成一個返回值的數組。
注意: 本例使用 鏈式語法

_(3).times(function(n){ genie.grantWishNumber(n); });

random_.random(min, max)
返回一個minmax之間的隨機整數。若是你只傳遞一個參數,那麼將返回0和這個參數之間的整數。

_.random(0, 100);
=> 42

mixin_.mixin(object)
容許用您本身的實用程序函數擴展Underscore。傳遞一個 {name: function}定義的哈希添加到Underscore對象,以及面向對象封裝。

_.mixin({
  capitalize: function(string) {
    return string.charAt(0).toUpperCase() + string.substring(1).toLowerCase();
  }
});
_("fabio").capitalize();
=> "Fabio"

iteratee_.iteratee(value, [context])
一個重要的內部函數用來生成可應用到集合中每一個元素的回調, 返回想要的結果 - 不管是等式,任意回調,屬性匹配,或屬性訪問。
經過_.iteratee轉換判斷的Underscore 方法的完整列表是 map, find, filter, reject, every, some, max, min, sortBy, groupBy, indexBy, countBy, sortedIndex, partition, 和 unique.

var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
_.map(stooges, _.iteratee('age'));
=> [25, 21, 23];

uniqueId_.uniqueId([prefix])
爲須要的客戶端模型或DOM元素生成一個全局惟一的id。若是prefix參數存在, id 將附加給它。

_.uniqueId('contact_');
=> 'contact_104'

escape_.escape(string)
轉義HTML字符串,替換&, <, >, ", ', 和 /字符。

_.escape('Curly, Larry & Moe');
=> "Curly, Larry &amp; Moe"

unescape_.unescape(string)
escape相反。轉義HTML字符串,替換&, &lt;, &gt;, &quot;, &#96;, 和 &#x2F;字符。

_.unescape('Curly, Larry &amp; Moe');
=> "Curly, Larry & Moe"

result_.result(object, property, [defaultValue])
若是指定的property 的值是一個函數,那麼將在object上下文內調用它;不然,返回它。若是提供默認值,而且屬性不存在,那麼默認值將被返回。若是設置defaultValue是一個函數,它的結果將被返回。

var object = {cheese: 'crumpets', stuff: function(){ return 'nonsense'; }};
_.result(object, 'cheese');
=> "crumpets"
_.result(object, 'stuff');
=> "nonsense"
_.result(object, 'meat', 'ham');
=> "ham"

now_.now()
一個優化的方式來得到一個當前時間的整數時間戳。可用於實現定時/動畫功能。

_.now();
=> 1392066795351

template_.template(templateString, [settings])
將 JavaScript 模板編譯爲能夠用於頁面呈現的函數, 對於經過JSON數據源生成複雜的HTML並呈現出來的操做很是有用。 模板函數可使用 <%= … %>插入變量, 也能夠用<% … %>執行任意的 JavaScript 代碼。 若是您但願插入一個值, 並讓其進行HTML轉義,請使用<%- … %>。 當你要給模板函數賦值的時候,能夠傳遞一個含有與模板對應屬性的data對象 。 若是您要寫一個一次性的, 您能夠傳對象 data 做爲第二個參數給模板 template 來直接呈現, 這樣頁面會當即呈現而不是返回一個模板函數. 參數 settings 是一個哈希表包含任何能夠覆蓋的設置 _.templateSettings.

var compiled = _.template("hello: <%= name %>");
compiled({name: 'moe'});
=> "hello: moe"

var template = _.template("<b><%- value %></b>");
template({value: '<script>'});
=> "<b>&lt;script&gt;</b>"

您也能夠在JavaScript代碼中使用 print. 有時候這會比使用 <%= ... %> 更方便.

var compiled = _.template("<% print('Hello ' + epithet); %>");
compiled({epithet: "stooge"});
=> "Hello stooge"

若是ERB式的分隔符您不喜歡, 您能夠改變Underscore的模板設置, 使用別的符號來嵌入代碼.定義一個 interpolate 正則表達式來逐字匹配嵌入代碼的語句, 若是想插入轉義後的HTML代碼則須要定義一個 escape 正則表達式來匹配,還有一個 evaluate 正則表達式來匹配您想要直接一次性執行程序而不須要任何返回值的語句.您能夠定義或省略這三個的任意一個.例如, 要執行Mustache.js類型的模板:

_.templateSettings = {
  interpolate: /\{\{(.+?)\}\}/g
};

var template = _.template("Hello {{ name }}!");
template({name: "Mustache"});
=> "Hello Mustache!"

默認的, template 經過 with 語句來取得 data 全部的值. 固然, 您也能夠在 variable 設置裏指定一個變量名. 這樣能顯著提高模板的渲染速度.

_.template("Using 'with': <%= data.answer %>", {variable: 'data'})({answer: 'no'});
=> "Using 'with': no"

預編譯模板對調試不可重現的錯誤頗有幫助. 這是由於預編譯的模板能夠提供錯誤的代碼行號和堆棧跟蹤, 有些模板在客戶端(瀏覽器)上是不能經過編譯的 在編譯好的模板函數上, 有 source 屬性能夠提供簡單的預編譯功能.

<script>
  JST.project = <%= _.template(jstText).source %>;
</script>

鏈式語法(Chaining)

您能夠在面向對象或者函數的風格下使用Underscore, 這取決於您的我的偏好. 如下兩行代碼均可以 把一個數組裏的全部數字乘以2.

_.map([1, 2, 3], function(n){ return n * 2; });
_([1, 2, 3]).map(function(n){ return n * 2; });

對一個對象使用 chain 方法, 會把這個對象封裝並 讓之後每次方法的調用結束後都返回這個封裝的對象, 當您完成了計算, 可使用 value 函數來取得最終的值. 如下是一個同時使用了 map/flatten/reduce 的鏈式語法例子, 目的是計算一首歌的歌詞裏每個單詞出現的次數.

var lyrics = [
  {line: 1, words: "I'm a lumberjack and I'm okay"},
  {line: 2, words: "I sleep all night and I work all day"},
  {line: 3, words: "He's a lumberjack and he's okay"},
  {line: 4, words: "He sleeps all night and he works all day"}
];

_.chain(lyrics)
  .map(function(line) { return line.words.split(' '); })
  .flatten()
  .reduce(function(counts, word) {
    counts[word] = (counts[word] || 0) + 1;
    return counts;
  }, {})
  .value();

=> {lumberjack: 2, all: 4, night: 2 ... }

In addition, the 此外, 數組原型方法 也經過代理加入到了鏈式封裝的Underscore對象, 因此您能夠 在鏈式語法中直接使用 reversepush 方法, 而後再接着其餘的語句.

chain_.chain(obj)
返回一個封裝的對象. 在封裝的對象上調用方法會返回封裝的對象自己, 直道 value 方法調用爲止.

var stooges = [{name: 'curly', age: 25}, {name: 'moe', age: 21}, {name: 'larry', age: 23}];
var youngest = _.chain(stooges)
  .sortBy(function(stooge){ return stooge.age; })
  .map(function(stooge){ return stooge.name + ' is ' + stooge.age; })
  .first()
  .value();
=> "moe is 21"

value_(obj).value()
獲取封裝對象的最終值.

_([1, 2, 3]).value();
=> [1, 2, 3]
相關文章
相關標籤/搜索