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]