Redux之compose

前言

在前面的基礎篇中咱們講解了createStore,bindActionCrearoes,combineReducers,在高級篇講解了applyMiddleware,致此redux相關的5個API就剩下一個compose,之因此把compose單獨寫一篇文章的緣由是由於是compose五個API裏惟一一個能單獨拿出來用的函數,就是函數式編程裏經常使用的組合函數,和 redux 自己沒有什麼多大關係。編程

compose的做用

把複雜的多函數嵌套調用,組合成純粹的函數調用,實現fn1(fn2(fn3(fn3(...args))))-->compose(fn1,fn2,fn3,fn4)(...args)這樣單純可讀的函數調用方式redux

舉例說明

let { compose } = require('redux');
function add1(str) {
  return '1' + str;
}
function add2(str) {
  return '2' + str;
}
function add3(str) {
  return '3' + str;
}
function add4(str) {
  return '4' + str;
}
let result = add1(add2(add3(add4('GuYan'))));
console.log(result); // '1234GuYan'
console.log(compose(add1,add2,add3,add4)('GuYan')); // '1234GuYan'
複製代碼
  • 執行分析
    • 【1】componse執行返回一個函數
    • 【2】componse的參數爲函數,返回的函數執行的時候實現了參數函數從右向左依次執行且每個參數函數執行的結果爲下一參數函數執行的入參,返回函數執行傳入的參數做爲第一次執行的參數函數的入參
  • 源碼實現
export default function compose(...funcs){
    // 若是參數沒傳,咱們本身內部實現一個函數返回
    if(funcs.lenth === 0){
        return arg => arg
    }
    // 若是傳入的參數只有一個函數,直接返回該函數
    if(funv.length === 1){
        retrun funcs[0]
    }
    /*若是傳入的參數爲多個函數,咱們爲了實現執行分析的【2】中的從右向左依次執行且每個參數函數執行的結果爲下一參數函數執行的入參,不難想到咱們數組中的遍歷方法, 沒錯就是reduce,可是reduce的遍歷是從左向右的,而咱們要實現的是從右向左執行, 因此咱們選用reduceRight來實現*/
    return funcs.reduceRight((a,b)=>(...args)=>b(a(...args)));
}
複製代碼

相信你們必定能夠讀懂前面的源碼實現了(若是有不明白的地方歡迎下方留言),可是細心的朋友們會發現真正的源碼的實現並非用reduceRight而是reduce,因此咱們結合源碼分析一遍咱們的例子中代碼的執行過程數組

源碼分析

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)))
}
複製代碼

上面代碼片斷是我直接從源碼中拷貝過來的,爲了方便講解咱們將箭頭函數修改爲普通函數形式,結果以下app

export default function compose(...funcs) {
  // 前兩種我就不復述了
  return funcs.reduce(function (a,b) {
    return function (...args) {
      return a(b(...args))
    }
  })
}
複製代碼
  • 結合示例
    • 第一次迭代
      • 參數:add1add2
      • 返回function fn1(...args1){return add1(add2(...args1))}
    • 第二次迭代
      • 參數:function fn1(...args1){return add1(add2(...args1))}add3
      • 返回:function fn2(...args2){return (function fn1(...args1){return add1(add2(...args1))})(add3(...args2))}
      function fn2(...args2) {
       return (function fn1(...args1) {
          return add1(add2(...args1))
        })(add3(...args2))
      }
      /* 源代碼執行的時候返回的是a執行傳入b執行返回的結構, 此時a是function fn1(...args1){return add1(add2(...args1))},b是add3; 因此我用一個讓function fn1(...args1){return add1(add2(...args1))}自執行傳入add3(...args2), 須要注意的是此時函數中的args1就是add3(...args2) */
      複製代碼
    • 第三次迭代
      • 參數:function fn2(...args2){return (function fn1(...args1){return add1(add2(...args1))})(add3(...args2))}add4
      • 返回:function fn3(...args3) {return (function fn2(...args2) {return (function fn1(...args1) {return add1(add2(...args1))})(add3(...args2))})(add4(...args3))}
      function fn3(...args3) {
          return (function fn2(...args2) {
              return (function fn1(...args1) {
                  return add1(add2(...args1))
                  })(add3(...args2))
              })(add4(...args3))
          }
      /* 此時a是function fn2(...args2){return (function fn1(...args1){return add1(add2(...args1))})(add3(...args2))},b是add4(...args3); * 如第二次迭代同樣咱們依據用一個自執行函數包裹a,且傳入參數`add4(...args3)` * 須要注意的是此時函數中的args2就是add4(...args3) */
      複製代碼
第幾回循環 a的值 b的值 返回的值
第一次 add1 add2 (...args1)=>(add1(add2(...args1)))
第二次 (...args1)=>(add1(add2(...args1))) add3 (...args2)=>((...args1)=>(add1(add2(...args1))))(add3(...args2))(...args2)=>add1(add2(add3(...args2)))
第三次 (...args)=>(add1(add2(add3(...args)))) add4 (...args3)=>((...args2)=>(add1(add2(add3(...args)))))(add4(...args3))(...args)=>add1(add2(add3(add4(...args))))
相關文章
相關標籤/搜索