无所事事的样子开始了摸鱼的一天
函数组合
函数组合要满足结合律,即组合内的函数可以任意函数组合为一组 柯里化函数的参数要
const _ = require('lodash');
const split = _.curry((sep,str) => _.split(str,sep));
const join = _.curry((sep,arr) => _.join(arr,sep));
const f = _.flowRight(join('-'),_.toLower,split(' '));
console.log(f('HELLO WORLD'));
const log = v => {
console.log(v); // 调试用函数组合
return v;
}
const f = _.flowRight(join('-'),log,_.toLower,log,split(' '));
console.log(f('HELLO WORLD'));
const map = _curry(fn,arr) => _.map(arr,fn);
const f = _.flowRight(join('-'),log,map(_.toLower),split(' '));
console.log(f('HELLO WORLD'));
const trace = _.curry((tag,v)=> {
console.log(tag , v); // log函数改造
return v;
});
const f = _.flowRight(join('-'),trace('map 之后'),map(_.toLower),trace('split 之后'),split(' '));
lodash的fp模块,函数优先,数据置后 lodash模块,数据优先,函数置后 lodash模块的使用的时候需要自己把代码柯里化处理,fp模块则不用
const fp = require('lodash/fp');
const f = fp.flowRight(fp.join('-'),fp.map(fp.toLower),fp.split(' '));
console.log(f('HELLO WORLD'));
Point Free
- 不需要指明处理的数据
- 只需要合成运算过程
- 需要定义一些基本的运算函数
普通模式
function f(word){
return word.toLowerCase().replace(/\s+/g,'_');
}
Point Free模式
const fp = require('lodash/fp');
const f = fp.flowRight(fp.replace(/\s+/g,'_'),fp.toLower);
// 函数组合的过程中不需要指明处理的数据
// world wild web ===> W. W. W
const fp = require('lodash/fp');
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.first,fp.toUpper)),fp.split(' '))
// 每次map都会遍历一次数组,减少map次数可以优化
console.log(firstLetterToUpper('world wild web'))
函子(我是老子)
- 容器:包含值和值的变形关系(这个关系就是函数)
- 函子:是一个特殊的容器,通过普通的对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理
一个盒子,对外公布一个map方法,用来接受参数,这个参数就是一个对值进行处理的函数
class Container{
constructor (value){
this._value = value;
}
map(fn){
return Container.of(fn(this._value));
}
static of(value){
return new Container(value);
}
}
let r = new Container(666)
.map(x => x*x) // 返回的还是一个函子,可以继续链式调用了呢
.map(x => x++)
console.log(r); // 返回的是一个函子,而不是value
let r = Container.of(666)
.map(x => x*x) // 返回的还是一个函子,可以继续链式调用了呢
.map(x => {
console.log(x); // 永远不对外公布函子内的值,只在map内操作
})
- 函数式编程的运算不直接操作值,而是有函子完成
- 函子就是实现了一个map方法的对象
- 函子可以看做一个黑盒子,黑盒子内封装了值
- 处理黑盒子里的值,需要给黑盒子的map方法传递一个处理值的函数,由传递过来的函数处理值
- map方法还是会返回一个包含处理过的值的一个函子
MayBe函子
class MayBe{
constructor (value){
this._value = value;
}
map(fn){
return isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value));
}
static of(value){
return new MayBe(value);
}
isNothing(){
return this._value ===null||this._value === undefined ;
}
}
let r = MayBe.of('hello')
.map(x => x.toUpperCase())
.map(x => null) // 某一时刻传入null了,在最终结果的时候无法得知
.map(x => x.split(' '))
Either函子
类似与if...else...的解决MayBe函子出现的null
class left {
static of(value) {
return new left(value)
}
constructor(value) {
this.value = value
}
map(fn) {
return this
}
}
class right {
static of(value) {
return new right(value)
}
constructor(value) {
this.value = value
}
map(fn) {
return right.of(fn(this.value))
}
}
function parseJSON(str) {
try {
return right.of(JSON.parse(str))
} catch (e) {
return left.of({error: e.message})
}
}
let res = parseJSON('{"name":"asd"}')
.map((res) => {
return res.name.toUpperCase()
})
console.log(res)
—————————————————————————————————————————————————————— 我这废柴