Underscore一個JavaScript實用庫,提供了一整套函數式編程的實用功能,但是沒有擴展任何JavaScript內置對象。它是這個問題的答案:“如果我在一個空白的HTML頁面前坐下, 並希望立即開始工作, 我需要什么?“...它彌補了部分jQuery沒有實現的功能,同時又是Backbone.js必不可少的部分。 (感謝@小鄧子daj 的翻譯建議)
Underscore提供了100多個函數,包括常用的: map, filter, invoke — 當然還有更多專業的輔助函數,如:函數綁定, JavaScript模板功能,創建快速索引, 強類型相等測試, 等等.
該項目代碼托管在GitHub上,你可以通過issues頁、Freenode的 #documentcloud 頻道、發送tweets給@documentcloud三個途徑報告bug以及參與特性討論。
Underscore是DocumentCloud的一個開源組件。
下載
http://www.bootcdn.cn/underscore.js/
安裝(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以方便鏈式調用。(愚人碼頭注:如果存在原生的forEach方法,Underscore就使用它代替。)
_.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
別名為 inject 和 foldl, reduce方法把list中元素歸結為一個單獨的數值。Memo是reduce函數的初始值,reduce的每一步都需要由iteratee返回。這個迭代傳遞4個參數:memo,value 和 迭代的index(或者 key)和最后一個引用的整個 list。
如果沒有memo傳遞給reduce的初始調用,iteratee不會被列表中的第一個元素調用。第一個元素將取代 傳遞給列表中下一個元素調用iteratee的memo參數。
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, "", undefined 和 NaN 都是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 函數,除非它失效。如果您正在使用一個大數組,你知道數組已經排序,傳遞true給isSorted將更快的用二進制搜索..,或者,傳遞一個數字作為第三個參數,為了在給定的索引的數組中尋找第一個匹配值。
_.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])
使用二分查找確定value在list中的位置序號,value按此序號插入能保持list原有的排序。如果提供iterator函數,iterator將作為list排序的依據,包括你傳遞的value 。iterator也可以是字符串的屬性名用來排序(比如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])
一個用來創建整數靈活編號的列表的函數,便於each 和 map循環。如果省略start則默認為 0;step 默認為 1.返回一個從start 到stop的整數的列表,用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格式的評論預覽, 當窗口停止改變大小之后重新計算布局, 等等.
傳參 immediate 為 true, debounce會在 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. 這樣可以讓wrapper 在 function 運行之前和之后 執行代碼, 調整參數然后附有條件地執行.
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 orundefined.
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)
如果object是 NaN,返回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)
如果value是undefined,返回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)
返回一個min 和 max之間的隨機整數。如果你只傳遞一個參數,那么將返回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 & Moe"
unescape_.unescape(string)
和escape相反。轉義HTML字符串,替換&, <, >, ", `, 和 /字符。
_.unescape('Curly, Larry & 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><script></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對象, 所以您可以 在鏈式語法中直接使用 reverse 或 push 方法, 然后再接着其他的語句.
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]