3

欢迎关注redux源码分析系列文章:
redux源码分析之一:createStore.js
redux源码分析之二:combineReducers.js
redux源码分析之三:bindActionCreators.js
redux源码分析之四:compose.js
redux源码分析之五:applyMiddleware

redux的compose函数实在太精妙,总共才9行,真正的代码其实才1行,看下源文件代码如下:

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)))
}

但是,就是这最后一行代码,不仔细分析,实在难以理解,我写了注释如下:


export default function compose(...funcs) {
  //如果参数长度为0,则返回一个最简单的函数,即传入什么,就返回什么的函数
  if (funcs.length === 0) {
    return arg => arg
  }
  //如果参数长度为1,则将参数列表中的第一个函数作为返回值
  if (funcs.length === 1) {
    return funcs[0]
  }

  //如果参数长度大于1,则对funcs列表执行reduce函数,
  //reduce方法会将(...args) => a(b(...args))整体作为一个返回值,赋值给a变量,b是funcs数组中的下一个函数
  //一开始,a,是funcs数组中的第一个函数,b是funcs数组中第二个函数,每执行一次reduce操作,a会被reduce函数中的返回值重新赋值,
  // 而reduce函数的返回值刚刚好是一个函数,即a = (...args) => a(b(...args)),
  // 由于a就是一个函数,下一轮reduce,新的a函数又会把funcs中下一个函数b作为参数执行,并继续返回下一个a函数

  //比如funcs = [f1, f2, f3, f4], 执行流程如下
  // a1 = (...args) => f1(f2(...args))
  // a2 = (...args) => a1(f3(...args))
  // a3 = (...args) => a2(f4(...args))
  // 依次代入,则得到
  // a2 = (...args) => f1(f2(f3(...args)))
  // a3 = (...args) => f1(f2(f3(f4(...args))))
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

所以,这个compose函数执行后,返回值是另外一个函数,这个函数,其实只是做了一件事情:把一个函数数组,按照顺序,从数组最后向前按照顺序执行,并且,把前一个执行的函数返回值,作为下一个执行函数的入参。对,你没看错,就是这么简单!


Happi
244 声望6 粉丝