函数式编程-函数的柯里化

本文最后更新于:2022年4月22日 上午

函数的柯里化的实现,以及 Vueredux-chunk 中柯里化的体现

在函数式编程中,函数的柯里化有利于我们将一个合理的组织代码,虽然不理解这个概念也不会影响编码,但是理解的这个概念,可以编写复用性更高,可维护性更好的代码

计算机科学中,柯里化 (英语:Currying),又译为卡瑞化加里化 ,是把接受多个参数函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

JavaScript 中柯里化的实现

function currying(fn) {
  function innerCurrying(...args) {

    // 如果形参的个数大于等于函数需要的参数,则直接调用函数
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      // 如果参数不够,则返回一个新的函数,用来接收剩余的参数,在函数内部递归的调用自身,直到形参的个数达到要求
      return function (...surplusArgs) {
        return innerCurrying.apply(this, [...args, ...surplusArgs]);
      };
    }
  }
  return innerCurrying;
} 

function foo(param1, param2, param3) {
  return param1 + param2 + param3;
}

// 柯里化之后的函数
const newFn = currying(foo);

console.log(newFn(10)(20)(30));  // 60
console.log(newFn(10, 20)(30));  // 60
console.log(newFn(10)(20, 30));  // 60
console.log(foo(10, 20, 30));    // 60

参数不确定的情况

函数的组合

const add1 = (num) => num + 1;
const mul2 = (num) => num * 2;
const div3 = (num) => num / 3;

const compose = (...funcs) => {
  return (value) => {
    return funcs.reduceRight((prev, next) => next(prev), value);
  };
};

const operate = compose(div3, mul2, add1);
const result = operate(1);
console.log('result:', result); // 1.333333333

使用 promise 改写函数的组合

const add1 = (num) => num + 1;
const mul2 = (num) => num * 2;
const div3 = (num) => num / 3;

const compose = (...fns) => {
  return (num) => fns.reduceRight((promise, fn) => promise.then(fn), Promise.resolve(num));
};

const operate = compose(div3, mul2, add1);
const result = operate(1);

result.then((res) => {
  console.log('promise result:', res); // 1.333333333
});

Vuejs 源码中 柯里化的应用

Vue3 后,我们创建应用的方式都变成了类似于以下的方式,从 vue 中导出 createApp 然后通过 createApp 来注册整个应用

import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');

createApp 源码

createApp 的源码位于 目录packages\runtime-core\src\renderer.tsbaseCreateRenderer 函数下,可以看到,该函数最终返回以下几个内容

createApp 是通过 createAppAPI函数返回的函数

return {
  render,
  hydrate,
  createApp: createAppAPI(render, hydrate)
}

createAppAPI 中,接受一个 render, hydrate,然后返回 createApp,我们知道vue在渲染时,最主要是通过调用 render 函数来进行渲染的,所以如此做的原因是,在进行一些跨端渲染的时候,例如小程序端,开发者可以自定义实现 render

export function createAppAPI<HostElement>(
  render: RootRenderFunction,
  hydrate?: RootHydrateFunction
): CreateAppFunction<HostElement> {
  return function createApp(rootComponent, rootProps = null) {
    ... 省略
  }
}

redux-chunk 中 柯里化的体现

在 redux-chunk 源码中也有函数柯里化的体现

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;