lodash 中文学习拾零之 Collection篇

来源:互联网 发布:淘宝推广计划书 编辑:程序博客网 时间:2024/05/22 01:36

作者:Soaring_Tiger 转载请注明出处

前情提要1 : lodash中文学习拾零之Array篇
前情提要2:lodash 中文学习拾零之 Chain篇

3、Collection(集合)与Array(数组)的区别

对于lodash的初学者而言,可能一下子搞不清楚为什么lodash提供了Array和Collection两类方法?表面上看起来好像这两套方法有些地方是可以互换的,那么我们就进一步来澄清什么是Collection方法,什么是Array方法。

在lodash中,Collection是一个抽象的概念,指的是那些我们准备用来迭代的Javascript object,可以是 数组、字符串或者object对象,至于这些数据类型之间的差别细节,则被lodash隐藏起来了,作为开发者你不用操心。

而lodash的 Array方法则没有那么抽象,它们要求你处理的就是实实在在的数组。从这个意义上讲,即便Array方法没有显式的检查你提交的数据类型,但是它们要求你提交的数据得有数值型length属性(a numerical length property)。

实际上,在大部分时候,你并不需要严格得区分 arrays 和 collections 之间的差别,因为你面对的大多数collections都是以数组的形式出现的,只有在比较少的情况下,你会面临着差别 。所以你只要记住,Array方法是严格要求数据类型(有数值型length属性)的就行了。


3.1 遍历collection元素

3.1.1 .forEach

_.forEach是处理Collection最基础的函数了,下面这个例子非常简单,就是告诉你forEach是如何进行迭代(循环)的:

var collection = [       '红',       '黄',       '蓝',       '绿'];   _.forEach(collection, function(name) {       console.log(name);   });   // →   // 红   // 黄   // 蓝   // 绿

_.forEach有三个参数,第一个参数是要处理的collection,第二个参数是迭代器(以匿名函数的形式出现),第三个参数是 The this binding of iteratee(可以理解为迭代器里的this绑定的方法).

_.forEach文档定义如下:
Aliases(别名):
_.each

Arguments(参数):
1、collection (Array|Object|string): The collection to iterate over.
2、[iteratee=_.identity] (Function): The function invoked per iteration.
3、 [thisArg] (*): The this binding of iteratee.

//例子var collection = [100,200,300,400];    _.forEach(collection, function(value) {        console.log(this.sqrt(value));  //对collection中的每个值开方    },    Math);    //本例中thisArg绑定了Math的方法//10//14.142135623730951//17.320508075688775//20

当迭代发生的时候,每轮到一个元素都激活一次迭代器,迭代器有三个参数:
(1)被迭代的元素,(2)该元素的index或者key,(3)collection。
在迭代器返回false值时,允许整个迭代过程提早结束,如下面的例子:

var myCollection = [       '阿猫',       '阿狗',       '小黑',       '阿花'];   _.forEach(myCollection, function(name, index, collection) {       if (name === '小黑') {           console.log('小黑的index: ' + index);           console.log(collection[index]);             return false;       }   });   // → 小黑的index: 1   // → 小黑

3.1.2 .forEachRight

与_.forEach的执行方向相反,从最右侧的元素先开始进行迭代:

_([1, 2]).forEachRight(function(n) {  console.log(n);}).value();// → 2// → 1

3.3 排序

排序是我们对collection进行操作时会经常遇到的问题,javascript自带的sort()、reverse()之类的函数,远远不能满足我们的需求。


3.3.1 .sortBy

_.sortBy会根据迭代器对输入的collection的每个数组元素进行计算后排序(升序)并生成一个新的数组,同时不会影响原collection的排序(这一点与原生的sort 不同)。

.sortBy有三个参数,与.forEach相同。

迭代器本身还有三个参数(value, index|key, collection),也与.forEach的迭代器相同。

//_.sortBy例子_.sortBy([1, 2, 3], function(n) {  return Math.sin(n);      //直接在迭代器中使用Math});// → [3, 1, 2]_.sortBy([1, 2, 3], function(n) {    return this.sin(n);   //在迭代器内用this绑定了Math}, Math);// → [3, 1, 2]var users = [  { 'user': 'fred' },  { 'user': 'pebbles' },  { 'user': 'barney' }];// 使用'user'作为快捷方式制定按'user'进行排序,简化了迭代器_.pluck(_.sortBy(users, 'user'), 'user');// → ['barney', 'fred', 'pebbles']

_.sorBy不只是对数组起作用,其实对字符串也一样起作用

_.sortBy('cBa').join('')   //Bac ,如果要返回值还是字符串,需要用join函数_.sortBy('cBa')//[ 'B', 'a', 'c' ] ,缺省情况下 sortBy的返回值都是数组

排序之后动态添加数组元素,使用_sortedIndex,可以让新元素自动按拟定好的顺序排列进去,这是多体贴的设计啊!

var collection = [       'Carl',       'Gary',       'Luigi',       'Otto'   ];   var name = 'Luke';  //新添加一个元素进数组   collection.splice(_.sortedIndex(collection, name), 0, name);// _.sortedIndex会保持collection已有的次序   // →// [//   "Carl",// "Gary",// "Luigi",// "Luke",// "Otto" // ]

3.3.2 _.sortByAll

与_.sortBy类似,但是可以对多个property name 或者多个迭代器进行排序,排序的顺序按照迭代器的排列顺序

var users = [  { 'user': 'fred',   'age': 48 },  { 'user': 'barney', 'age': 36 },  { 'user': 'fred',   'age': 42 },  { 'user': 'barney', 'age': 34 }];//先按'user'排序,再按'age'排序_.map(_.sortByAll(users, ['user', 'age']), _.values);// → [['barney', 34], ['barney', 36], ['fred', 42], ['fred', 48]]_.map(_.sortByAll(users, 'user', function(chr) {  return Math.floor(chr.age / 10);}), _.values);// → [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]

3.3.3 _.sortByOrder

类似于_.sortByAll,但是可以制定每一个迭代器的升降顺序,非常灵活!

var users = [  { 'user': 'fred',   'age': 48 },  { 'user': 'barney', 'age': 34 },  { 'user': 'fred',   'age': 42 },  { 'user': 'barney', 'age': 36 }];// 对'user'进行升序排列,对于'age'进行降序排列_.map(_.sortByOrder(users, ['user', 'age'], ['asc', 'desc']), _.values);// → [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 42]]

3.4 数据过滤和搜索

在已有数据集合中搜索和过滤数据是经常用到的功能,lodash提供了一系列工具来帮助我们实现数据的过滤和搜索。


3.4.1 _.where

.where是lodash当中最简单的过滤数据的方法,只有每一个条件都符合的数据才会被挑出来。
.where的好处是简单、精准,严格。

Note: This method supports comparing arrays, booleans, Date objects,
numbers, Object objects, regexes, and strings. Objects are compared by
their own, not inherited, enumerable properties. For comparing a
single own or inherited property value see _.matchesProperty.

注意:.where支持 数组, 布尔值, 日期, 数值, Object类型, 正则表达式,字符串的比较,Object类型只能比较其自身非继承的可枚举属性,要想比较单个Object或继承属性需要用 _.matchesProperty

var collection = [       { name: '路飞', age: 19, gender: '男' },       { name: '索隆', age: 21, gender: '男' },       { name: '娜美', age: 20, gender: '女' },       { name: '罗宾', age: 30, gender: '女' }];   _.where(collection, { age: 30, gender: '女' });   // →   // [   //   { name: '罗宾', age: 30, gender: '女' }   // ]

3.4.2 .filter

_.filter有多种过滤方法
(1) _.matches
(2)_.matchesProperty
(3)_.property

//例子_.filter([4, 5, 6], function(n) {  return n % 2 == 0;});// → [4, 6]var users = [  { 'user': 'barney', 'age': 36, 'active': true },  { 'user': 'fred',   'age': 40, 'active': false }];// using the `_.matches` callback shorthand_.pluck(_.filter(users, { 'age': 36, 'active': true }), 'user');// → ['barney']// using the `_.matchesProperty` callback shorthand_.pluck(_.filter(users, 'active', false), 'user');// → ['fred']// using the `_.property` callback shorthand_.pluck(_.filter(users, 'active'), 'user');// → ['barney']

_.filter还可以接受迭代器进行过滤

var collection = [       { type: '衬衣', size: 'L' },       { type: '裤子', size: 'S' },       { type: 'T恤', size: 'XL' },       { type: '鞋子', size: 'M' }];_.filter(collection, function(item) {   return item.size === 'L' || item.size === 'M';});// → // [//   { type: "衬衣", size: "L" },//   { type: "鞋子", size: "M" }// ]

3.4.3 .reject

当你不知道从集合里面直接选出什么,但是却明确知道不要选什么的时候,你可以用.reject来处理了。

//例子中把 enabled:false的数据筛掉了var collection = [       { name: '冰与火之歌', enabled: true },       { name: '星球大战', enabled: false },       { name: '指环王', enabled: false },       { name: '哈里波特', enabled: true }];   _.reject(collection, { enabled: false });   // →   // [   //   { name: "冰与火之歌", enabled: true },   //   { name: "哈里波特", enabled: true }   // ]

3.5 只找一条符合要求的数据

有时候你并不需要找到所有符合条件的数据,而是只要第一条就够了,那么就用find系列(find、findLast、findWhere),find系列的参数和filter一样,但是返回值不再是数组,而是一个符合条件的元素。如果没找到符合条件的,那就返回undefined

3.5.1_.find

找出第一条符合条件的数组元素(即从数组的左侧找起)

var users = [  { 'user': '钱夫人',  'age': 36, 'active': true },  { 'user': '阿土伯',    'age': 45, 'active': false },  { 'user': '孙小美', 'age': 20,  'active': true },  { 'user': '糖糖', 'age': 20,  'active': true }];_.result(_.find(users, function(chr) {    return chr.age < 40;    //找出第一个age小于40的元素}), 'user');// → '钱夫人'

3.5.2_.findLast

找出最后一条符合条件的数组元素(即从数组的右侧找起)

_.findLast([1, 2, 3, 4], function(n) {  return n % 2 == 1;});// → 3

3.5.3 _.findWhere

参数source是个object,严格按照source来查找匹配的第一项

var users = [  { 'user': '钱夫人', 'age': 36, 'active': true },  { 'user': '阿土伯',   'age': 45, 'active': false }];_.result(_.findWhere(users, { 'age': 36, 'active': true }), 'user');//'钱夫人'_.result(_.findWhere(users, { 'age': 45, 'active': false }), 'user');//'阿土伯'

3.6 “集合”改造(Transforming collections)

lodash有一批工具用于把Collection(集合)改造为新的数据结构,而且还有工具把两个或更多的集合合并到一个集合里去。这些工具可以把我们程序狗从一些繁重而重复的劳动中解放出来,并且让我们的代码更加简介易懂。


3.6.1_.groupBy

在集合中,往往有些元素的某项属性的值是相同的,那么我们就可以这项属性为key进行分组,从而产生一个新的JSON对象,这个JSON对象的key就是被分组的值。

_.groupBy有三个参数,第一个参数是要处理的collection,第二个参数是迭代器(以匿名函数的形式出现),第三个参数是 The this binding of iteratee(可以理解为迭代器里的this绑定的方法)。

groupBy与indexBy的区别在于:groupBy聚合的值以数组形式出现,indexBy获得的值以Object形式出现。

//比如下面这个例子:以size作为分组的依据,得到的新JSON中有"S"和"M"两个Keyvar collection = [       { name: 'Lori', size: 'S' },       { name: 'Johnny', size: 'M' },       { name: 'Theresa', size: 'S' },       { name: 'Christine', size: 'S' }   ];_.groupBy(collection, 'size');// {//   S:[//       { name: "Lori", size: "S" },//       { name: "Theresa", size: "S" },//       { name: "Christine", size: "S" }//   ]//   M: [//     { name: "Johnny", size: "M" }//   ]// }
//也可以用迭代器进行分类,并用迭代器指定key的名称var collection = [       { name: '小黄', age: 20 },       { name: '老李', age: 50 },       { name: '老朱', age: 67 },       { name: '大蒋', age: 39 }   ];   _.groupBy(collection, function(item) {    return item.age > 65 ? 'retired' : 'working';});// →// {//  [//    working: [//       { name: "小黄", age: 20 },//       { name: "老李", age: 50 },//       { name: "大蒋", age: 39 }//    ],//    retired:[//        { name: "老朱", age: 67 }//   ]// }

3.6.2 min,max

_.min(collection, [iteratee], [thisArg])
_.max(collection, [iteratee], [thisArg])

找出那个符合条件的最小(或者最大)的数组元素。

var collection = [       { name: 'Douglas', age: 52, experience: 5 },       { name: 'Karen', age: 36, experience: 22 },       { name: 'Mark', age: 28, experience: 6 },       { name: 'Richard', : age: 30, experience: 16 }   ];   //用Key来查找    _.min(collection, 'age'),   // → { name: "Mark", age: 28, experience: 6 }   //用迭代器来查找   _.max(collection, function(item) {       return item.age + item.experience;   });   // → { name: "Karen", age: 36, experience: 22 }

3.7 集合的扁平化和压缩

集合中数据有时是嵌套结构的,我们需要对它们进行扁平化处理;
而有些时候,集合中的元素包含一些没用的值,我们可以对其进行压缩处理。
通过扁平化和压缩,我们可以得到更加精炼的数据结构,以便进行分析和展示。

//以下是个多种工具结合进行处理的例子:var collection = [       { employer: 'Lodash', employees: [           { name: 'Barbara' },           { name: 'Patrick' },           { name: 'Eugene' }       ]},       { employer: 'Backbone', employees: [           { name: 'Patricia' },           { name: 'Lillian' },           { name: 'Jeremy' }       ]},       { employer: 'Underscore', employees: [           { name: 'Timothy' },           { name: 'Bruce' },           { name: 'Fred' }]} ];//1、用.pluck挑出需要的Key及其value//注意pluck拔出的数据是个二维数组,所以还要用flatten将二维数组降为一维数组var employees = _.flatten(_.pluck(collection, 'employees'));//2、通过迭代器筛选出要使用的数据_.filter(employees, function(employee) {   return (/^[bp]/i).test(employee.name);   });   // →    // [   //   { name: "Barbara" },   //   { name: "Patrick" },   //   { name: "Patricia" },   //   { name: "Bruce" }   // ]

3.8 鉴别部分或全部的集合元素 some、every

3.8.1_.some

some的作用是判断只要集合中有符合要求的属性,就返回true,否则返回false

_.some([null, 0, 'yes', false], Boolean);// → truevar users = [  { 'user': 'barney', 'active': true },  { 'user': 'fred',   'active': false }];// using the `_.matches` callback shorthand_.some(users, { 'user': 'barney', 'active': false });// → false// using the `_.matchesProperty` callback shorthand_.some(users, 'active', false);// → true// using the `_.property` callback shorthand_.some(users, 'active');// → true

3.8.2_.every

_.every则是判断是否集合中每一个元素都包含

var collection = [       { name: 'Jonathan' },       { first: 'Janet' },       { name: 'Kevin' },       { name: 'Ruby' }   ];if (!_.every(collection, 'name')) {   return '缺少name属性;}// → "缺少name属性"

lodash Collection小结:

1、数组(Array)肯定是集合(Collection),所以所有的Colleciton方法都适用于数组;
2、集合不一定都是数组;
3、本节中还有少量的Collection方法没有提及,如map、reduce、reduceRight将在 Map/Reduce篇中介绍。

0 0
原创粉丝点击