函數式編程(二)

高階函數

知足如下兩點的函數:javascript

  1. 函數能夠做爲參數被傳遞
  2. 函數能夠做爲返回值輸出

叫高階函數,很顯然js中的函數知足高階函數的條件。java

函數做爲參數:git

function pow(x) {
    return x * x;
}
const arr = [1, 2, 3];
const res = arr.map(pow);

函數做爲返回值:github

function getPrintFn() {
    function print(msg) {
        console.log(msg);
    }
    return print;
}

高階函數與函數式編程有什麼關係?經過上一篇咱們知道函數式編程採用純函數,那怎麼把不純的函數轉化爲一個純函數呢?經過把不純的操做包裝到一個函數中,再返回這個函數(即上面的例子),便可達到目的。編程

柯里化(curry)

只傳遞給函數一部分參數來調用它,讓它返回一個函數去處理剩下的參數。

特色:
接收單一參數,將更多的參數經過回調函數來搞定;
返回一個新函數,用於處理全部的想要傳入的參數;
須要利用call/apply與arguments對象收集參數;
返回的這個函數正是用來處理收集起來的參數;數組

function add(x, y) {
    return x + y;
}

// 柯里化
function add(x) {
    return function(y) {
        return x + y;
    }
}
const increment = add(1);
increment(2); // 3

當咱們談論純函數的時候,咱們說它們接受一個輸入返回一個輸出。curry 函數所作的正是這樣:每傳遞一個參數調用函數,就返回一個新函數處理剩餘的參數。這就是一個輸入對應一個輸出。curry函數適用於如下場景:網絡

  • 延遲執行:不斷的柯里化,累積傳入的參數,最後執行。
  • 固定易變因素:提早把易變因素,傳參固定下來,生成一個更明確的應用函數。最典型的表明應用,是bind函數用以固定this這個易變對象。

代碼組合(compose)

在函數式編程中,經過將一個個功能單一的純函數組合起來實現一個複雜的功能,就像樂高拼積木同樣,這種稱爲函數組合(代碼組合)。下面看一個例子:app

clipboard.png

最佳實踐是讓組合可重用。異步

函子

咱們知道,函數式編程實質是經過管道把數據在一系列純函數間傳遞,可是,控制流(control flow)、異常處理(error handling)、異步操做(asynchronous actions)和狀態(state)呢?還有更棘手的反作用(effects)呢?這些問題的解決就要引入函子的概念了。async

咱們首先定義一個容器,用來封裝數據

clipboard.png

函子封裝了數據和對數據的操做,functor 是實現了map函數並遵照一些特定規則的容器類型。

clipboard.png

把值裝進一個容器,並且只能使用 map 來處理它,這麼作的理由究竟是什麼呢?
讓容器本身去運用函數能給咱們帶來什麼好處?
Functor 是一個對於函數調用的抽象,咱們賦予容器本身去調用函數的能力。當 map 一個函數時,咱們讓容器本身來運行這個函數,這樣容器就能夠自由地選擇什麼時候何地如何操做這個函數,以至於擁有惰性求值、錯誤處理、異步調用等等很是牛掰的特性。

函子的類型

1.Maybe(處理null問題)
2.Either(if…else)
3.IO(IO、網絡請求、DOM)
4.Monad(嵌套問題)

Maybe

一種用來處理null和undefined問題的函子,避免繁瑣的手動判空操做

clipboard.png

Either

一種用來處理if…else問題的函子

clipboard.png

IO

經過返回一個獲取數據的函數來延遲IO的反作用,等調用者去執行有反作用的函數,
以保證獲取數據過程當中的無反作用特性

clipboard.png

Monad

monad 是能夠變扁(flatten)的實現了of方法的 functor

clipboard.png

總結

學習函數式編程,實際上就是學習函子的各類運算。因爲能夠把運算方法封裝在函子裏面,因此又衍生出各類不一樣類型的函子,有多少種運算,就有多少種函子。函數式編程就變成了運用不一樣的函子,解決實際問題。

參考文檔
https://github.com/xitu/gold-...
https://llh911001.gitbooks.io...

相關文章
相關標籤/搜索