函子(Functor)函子是一个特殊的容器,通过一个普通对象来实现,该对象具有map
方法,map
方法可以运行一个函数对值进行处理(变形关系),容器
包含值和值变形关系(这个变形关系就是函数) 。函数式编程中解决副作用的存在
- 函数式编程的运算不直接操作值,,而是由函子完成
- 函子就是一个实现了
map
契约的对象 - 我们可以把函子想象成一个盒子,盒子里面封装了一个值
- 想要处理盒子中的值,我们需要给盒子的
map
方法传递一个处理值的函数(纯函数),由这个函数来对值进行处理 - 最终map方法返回一个包含新值所在的盒子(函子)
// functor 函子class Container {constructor (value) {// 函子内部保存这个值 。下划线是不想外部访问this._value = https://www.huyubaike.com/biancheng/value}// map 方法接收一个处理值的函数map (fn) {return new Container(fn(this._value))}}
此时就已经创建了一个函子但是这是面向对象的方式来创建的 , 换成用函数式编程来写一个函子class Container {constructor (value) {this._value = https://www.huyubaike.com/biancheng/value}map (fn) {return Container.of(fn(this._value))}static of (value) {return new Container(value)}}let x = Container.of(5).map(x => x + 1).map(x => x - 1)
但是这个函子还是存在一些问题,比如空值的时候就会报错, 会让我们的函子变的不纯,我们需要去拦截空值错误,我们创建一个方法去判断是否为空值,如果是控制我们直接返回一个空值的函子,如果有值再去处理,这个时候就需要使用MayBe
函子let x = Container.of(null).map(x => x + 1).map(x => x - 1)
MayBe 函子我们在编程的过程中可能会遇到很多错误,需要对这些错误做相应的处理,MayBe
函子的作用就是可以对外部的空值情况做处理(控制副作用在允许的范围)// MayBe 函子class MayBe {constructor (value) {this._value = https://www.huyubaike.com/biancheng/value}map (fn) {return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))}isNothing () {return this._value === undefined || this._value === null}static of (value) {return new MayBe(value)}}let x = MayBe.of(null).map(x => x + 1).map(x => x - 1)console.log(x)
【JavaScript函数式编程之函子】这个时候我们已经能正常执行了,但是现在出现了空值的函子,但是我们不知道那个地方出现了空值,所以我们创建两个函子一个是正常的处理一个是出现错误情况处理,正常的就按照正常的方式创建,错误的是是否我们把map
方法改造一下让她不再处理回调函数,直接返回一个空值的MayBe
函子 , 这样就记录下了错误信息Eitcher
函子就是来处理这种情况的Either函子
Eitcher
类似于 if else
的处理 , 两者中的任何一个,异常会让函数变的不纯 , Eitcher
函子可以用来做异常处理// 因为是二选一 , 所以定义两个类 Left 和 Right// 记录错误信息的class Left {constructor (value) {this._value = https://www.huyubaike.com/biancheng/value}map (fn) {return this}static of (value) {return new Left(value)}}// 正常处理class Rgiht {constructor (value) {this._value = value}map (fn) {return Rgiht.of(fn(this._value))}static of (value) {return new Rgiht(value)}}function parseJson (str) {try {return Rgiht.of(JSON.parse(str))} catch (err) {return Left.of({ message: err.message })}}// 故意传入错误的数据let r = parseJson('{ name: "2" }')r.map(x => x.name.toUpperCase())console.log(r)
IO 函子IO
函子中的 _value
是一个函数, 这里把函数作为值来处理,IO 函子可以吧不纯的动作储存到_value
中,延迟这个不纯的操作(惰性执行),保证当前的操作是纯的 , 延迟把不纯的操作到调用者来处理const fp = require('lodash/fp')// IO 函子class IO {constructor (fn) {this._value = https://www.huyubaike.com/biancheng/fn}static of (value) {return new IO(function () {return value})}map (fn) {// 把当前的value 和传入的fn 函数组合成一个新的函数return new IO(fp.flowRight(fn, this._value))}}let r = IO.of(process).map(x => x.execPath)console.log(r)console.log(r._value())
IO 函子内部帮我们包装了一些函数,当我们传递函数的时候有可能这个函数是一个不纯的操作,不管这个函数纯与不纯,IO这个函子在执行的过程中它返回的这个结果始终是一个纯的操作,我们调用map
的时候始终返回的是一个函子,但是
推荐阅读
- Java函数式编程:一、函数式接口,lambda表达式和方法引用
- Vue3 SFC 和 TSX 方式调用子组件中的函数
- C++ 函数重载解析策略
- 原生JavaScript
- 钩子 【pytest官方文档】解读-插件开发之hooks 函数
- Java 最长公共前缀
- TCP和UDP的区别与联系以及网络字节序和主机字节序的转换函数实践
- Python函数-2V2
- MySQL 窗口函数
- JavaScript之无题之让人烦躁的模块化