1. 程式人生 > >redux原理——ruduce函式和compose函式

redux原理——ruduce函式和compose函式

reduce()合併函式核心:每次的返回值是一個函式,再用該函式去執行下一個陣列元素(陣列元素先執行傳入引數返回)

講redux之前首先要理解一個函式-----reduce()

語法
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

引數說明:
一、function(total,currentValue, index,arr)	必需。用於執行每個陣列元素的函式。
    函式引數:
    total	必需。初始值, 或者計算結束後的返回值。
    currentValue	必需。當前元素
    currentIndex	可選。當前元素的索引
    arr	可選。當前元素所屬的陣列物件。

二、initialValue	可選。傳遞給函式的初始值

reduce()函式有兩種用法,一般我們只用到了第一種,即累加(這裡不再舉例)

   reduce() 方法接收一個函式作為累加器,陣列中的每個值(從左到右)開始縮減,最終計算為一個值。

還有一種比較高階的用法:

  reduce() 可以作為一個高階函式,用於函式的 compose。

注:意思就是寫個函式 能將多個函式進行組合成一個函式,就是一元鏈式函式

注意: reduce() 對於空陣列是不會執行回撥函式的。

例子:這裡想到了陣列的reduce()函式

實現思路:要想實現一個這樣的函式,肯定是需要有一個遍歷的過程,一個函式的執行結果是另一個函式的引數,那這樣就需要有個累計的過程,綜合以上2點,想到陣列中有個reduce函式。這裡我們來看看reduce函式

接下來實現:chained函式

function chained(funcs) {
  return function(input){
    return funcs.reduce(function(input, fn){ return fn(input) }, input);
  }
}

chained([f3,f2,f1])(2) //呼叫 

函式解析:分為以下4個步驟解析

chained函式入參funcs 函式陣列  返回值:入參為input的函式(這裡稱為鏈式回撥函式

鏈式回撥函式:入參:input 初始值  返回值:reduce()函式 funcs 函式陣列 執行reduce()函式

reduce函式:入參:計算函式和初始值

計算函式:function(input, fn){ return fn(input) }  

                  首次入參:input輸入值  fancs陣列的第一個元素 fn1

                  二次入參:fn1(input)執行後返回值  fancs陣列的第一個元素 fn1

                  ...以此類推,知道fancs的陣列元素全部參與執行

抽象理解:reduce 英文意思:減少;縮小

    A.reduce(function(total, currentValue, currentIndex, arr), initialValue) 可以理解為逐漸減少陣列A的元素,減少執行該過程是傳給回撥函式,用作新的入參,而減少後變為回撥函式的另一個入參(即total返回值)

陣列A元素變化示意圖:元素 ====> 入參 ====>返回值 ====> 入參 ====>……====>最終合成結果

——————————————————————————————————————————————————————

compose函式:函式原始碼參見:https://github.com/reduxjs/redux/blob/v3.7.2/src/compose.js

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) => b(a(...args)))  //從左到右
}

將上面的寫法轉換為es5:

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) => b(a(...args)))

  //下面函式是返回的compose函式
  return funcs.reduce(
    
    //下面返回函式是reduce的回撥函式 接收 入參 a, b 
    //a為fn1 ,b為fn2(沒有傳入初始值)
    function(a,b){

      //下面返回函式是reduce的回撥函式實際執行函式
      return function(...args){ //這裡...args指的是compose函式傳入的引數
         var transferVal = a(...args)
         return b(transferVal)
      }
    }
  )
}

chained([f3,f2,f1])(2) //呼叫

執行過程說明:

我們一步一步分解一下, funcs 初始化的值為 funcs = [fn1,fn2,fn3], reduce執行

   第一步時 

  a = fn1

  b = fn2 

      ...args = 2

       b(a(2)) = fn2(fn1(2))

  (2) => b(a(2))   = (2) = > fn2(fn1(2))

第二步時

      a =  (2) = > fn2(fn1(2))  // 避免和後面混淆,rest引數名修改為  ag

      b = fn3

      b(a(...args)) = fn3( a(...args) )  = fn3(fn2(    fn1(...args)   ))  // 這一步是關鍵,a(...args)執行後作為b函式的入參,也就是 ...ag = fn3(...args)

   (...args) => b(a(...args))   = (...args) = > fn3(fn2(fn1(...args))) 

所以最後返回的就是這樣的一個函式  (...args) = > fn3(fn2(fn1(...args))) 

reduce()合併函式核心:每次的返回值是一個函式,再用該函式去執行下一個陣列元素(陣列元素先執行傳入引數返回)

說明:這裡是從左到右

從右到左寫為 funcs.reduce((a, b) => (...args) => a(b(...args)))