JavaScript函数式编程学习笔记
2020/08/06
一、函数式编程概念简介
函数与方法的区别
函数是一段可以通过其名称被调用的代码
方法是一段必须通过其名称及其关联对象的名称被调用的代码
函数的引用透明性
所有的函数对于相同的输入都会返回相同的值
可以用值替换函数
函数式编程主张声明式编程和编写抽象的代码
命令式遍历数组
声明式遍历数组
纯函数
纯函数产生可测试的代码
给定输入就会返回相同输出的函数,遵循引用透明性;不应该依赖外部变量,也不应该改变外部变量
管道与组合
纯函数应该只做一件事情
举一个linux命令的例子:我们想要在一个文件中找到一个字符串并统计它的出现次数:
上面的命令通过组合多个函数解决了这个问题,组合不是linux命令独有的,但他是函数式编程的核心,也叫作函数式组合(Funtional Composition)
二、高阶函数
高阶函数是接收函数作为参数并且/或者返回函数作为输出的函数(Higher-Order functions HOC)
三、闭包和高阶函数
当innerFn被return的时候为他设置作用域, 返回函数的引用被存储在closureFn里面
四、柯里化和偏应用
柯里化:吧一个多参数函数转换成一个嵌套的一元函数的过程
处理两个参数的柯里化函数
柯里化的使用场景/优点如下
- 参数复用:柯里化可以让我们固定一部分参数,生成一个新的函数,这样子后续调用这个新函数就不用再次提供这些参数了。
- 延迟计算:通过柯里化,我们可以创建一系列的函数调用链,每一步返回一个新的函数,直至所有的参数被提供之后,才执行原始函数的计算。
- 功能分解:柯里化有助于将复杂的函数分解为能够处理一部分功能的简单函数,这些简单函数易于测试和维护。
- 动态生成函数:可以根据柯里化得到的中间函数生成具有特定功能的函数,而无需对每种情况都编写独立的函数定义。
柯里化实战:在数组中寻找数字
Partial Application 偏应用,颠倒参数的传递顺序
将回调函数和时间参数调换
偏函数定义:
五、组合(函数组合)和管道(Composition and Pipelines)
UNIX哲学:
- 每个程序只做好一件事情,如果要添加新功能,请重新构建而不是在复杂的旧程序中添加新功能
- 每个程序的输出应该是另一个尚未可知程序的输入
接收两个参数的compose函数的实现:
接收n个参数:
六、函子Functor
函子是一个普通对象,它实现了map函数,用map操作对象值的时候生成一个新对象
换句话说:函子是一个实现了map方法的对象
用Maybe和Either函子处理错误
Maybe函子
不足:不知道map函数在哪一步出错了
Either函子
七、单子Monad
单子也是一种函子
通过join返回maybe对象里面的value值,脱掉了Maybe对象的外衣
八、异步编程Generator
Generator基础
创建一个Generator
使用它:
那么如何得到里面的value呢?可以使用next()方法
如果我们调用两次next方法呢?
yield关键字
带有yield关键字的G都会以惰性求值的方式进行,也就是说,代码直到调用的时候才会执行
Generator的值:
Generator里面有很多值,我们如何知道何时停止调用next方法呢?
每次对next函数的调用都会返回一个对象
done是一个可以判断Generator序列是否被完全消费的属性
用循环遍历Generator
给 Generator传递值
使用setTimeout的例子
调用main函数,并遇到第一个yield语句,进入了暂停模式,但在暂停之前,他调用了getDataOne函数,
一秒钟之后setTimeout的回调会执行generator.next(‘dummy data one’),yield语句将会返回’dummy data one’,dataOneb变成’dummy data one’
然后会执行
let dataTwo = yield getDataTwo();
执行方式和之前一样
真实的例子:
上面的例子会造成回调地狱,用Generator来改写可以简化一下: