1. 概念
- 纯函数和柯里化很容易写出洋葱代码 h(g(f(x))) ,函数组合可以让我们把细粒度的函数重新组合生成一个新的函数
- 如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数
- 函数就像是数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结果
- (当我们遇到函数比较复杂时,可以把函数拆分成很多的小函数,此时多了中间过程产生的参数)
- 函数组合默认是从右到左执行
- 案例 ```javascript // 函数组合演示 // 获取数组最后一个值
// 把函数进行组合 注意的是 函数组合默认是从右到左执行 function compose(f, g) { return function (value) { return f(g(value)) } } // 反转 function reverse(array){ return array.reverse(); } // 取第一个元素 function first(array){ return array[0]; }
const last = compose(first,reverse); console.log(last([“a”,”b”,”c”,”d”]));
<a name="SUUgx"></a>
## 2. lodash中的组合函数
<a name="T7uHI"></a>
#### 1.lodash 中组合函数 flow() 或者 flowRight(),他们都可以组合多个函数
flow() 是从左到右运行<br />flowRight() 是从右到左运行,使用的更多一些<br />案例:
```javascript
// lodash 中的组合函数 flowRight() 是从右到左运行
const _ = require('lodash')
// 翻转
const reverse = arr => arr.reverse()
// 求第一个元素
const first = arr => arr[0]
// 转大写
const toUpper = str => str.toUpperCase()
// 使用lodash中的flowRight 来进行组合函数
const fn = _.flowRight(toUpper,first,reverse);
console.log(fn(['one','tow','three']));
2.lodash_fp 模块
- 提供了实用的对函数式编程友好的方法
- 提供了不可变 auto-curried, iteratee-first, data-last 的方法
- fp中提供的方法都是柯里化的 如果有多个参数都是函数优先,数据滞后的
- 使用fp模块的示例 ```javascript // MEVER SAY DIE —-》nerver-say-die // fp中提供的方法都是柯里化的 如果有多个参数都是函数优先数据滞后的 const fp = require(‘lodash/fp’);
const fn = fp.flowRight(fp.join(‘-‘), fp.map(fp.toLower), fp.split(‘ ‘))
console.log(fn(‘MEVER SAY DIE’));
1. lodash和lodsh/fp模块中 map方法的区别
```javascript
// lodash和lodsh/fp模块中 map方法的区别
// lodash
// const _ = require('lodash');
// console.log(_.map(['23','8','10'],parseInt));
// // parseInt('23',0,array)
// // parseInt('8',1,array)
// // parseInt('10',2,array)
// //parseInt 的第二个参数其实是 转化为几进制
// // 23 0其实是10进制
// // 8 1进制没有 所以等于NaN
// // 10 二进制结果为2
// // 所以 结果为[ 23, NaN, 2 ]
// end
// lodsh/fp
const fp = require('lodash/fp');
console.log(fp.map(parseInt,['23','8','10']));
// end
3. 组合函数实现原理
// 模拟 lodash中的 组合函数
// 翻转
const reverse = arr => arr.reverse()
// 求第一个元素
const first = arr => arr[0]
// 转大写
const toUpper = str => str.toUpperCase()
// 模拟 lodash中的 flowRight 组合函数(从右到左运行)
function compose(...args) {
return function (value) {
/**
* reduce 为数组中的每一个元素依次执行回调函数
* reduce() 方法接收一个函数作为累加器,
* 数组中的每个值(从左到右)开始缩减,最终计算为一个值。
* reduce() 可以作为一个高阶函数,用于函数的 compose。
* 注意: reduce() 对于空数组是不会执行回调函数的。
* reduce(函数(total:必需。初始值, 或者计算结束后的返回值
* currentValue:必需。当前元素
* currentIndex:可选。当前元素的索引
* arr:可选。当前元素所属的数组对象。)
* ,初始值(可选))
*/
return args.reverse().reduce(function(acc,fn){
return fn(acc);
},value)
}
}
// ES6 箭头函数表示
// const compose = (...args) => value => args.reverse().reduce((acc,fn)=>fn(acc),value)
// 使用模拟的组合函数 来进行组合函数
const fn = compose(toUpper, first, reverse);
console.log(fn(['one', 'tow', 'three','aaaaa']));
4. 结合律(函数组合要满足的一个特点)
(a×b)×c=a×(b×c)
我们可以先把a和b组合 也可以先把b和c组合
结果是一样的
案例:
// lodash 中的组合函数 flowRight() 是从右到左运行
const _ = require('lodash')
// 使用lodash中的flowRight 来进行组合函数
const fn1 = _.flowRight(_.toUpper,_.first,_.reverse);
const fn2 = _.flowRight(_.flowRight(_.toUpper,_.first),_.reverse);
const fn3 = _.flowRight(_.toUpper,_.flowRight(_.first,_.reverse));
console.log(fn1(['one','tow','three']));
console.log(fn2(['one','tow','three']));
console.log(fn3(['one','tow','three']));
5. 调试
// 函数组合调试
// MEVER SAY DIE ---》nerver-say-die
const _ = require('lodash');
// 调试函数 打印然后把拿到的值再输出出去(打印会不清晰没有标记tag)
const log = v => {
console.log(v);
return v;
}
const trace = _.curry((tag, v) => {
console.log(tag, v);
return v
})
// 切割字符串柯里化
const split = _.curry((sep, str) => _.split(str, sep));
// 拼接柯里化
const join = _.curry((sep, array) => _.join(array, sep));
// map 对数组中的每个元素进行处理 柯里化
const map = _.curry((fn, arr) => _.map(arr, fn));
const fn = _.flowRight(join('-'), trace('map后'), map(_.toLower), trace('split后'), split(' '))
console.log(fn('MEVER SAY DIE'));
我们可以自己写一个调试函数trace 利用 函数组合中 上一个函数返回值传递给下一个参数 我们就可以从中获取到这个参数 从而进行调试
6. PointFree
概念
- 一种编程的风格,具体实现是函数的组合,他更抽象一些
- 我们可以把数据处理的过程定义成与数据无关的合成运算,不需要用到代表数据的那个参数,只要把简单的运算步骤合成到一起,在使用这种模式之前我们需要定义一些辅助的基本运算函数。
const fp = require(‘lodash/fp’) // replace字符串中用一些字符替换另一些字符 const f = fp.flowRight(fp.replace(/\s+/g, ‘_’), fp.toLower);
console.log(f(‘Hello world’));
```javascript
// point free
// world wild web => W. W. W
const fp = require('lodash/fp')
// replace字符串中用一些字符替换另一些字符
// const firstLetterToUpper = fp.flowRight(fp.join('. '),fp.map(fp.first),fp.map(fp.toUpper),fp.split(' '))
const firstLetterToUpper = fp.flowRight(fp.join('. '),fp.map(fp.flowRight(fp.toUpper,fp.first)),fp.split(' '))
console.log(firstLetterToUpper('world wild web'));