最近在学习JS函数式编程相关的内容,因而详细的翻看了Lodash的文档,感到别有洞天。这里把本身对一些API的使用和见解作个笔记记录下。css
例子:前端
_.head([1, 2, 3]); // → 1 _.last([1, 2, 3]); // → 3
分别能够抽取数组第一个元素的值和最后一个元素的值。咋看之下以为很无聊。可是跟下面两个结合起来就厉害。编程
例子:数组
_.tail([1, 2, 3]); // → [2, 3] _.initial([1, 2, 3]); // → [1, 2]
也如字面描述通常容易理解的函数。可是结合上面的两个函数就产生很大能量。数据结构
首先看一个针对数组尾部特殊化处理的例子:app
let names=['fred', 'barney', 'pebbles']; _.initial(names).join(', ') + (_.size(names) > 1 ? ', & ' : '') + _.last(names); // → 'fred, barney, & pebbles'
怎么样比简单的写for
+if else
优雅不少吧。接着咱们来看看递归求和:函数式编程
function sum(arr){ return _.head(arr) ? ( _.head(arr) + sum( _.tail(arr) ) ) : 0; }
Tips函数
1)其实好像数组均可以表现为性能
[a, [b, [c .....]]]
而后再将其扁平化的结果。 是否是?因此结合这四个函数,不少数组遍历的操做均可以改写成递归的方式。虽然性能可能略差,可是可读性反而更强了(并不是全部的递归都必定损耗性能,详细能够去了解下JIT优化)。学习
2)可是在ES6中,更推荐优先使用数组的解构。
例子:
_.zip(['fred', 'barney'], [30, 40]); // → [['fred', 30], ['barney', 40]]
_.zip(*array) 将几个数组按照位置组成新的数组,返回数组列表。这个方法就有点像SQL里面select两个列的状况。对重组数据结构很是有帮助。
既然lodash是个函数库,那有zip确定也有他的逆运算unzip。这里就不举例了。unzip其实能够看做对ES6数组解构的补充,应用的场景也是十分类似的。
这三个函数其实早就名声在外,就不举例了。列出来只是为了提醒,遍历集合可不只仅只有_.each。任什么时候候都优先考虑这些函数。
例子:
let users = [ { 'user': 'barney', 'active': true }, { 'user': 'fred', 'active': false } ]; _.every(users, { 'user': 'barney', 'active': false }); // → false _.some(users, ['active', false]); // → true
什么?看不懂?
_.every => && _.some => ||
懂了吧。其实一样也算是对_.each的扩充。还有他们都有条件短路的优化哦。
是函数柯里化的函数。不要问我为何不是库里化。什么是柯里化自行百度。
例子:
let abc = function(a, b, c) { return [a, b, c]; }; let curried = _.curry(abc); curried(1)(2)(3); // → [1, 2, 3] curried(1, 2)(3); // → [1, 2, 3] curried(1, 2, 3); // → [1, 2, 3] // Curried with placeholders. curried(1)(_, 3)(2); // → [1, 2, 3]
柯里化有3个常见做用:1. 参数复用;2. 构建高阶函数;3. 延迟计算。
参数复用的例子:
let parse = function(data, config){ …… return ……; }; let config = {}; let parseByConfig = _.curryRight(parse)(config);
如代码所示,这是一个数据解析函数,经过某些配置按照必定的规则去解析数据。若是在某个场景下参数配置都同样。那能够用柯里化先引入一个参数。而后再接收不一样的数据。这样就不用在每次调用时都引入一样的config参数。
剩下两个特性一个等会讲,一个不在本文讨论范围内。
部分函数,我习惯这么叫他,仍是先看例子。
let greet = function(greeting, name) { return greeting + ' ' + name; }; let sayHelloTo = _.partial(greet, 'hello'); sayHelloTo('fred'); // → 'hello fred' // Partially applied with placeholders. let greetFred = _.partial(greet, _, 'fred'); greetFred('hi'); // → 'hi fred' let greet = function(greeting, name) { return greeting + ' ' + name; }; let sayHelloTo = _.partial(greet, 'hello'); sayHelloTo('fred'); // → 'hello fred' // Partially applied with placeholders. let greetFred = _.partial(greet, _, 'fred'); greetFred('hi'); // → 'hi fred'
好像跟柯里化很像。是的,它其实就是柯里化的具体应用——构建高阶函数。_.curry会把一个函数转化成能够柯里化函数,而当这个柯里化函数接受了必定的参数后,它就变成了一个部分应用函数了。
这个是我认为的lodash中最有意思的方法。
$('div').css('color','red') .on('click', function(){}) .fadeIn();
做为一个合格的前端攻城狮,你对这个必定不陌生。它必定给你带来过不少美好的记忆。那咱们如何让这样一段优雅的代码应用到非DOM对象上呢。用_.chain
就好了。
_.head( _.map( _.sortBy('users', 'age'), function(o) { return `${o.user} is ${o.age}`; } ) ) _.chain(users) .sortBy('age') .map(function(o) { return o.user + ' is ' + o.age; }) .head() .value();
两段代码在作同样的事情。你更喜欢哪一个呢。不过要注意_.chain
最后的value。由于_.chain
用一个容器包装了你的对象,最后须要经过value返回出真正的值。若是不能理解,联想一下下面这段代码:
$('div')[0].classList
用jQuery选择器筛选到的是jQuery对象,而若是要调用真正的DOM对象的属性的话,还要用索引去调用它。
function square(n) { return n * n; } var addSquare = _.flow(_.add, square); addSquare(1, 2); // → 9
这一样是用来组合高阶函数的一个方法。若是用数学的角度去思考的话,就有点像, 把函数 f(), g(), 和h() 组合起来能够获得复合函数 f( g( h() ) )。