函数科里化指的把一个函数从接受多个参数转化为接受一个参数,并且返回接受剩下函数的函数。
科里化主要有三个作用: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。