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))))
相关文章
相关标签/搜索