2018-05-26 经常用到的lodash 函数
lodash的官方文档: https://lodash.com/docs/4.17.10
lodash的中文文档: http://lodash.think2011.net/keys
所有的方法,根据操作对象的不同被放到了不同的目录下,比如当你想处理一个数组的时候,与其开始着手写个方法,不如到lodash的array目录下找找有没有可以用的方法,避免造重复的车轮,而且处处可用,很方便。
下面是我常用的一些方法,归纳出来,其实都很基础,只是记录下来。例子大部分来自官网。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
.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属性)的就行了。