JavaScript函數式編程之函子

函子(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的時候始終返回的是一個函子,但是

推薦閱讀