函数科里化的一些实现

2019/07/14 bug

函数科里化指的把一个函数从接受多个参数转化为接受一个参数,并且返回接受剩下函数的函数。
科里化主要有三个作用:1.参数复用; 2.提前返回; 3.延迟计算/运行

简单的示例

const add = (x, y, z) => x + y + z  
const addCurry = currying(add)  
console.log(addCurry(1)(2)(3) === add(1, 2, 3)) // true  
console.log(addCurry(1, 2)(3) === add(1, 2, 3)) // true  

在上面的示例里 add 函数本来是接受三个参数的,进过currying函数包装后,可以一个或者多个个参数,当参数满足一定的条件之后,再进行计算。

简单实现

函数的前两个参数为要被科里化的函数,总的接受参数的长度,剩余的参数则全部作为要被科里化函数的参数。总的逻辑是,当接受参数的数量大于函数可接受的参数或者自定义参数时,直接掉用该函数,否则递归调用 currying 等待外部继续调用。

const currying = (fn, arglen = fn.length, ...rest) =>  
                 arglen <= rest.length ?  
                 fn(...rest): currying.bind(null, fn, arglen ,...rest)  

科里化在 redux-thunk 里的应用

// redux-thunk 源码  
function createThunkMiddleware(extraArgument) {  
  return ({ dispatch, getState }) => next => action => {  
    if (typeof action === 'function') {  
      return action(dispatch, getState, extraArgument);  
    }  

    return next(action);  
  };  
}  

const thunk = createThunkMiddleware();  
thunk.withExtraArgument = createThunkMiddleware;  

export default thunk;  

可以看到 createThunkMiddleware 每执行一次都会返回一个函数,直到最后接收 action 时才真正返回了结果。
从 redux 的源码里可以看到是怎么调用这个函数的。

// redux applyMiddleware  

export default function applyMiddleware(...middlewares) {  
  return createStore => (...args) => {  
    const store = createStore(...args)  
    let dispatch = () => {  
      throw new Error(  
        'Dispatching while constructing your middleware is not allowed. ' +  
          'Other middleware would not be applied to this dispatch.'  
      )  
    }  

    const middlewareAPI = {  
      getState: store.getState,  
      dispatch: (...args) => dispatch(...args)  
    }  
    const chain = middlewares.map(middleware => middleware(middlewareAPI))  
    dispatch = compose(...chain)(store.dispatch)  

    return {  
      ...store,  
      dispatch  
    }  
  }  
}  

createThunkMiddleware 是一个中间件,作为 applyMiddleware 的入参 middlewares 传入。
第一次调用函数传入了middlewareAPI, 第二次则是在 compose 函数里调用,传入了store.dispatch,最后则是我们在实际的状态管理时,action不是函数 dispath({type:’xxx’}) 直接同步分发 action,action 时函数则调用 action,来实现异步调用 action。

Search

    Table of Contents