@xiaoqq
2016-11-10T07:52:03.000000Z
字数 6686
阅读 2216
Lodash
上次分享听龙哥提起Lodash,就觉得这个框架与C#中的LINQ非常类似,所以,想对比一下两个框架。
LINQ:标准查询运算符,大多数这些方法都在序列上运行,其中的序列是一个对象,其类型实现了IEnumerable 接口或 IQueryable 接口。标准查询运算符提供了包括筛选、投影、聚合、排序等功能在内的查询功能。
说白了就是可以用写SQL的语句来操作对象集合,LINQ虽然源于SQL,但是却比SQL强大。
而Lodash带给我最惊喜的一点就是,它能类似于LINQ一样直接对JavaScript的数组(Array)、集合(Collection)甚至是对象进行操作。
编程中操作最多的就是查询,一般来说基本查询需要使用到以下六个操作符:
操作 | SQL | Lodash |
---|---|---|
查询(投影) | select | map |
过滤 | where | filter |
排序 | order by | orderBy |
分组 | group | groupBy |
连接 | join | (官方没有) |
获取数据 | from | 每个函数第一个参数/_() /_.chain() |
注:在lodash4.0之前,过滤使用的都是select
和where
,4.0之后统一改成了filter
其实JavaScript数组自带的map
和filter
函数,已经非常强大了,lodash对其功能基础上进行了两点增强:
DEMO:
var users = {
a:{ 'user': 'barney', 'age': 36, 'active': true },
b:{ 'user': 'fred', 'age': 40, 'active': false },
c:{ 'user': 'pebbles', 'age': 1, 'active': true },
}; //注意,users不是数组,而是一个对象!
_(users).map('age').orderBy().value() //[1, 36, 40]
该函数可以输入三个参数,第三个参数使用'asc', 'desc'
表示升序还是降序
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]]
_(users).groupBy('active').value() //Object {true: Array[2], false: Array[1]}
Join是SQL中比较复杂的语句,lodash中也有join
函数,但是却不是连接的意思。真正的连接操作要用到一个非官方的库lodash-joins。
lodash中每个函数的第一个参数就是输入的数据,当然,也可以使用_()
或_.chain()
包装成一个LodashWrapper
对象,最后可以通过链式调用的方式来操作数据。
排序:_.orderBy(collection, [iteratees=[_.identity]], [orders])
反转:_.reverse(array)
去重:_.uniq(array)
_.uniqBy(array, [iteratee=_.identity])
_.uniqWith(array, [comparator])
(还有两个:_.sortedUniq(array)
_.sortedUniqBy(array, [iteratee])
)
交集:_.intersection([arrays])
_.intersectionBy([arrays], [iteratee=_.identity])
_.intersectionWith([arrays], [comparator])
并集:_.union([arrays])
_.unionBy([arrays], [iteratee=_.identity])
_.unionWith([arrays], [comparator])
差集:_.difference(array, [values])
_.differenceBy(array, [values], [iteratee=_.identity])
_.differenceWith(array, [values], [comparator])
过滤:_.filter(collection, [predicate=_.identity])
所否所有元素满足: _.every(collection, [predicate=_.identity])
至少一个元素满足:_.some(collection, [predicate=_.identity])
是否包含元素: //TODO 未找到
投影:_.map(collection, [iteratee=_.identity])
_.invokeMap(collection, path, [args])
_.mapKeys(object, [iteratee=_.identity])
_.mapValues(object, [iteratee=_.identity])
跳过://TODO未找到
提取:_.take(array, [n=1])
_.takeRight(array, [n=1])
_.takeRightWhile(array, [predicate=_.identity])
_.takeWhile(array, [predicate=_.identity])
官方文档没有,非官方的库:lodash-joins
分组:_.groupBy(collection, [iteratee=_.identity])
删除:_.remove(array, [predicate=_.identity])
根据值删除:_.pull(array, [values])
等值:_.isEqual(value, other)
_.isEqualWith(value, other, [customizer])
第一个:_.head(array)
最后一个:_.last(array)
第n个:_.nth(array, [n=0])
串联:concat
最大:_.max(array)
_.maxBy(array, [iteratee=_.identity])
最小:_.min(array)
_.minBy(array, [iteratee=_.identity])
均值:_.mean(array)
_.meanBy(array, [iteratee=_.identity])
总和:_.sum(array)
_.sumBy(array, [iteratee=_.identity])
原文链接:Lodash: 10 Javascript Utility Functions That You Should Probably Stop Rewriting
使用times可以让循环更简洁
// 1. Basic for loop.
for(var i = 0; i < 5; i++) {
// ....
}
// 2. Using Array's join and split methods
Array.apply(null, Array(5)).forEach(function(){
// ...
});
// Lodash
_.times(5, function(){
// ...
});
Take note: If your N is going to be non-trivial, please use a basic for loop or a reverse while loop for a much more performant iteration.
使用字符串来代替回调函数,这个功能是在惊艳!
// Fetch the name of the first pet from each owner
var ownerArr = [{
"owner": "Colin",
"pets": [{"name":"dog1"}, {"name": "dog2"}]
}, {
"owner": "John",
"pets": [{"name":"dog3"}, {"name": "dog4"}]
}];
// Array's map method.
ownerArr.map(function(owner){
return owner.pets[0].name;
});
// Lodash
_.map(ownerArr, 'pets[0].name');
先来看看uniqueId
函数:Generates a unique ID. If prefix is given, the ID is appended to it.
我们要创建一个初始值不同、长度为 6 的数组,其中 _.uniqueId 方法用于生成独一无二的标识符(递增的数字,在程序运行期间保持独一无二)。
// Create an array of length 6 and populate them with unique values. The value must be prefix with "ball_".
// eg. [ball_0, ball_1, ball_2, ball_3, ball_4, ball_5]
// Array's map method.
Array.apply(null, Array(6)).map(function(item, index){
return "ball_" + index;
});
// Lodash
_.times(6, _.uniqueId.bind(null, 'ball_'));
JavaScript 没有直接提供深拷贝的函数,但我们可以用其他函数来模拟,比如 JSON.parse(JSON.stringify(objectToClone)),但这种方法要求对象中的属性值不能是函数。Lodash 中的 _.cloneDeep 函数封装了深拷贝的逻辑,用起来更加简洁。
var objA = {
"name": "colin"
}
// Normal method? Too long. See Stackoverflow for solution: http://stackoverflow.com/questions/4459928/how-to-deep-clone-in-javascript
// Lodash
var objB = _.cloneDeep(objA);
objB === objA // false
// Get a random number between 15 and 20.
// Naive utility method
function getRandomNumber(min, max){
return Math.floor(Math.random() * (max - min + 1)) + min;
}
getRandomNumber(15, 20);
// Lodash
_.random(15, 20);
_.assign 是浅拷贝,和 ES6 新增的 Ojbect.assign 函数功能一致(建议优先使用 Object.assign)。
// Adding extend function to Object.prototype
Object.prototype.extend = function(obj) {
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
this[i] = obj[i];
}
}
};
var objA = {"name": "colin", "car": "suzuki"};
var objB = {"name": "james", "age": 17};
objA.extend(objB);
objA; // {"name": "james", "age": 17, "car": "suzuki"};
// Lodash
_.assign(objA, objB);
// Naive method: Remove an array of keys from object
Object.prototype.remove = function(arr) {
var that = this;
arr.forEach(function(key){
delete(that[key]);
});
};
var objA = {"name": "colin", "car": "suzuki", "age": 17};
objA.remove(['car', 'age']);
objA; // {"name": "colin"}
// Lodash
objA = _.omit(objA, ['car', 'age']); // {"name": "colin"}
大多数情况下,Lodash 所提供的辅助函数都会比原生的函数更贴近开发需求。在上面的代码中,开发者可以使用数组、字符串以及函数的方式筛选对象的属性,并且最终会返回一个新的对象,中间执行筛选时不会对旧对象产生影响。
var luckyDraw = ["Colin", "John", "James", "Lily", "Mary"];
function pickRandomPerson(luckyDraw){
var index = Math.floor(Math.random() * (luckyDraw.length -1));
return luckyDraw[index];
}
pickRandomPerson(luckyDraw); // John
// Lodash
_.sample(luckyDraw); // Colin
// Lodash - Getting 2 random item
_.sample(luckyDraw, 2); // ['John','Lily']
var luckyDraw = ["Colin", "John", "James", "Lily", "Mary"];
function pickRandomPerson(luckyDraw){
var index = Math.floor(Math.random() * (luckyDraw.length));
return luckyDraw[index];
}
pickRandomPerson(luckyDraw); // John
// Lodash
_.sample(luckyDraw); // Colin
// Using try-catch to handle the JSON.parse error
function parse(str){
try {
return JSON.parse(str);
}
catch(e) {
return false;
}
}
// With Lodash
function parseLodash(str){
return _.attempt(JSON.parse.bind(null, str));
}
parse('a'); // false
parseLodash('a'); // Return an error object
parse('{"name": "colin"}'); // Return {"name": "colin"}
parseLodash('{"name": "colin"}'); // Return {"name": "colin"}