Underscore.js
简介
Underscore 是一个 JavaScript 库,在没有拓展任何内置对象的前提下,提供了一整套的函数式编程类型的实用函数。主要解决了这样一个问题:“如果我面对一个空白 HTML 文档,我想要一个高效的编码,该如何开始”。与此同时,她弥补了 jQuery 的不足,也成为 Backbone 的首要依赖。
Underscore 提供了100多个函数,不止包含常用的 map
filter
invoke
帮你解决日常开发问题,同时提供诸如 函数绑定,视图模板,快速索引,强类型相等测试等等高级功能。
想要进一步研读源码,这里有一份测试代码可以参考。当然更好的方式就是去阅读这份包含注释的源码了
尽情享用 Underscore 为你带来的便利。如果你想让这个库更加完美,可以试试Underscore-contrib 本项目源码也托管在 GitHub 上,你可以提交 Issue 来报告 bug 以及参与特性讨论。
Underscore 是 DocumentCloud 的开源组件库。
安装
- Nodejs
npm i underscore
- Meteor
meteor add underscore
- Require
require(['underscore'],...
- Bower
bower i underscore
- Component
component i jashkenas/underscore
- Yarn
yarn add underscore
集合函数
遍历集合 _.each(list, iteratee, [context])
别名 _.forEach
遍历 list 中的所有元素,针对每一个元素可以执行一个 iteratee 函数,如果指定了上下文 context 怎把 iteratee 绑定到这个上下文中。iteratee 指定接收三个参数 (element, index, list) 函数默认返回 list 本身,供链式调用。
_.each([1, 2, 3], alert) // 依次弹出3个值1,2,3
_.each({one: 1, two: 2, three: 3}, alert) // 依次弹出3个值1,2,3
注意 这里的集合包含了数组,对象以及类数组,但应避免传入 Length 属性不确定的集合
有个 each 的抽象版本 _.invoke(list, methodName, *arguments)
这个函数与 each 的区别在于
- 可以额外传参,参数会在 method 调起时传入,所以对所有元素都会生效
- 传入的是函数名,而非函数本身
处理集合 _.map(list, iteratee, [context])
别名 _.collect
通过 iteratee 将 list 中的每个值映射到新的数组中, 此方法返回新数组
_.map([1,2,3], (num)=> num*3) // [3, 6, 9]
_.map({one: 1, two: 2, three: 3}, (num, key)=> num*3) //[3,6,9]
有个针对对象数组的精简版本 _pluck(list, propertyName) 用以萃取对象数组中某属性值,返回一个数组。
_.pluck([{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}], 'name');//["moe", "larry", "curly"]
集合降维 _.reduce(list, iteratee, [memo], [context])
别名 _.inject & _.foldl
reduce 将 list 中的元素归结为一个单独的值,memo 是 reduce 的初始值,reduce 每一步都由 iteratee 返回。iteratee 指定接收四个参数,memo, value, index, list。 如果没有传递 memo,reduce 会从第二个元素开始,并将第一个参数作为 memo 传递给处理函数。
sum = _.reduce([1,2,3], (memo, num)=> memo+num) // 6
降维方向如果从集合尾部开始,那么就对应了 _.reduceRight 其实现与 reduce 相同,别名为 _.foldr
let list = [[0, 1], [2, 3], [4, 5]]
let flat = _.reduceRight(list, (pre, next)=> pre.concat(next)); //[4,5,2,3,0,1]
查找定位 _.find(list, predicate, [context])
别名 _.detect
遍历 list 将其中每一个值提供给真值监测函数 predicate。找到匹配的函数立即返回并输出通过检测的元素值,剩余部分无视。
let evenBad = _.find([1,2,3,4,5], (num)=>num%2==0) // 2
排序 _.sortBy(list, iteratee, [context])
返回一个排序后的list拷贝副本。如果传递iteratee参数,iteratee将作为list中每个值的排序依据。迭代器也可以是字符串的属性的名称进行排序的(比如 length)。
_.sortBy([1, 2, 3, 4, 5, 6], (num)=>Math.sin(num)); //[5, 4, 6, 3, 1, 2]
基于查找就有很多事情可以做了。
一、 最值
_.max(list, [iteratee],[context])/ _.min,这两个不仅可以返回数组的最值,还能通过指定比较依据来取得对象数组某个属性的最值。
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};
二、索引、分组
_.indexBy(list, iteratee, [context])
用过 Excel 的按行排序吧,这里就是按照 iteratee 指定的元素对 list进行排序。
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}
}
_.groupBy(list, iteratee, [context]) 把一个集合分组为多个集合,通过 iterator 返回的结果进行分组. 如果 iterator 是一个字符串而不是函数, 那么将使用 iterator 作为各元素的属性名来对比进行分组.
_.groupBy([1.3, 2.1, 2.4], (num)=>Math.floor(num) });// {1: [1.3], 2: [2.1, 2.4]}
_.groupBy(['one', 'two', 'three'], 'length');//{3: ["one", "two"], 5: ["three"]}
_.countBy(list, iteratee, [context]) 排序一个列表组成一个组,并且返回各组中的对象的数量的计数。类似groupBy,但是不是返回列表的值,而是返回在该组中值的数目。
_.countBy([1, 2, 3, 4, 5], (num)=> num % 2 == 0 ?'even': 'odd';); //{odd: 3, even: 2}
高级查找->全局监测 _.every(list, [predicate], [context])
别名 _.all
如果 list 中 所有对象 都满足 predicate 监测,则返回 true
let isAllOdd = (list)=> _.every(list, (item)=>item%2==0)
isAllOdd([1,2,3,4]) //false
与之相辅的有一个存在性监测, _.some(list, [predicate], [context]) 这种监测类似于 find 但并不返回满足监测的元素,而是 Boolean 值。
别名 _.any
如果 list 中有 任何一个 元素通过 predicate 的真值检测就返回true。一旦找到了符合条件的元素, 就直接中断对list的遍历。
let isHasOdd = (list)=> _.every(list, (item)=>item%2==0)
isHasOdd([1,2,3,4]) //true
存在性监测有个精简版的 _.contains(list, value)
如果 list 中包含 value 的值则返回 true 并终止监测
高级查找->过滤器 _.filter(list, predicate, [context])
别名 _.select
遍历 list 返回包含所有通过predicate真值检测的元素值。
let evenGood = _.filter([1,2,3,4,5], (num)=>num%2==0) //[2,4]
高级查找->使用属性查找对象 _.where(list, properties)
遍历list中的每一个值,返回一个数组,包含了properties所列出的属性的对象集合。
_.where(loves, {name: "meng", year: 1990});// [{id: 1020, name: 'meng', year: '1990}, {id: 1022, name: 'meng', year: '1990}]
如果希望返回的是第一个值,那就可以结合 find 函数的尿性,组成一个 _.findWhere 方法
高级查找->排除法查找 _.reject(list, properties, [context])
返回list中没有通过predicate真值检测的元素集合,与filter相反。
let oddGood = _.reject([1,2,3,4,5], (num)=>num%2==0) //[1,3,5]
乱序函数,舒服了 _.shuffle(list)
返回一个随机乱序的 list 的副本,使用 F-Y 算法实现
_.shuffle([1, 2, 3, 4, 5, 6]); //[4, 1, 6, 3, 5, 2]
随机取样函数 _.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(list)
把list(任何可以迭代的对象)转换成一个数组,在转换 arguments 对象时非常有用。
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4); // [2,3,4]
集合长度/尺寸 .size(list)
正则分组 _.partition(array, predicate)
拆分一个数组(array)为两个数组:第一个数组其元素都满足predicate迭代函数, 而第二个的所有元素均不能满足predicate迭代函数。
_.partition([0, 1, 2, 3, 4, 5], isOdd);//[[1, 3, 5], [0, 2, 4]]