Redux源碼(二) —— compose.js

Source Time

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
複製代碼

Analysis

須要說明的是,compose函數的存在實際上是服務於中間件的,即當咱們使用applyMiddleware實現功能加強的背後,其實就是利用了compose函數將這多個加強函數進行合理的組合。javascript

首先,compose函數利用了es6的rest參數,將多個類型爲函數的參數收集到一個叫做funcs的數組中,而後進行進一步邏輯判斷,最終結果都會是返回一個函數,保證輸入輸出。java

  1. 當funcs數組中沒有函數,即爲一個空數組時,傳入什麼,傳出什麼,沒有操做。
  2. 當funcs數組中有一個函數時,返回這個函數。
  3. 有意思的是當有多個函數的時候,funcs會調用reduce方法,將多個函數嵌套。

來用例子說話吧:es6

// 初始數據
let data = 1;
// 加1函數
const add1 = v => v + 1;
// 乘2函數
const multi2 = v => v * 2;

// 1. compose沒有參數
const func1 = compose();
func1(data); // -> 1

// 2. compose有一個參數,爲add1
const func2 = compose(add1);
func2(data); // -> 2,運算順序爲 1 + 1

// 3. compose有兩個參數,順序依次爲add1與multi2
const func3 = compose(add1, multi2);
func3(data); // -> 3,運算順序爲 1 * 2 + 1

// 4. compose有兩個參數,順序依次爲multi2與add1
const func4 = compose(multi2, add1);
func4(data); // -> 4,運算順序爲 (1 + 1) * 2
複製代碼

這裏重點關注一下func3func4能夠看出,接受參數相同可是順序不一樣,也會致使結果的不一樣,很明顯,越是在後面的函數,執行的次序越靠前,從源碼中的a(b(...args))也能夠獲得印證。redux

以上其實就是redux中間件的基本實現原理,關於中間件,咱們後續再說。數組

Currying

聊完了compose這個組合函數,順便來聊一下柯里化這個概念吧,由於這個概念在你編寫本身的中間件的時候可能會涉及到,下面是來自於百度百科的解釋:app

在計算機科學中,柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,而且返回接受餘下的參數且返回結果的新函數的技術。函數

若是須要舉例,那麼也很簡單,就像這樣子:post

// 如今有個add函數接受兩個參數a、b,並返回a + b
const add = (a, b) => a + b;
add(1, 2); // -> 3

// 如今用柯里化的思想來實現一下
const addByCurrying = a => b => a + b;
addByCurrying(1)(2); // -> 3
複製代碼

能夠看到其實使用柯里化就是將本來接受多個參數的函數變爲一次只接受一個參數,並返回一個新的函數用來處理剩餘的函數,就像是add改寫爲addByCurrying後,實現一個a+b實際上是利用了兩個函數調用完成的,第一次接受1,第二次接受2。spa

講完了柯里化的含義,那麼爲何要費勁套這麼多層去實現一個a+b?那確定是有他的好處的,想了解具體的就移步這裏——詳解JS函數柯里化,感受這篇文章中寫的很清楚了。rest

All

相關文章
相關標籤/搜索