2018-05-26 经常用到的lodash 函数

lodash的官方文档: https://lodash.com/docs/4.17.10
lodash的中文文档: http://lodash.think2011.net/keys
所有的方法,根据操作对象的不同被放到了不同的目录下,比如当你想处理一个数组的时候,与其开始着手写个方法,不如到lodash的array目录下找找有没有可以用的方法,避免造重复的车轮,而且处处可用,很方便。

image.png

下面是我常用的一些方法,归纳出来,其实都很基础,只是记录下来。例子大部分来自官网。BTW, 这里我只简单的记下用到的方法,参数写的可能不规范,主要是后面的使用场景和方法。建议大家先看一下官方文档。
lodash引入的时候一般都用表示。不知道为什么有些 发布之后就丢掉了。
var _=require("lodash")

--collection操作--

.isEmpty(value) , Checks if value is an empty object, collection, map, or set.
.orderBy(collection, [iteratees=[.identity]], [orders]) 和
.sortBy()相比, 这个方法功能更多,可以选择根据collection的某个字段按照升序或者降序排列。例子

var users = [
  { 'user': 'fred',   'age': 48 },
  { 'user': 'barney', 'age': 34 },
  { 'user': 'fred',   'age': 40 },
  { 'user': 'barney', 'age': 36 }
];
 
// Sort by `user` in ascending order and by `age` in descending order.
_.orderBy(users, ['user', 'age'], ['asc', 'desc']);
// => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
再如,按时间降序排序
_.orderBy(pickTask.pullResults, "pulledWhen", "desc");

.map(collection, [iteratee=.identity]), 从数组对象中映射出某个值来

如,取出OrderId: _.map(requestInputList, input => input.OrderId)

.filter(collection, [predicate=.identity]),从数组对象中过滤出某些符合条件的对象来
_.find(collection, function), 返回符合条件的第一个元素

_.find(itemFieldViews, field => propertyName === field.propertyName);

_.size(collection) 得出这个数组的长度
.forEach(collection, function) , .each()和.forEach() 已经是一样了, 注意.each(里面不能用yield表达式)
.flatMap(collection, [iteratee=.identity]),将数组里的每个元素都经过后面的function计算一遍,输出一个计算过的数组

function duplicate(n) {
  return [n, n];
}
 
_.flatMap([1, 2], duplicate);
// => [1, 1, 2, 2]

.groupBy(collection, [iteratee=.identity]), 返回的是key-values 对,就是一个个object。这个跟java8 lambda的xx.stream().collect(Collectors.groupingBy(o -> o.id)); 很像。
但是这里想说的是,当在js里要用_.each()按object来遍历这个结果,是这样写的:

_.each(itemLinesGroupByLocation, (values, keys)=>{
......
})
不是(key, values)哦

当然还可以用其他方式遍历:

for(let key in itemLinesGroupByLocation){
    console.log(key)
    console.log(itemLinesGroupByLocation[key])
}
或者
for(let locationId of _.keys(itemLinesGroupByLocation)){
    let items = itemLinesGroupByLocation[locationId]
    ...
}

--array操作--

_.head([1, 2, 3]); _.head() = _.first() 取出数组的第一个元素。
_.uniq(array), 去重数组或者collection
_.union([arrays]),联合两个数组,会去重
_.includes(collection, value, [fromIndex=0]), 查看某个值是否在这个collection里
_.flatten(array) 一维扁平化数组

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

_.remove(array, function) 从数组中删掉符合条件的元素
举例

var array = [1, 2, 3, 4];
var evens = _.remove(array, function(n) {
  return n % 2 == 0;
});
 
console.log(array);
// => [1, 3]
 
console.log(evens);
// => [2, 4]

--Math操作--

_.ceil(4.006); = 5 取大
_.sum(array) 把数组的所有值加起来输出一个结果
.sumBy(array, [iteratee=.identity]),遍历数组,找出function里指定的元素,并求和

var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
 
_.sumBy(objects, function(o) { return o.n; });
// => 20
 
// The `_.property` iteratee shorthand.
_.sumBy(objects, 'n');
// => 20

--array操作--

_.pick(object, [paths]), 从一个object里挑出几个属性

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.pick(object, ['a', 'c']);
// => { 'a': 1, 'c': 3 }

.pickBy(object, [predicate=.identity]), 第二部分是个函数,作用于每个元素

var object = { 'a': 1, 'b': '2', 'c': 3 };
 
_.pickBy(object, _.isNumber);
// => { 'a': 1, 'c': 3 }

--Object操作--

_.keys(Object) , 官网说它的作用是:

Creates an array of the own enumerable property names of `object`.

**Note:** Non-object values are coerced to objects. See the [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) for more details.

实际使用中,我大多数用于取_.groupBy()后的map的keys, 不过今天注意到官网在对这个function解释的例子中有个

_.keys('hi');
// => ['0', '1']

网上一搜,为什么参数为一个字符串的时候输出0,1.甚至我把hi改成hiii,输出的是0,1,2,3,看起来是字符串的index。网上也没找到合理的解释。于是注意到官网有这么一句Note: Non-object values are coerced to objects. See the ES spec for more details. 也就是说‘hi’ 此时被转成object,但是为什么是0,1,于是做了个实验,字符串实例化成StringObject后确实用index做为key了,勉强可以解释得通了。官网的解释是在看不太懂。。读的懂的请留言,互相学习:http://ecma-international.org/ecma-262/6.0/#sec-object.keys

image.png

.merge(object, [sources]), 官网对它的描述是跟.assign很像,那么就先看下_.assign是干嘛的,理解这个方法我是参阅了https://scarletsky.github.io/2016/04/02/assign-vs-extend-vs-merge-in-lodash/,作者对官网描述的翻译让我豁然开朗。。泪流满面,原来是这样,
_.assign() , 把源对象(sources)的属性分配到目标对象(object),源对象会从左往右地调用,后面对象的属性会覆盖前面的。

看完摘录自这位作者的例子后就懂了。

_.assign({}, { a: 1 }, { b: 2 });  // 意思就是,{}+{a:1}={a:1}+{b:2}={a:1, b:2}
// { a: 1, b: 2 }

_.assign({}, { a: 1 }, { b: 2 }, { a: 2 });   // 后面的 { a: 2 } 把前面的 { a: 1 } 覆盖了
// { a: 2, b: 2 } 
merge 也和 assign 类似,不同的地方在于 merge 遇到相同属性的时候,如果属性值为纯对象(plain object)或者集合(collection)时,不是用后面的属性值去覆盖前面的属性值,而是会把前后两个属性值合并。
如果源对象的属性值为 undefined,则会忽略该属性。
assign(
  {},
  { a: 1 },
  { b: { c: 2, d: 3} },
  { b: { e: 4 } }
)
// { a: 1, b: { e: 4 } }
merge(
  {},
  { a: 1 },
  { b: { c: 2, d: 3} },
  { b: { e: 4 } }
)
// { a: 1, b: { c: 2, d: 3, e: 4 } }

我今天替别人填了个坑就是.union() 他写成了.merge().
总结就是,如果只是要合并两个纯粹的list(指元素是基础类型)并去重,用.union([arrays])。如果要合并object组成的list,并去重, 就用.merge(object, [sources])。例子:

let studentClass1 = [{"name":"lucy", "age":10}];
let studentClass2 = [{"name":"lucy", "age":10}, {"name":"sam", "age":11}];
let allStudents = _.union(studentClass1, studentClass2);  // 不会合并,会去重
let allStudents2 = _.merge(studentClass1, studentClass2); //会合并,会去重
console.log(allStudents);
console.log(allStudents2);
console.log(_.union(["1","2"],["2","3"])); //会合并,会去重
// 结果
[ { name: 'lucy', age: 10 },
  { name: 'lucy', age: 10 },
  { name: 'sam', age: 11 } ]
[ { name: 'lucy', age: 10 }, { name: 'sam', age: 11 } ]
[ '1', '2', '3' ]
写在最后,只是一些解释,可不看。

在整理这篇文章之前,我发现我居然分不清lodash的collection 和array, 平时在使用中也没有遇到因为collection和array使用出错的问题。因此出于责任心,我找了相关的资料, #####总结就是好像二者区别不大,在用lodash的时候应该是没影响,所以上面的中文解释,我也没区分数组或者集合了:
https://blog.csdn.net/Soaring_Tiger/article/details/48180511
引用这位作者的解释:
在lodash中,Collection是一个抽象的概念,指的是那些我们准备用来迭代的Javascript object,可以是 数组、字符串或者object对象,至于这些数据类型之间的差别细节,则被lodash隐藏起来了,作为开发者你不用操心。

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343