极客时间返利平台,你可以在上边通过山月的链接购买课程,并添加我的微信 (shanyue94) 领取返现。
每天晚上九点 B站讲解前端工程化直播,并解答相关问题。

# 如何实现 compose 函数,进行函数合成

更多描述

实现一个 compose 函数,进行函数合成,比如 redux 中的 compose,react 高阶组件连续调用时的 compose

const add10 = (x) => x + 10;
const mul10 = (x) => x * 10;
const add100 = (x) => x + 100;

// (10 + 100) * 10 + 10 = 1110
compose(add10, mul10, add100)(10);

Issue

欢迎在 Gtihub Issue 中回答此问题: Issue 182 (opens new window)

function compose() {

  let fns = [...arguments];

  return function() {
    let args = [...arguments];
    let result = fns.reduce((ret, fn) => {
      ret = fn.apply(this, ret);
      return Array.isArray(ret) ? ret : [ret];
    }, args);

    return result;
  }
}

let toUpperCase = (x) => x.toUpperCase();
let exclaim = (x) => x + '!';
let shout = compose(toUpperCase,exclaim);
let str = shout('hello world');
console.log(str);

第一次试着写,简单查了一下 compose 是什么意思,竟然拼凑出来了。请各位指正。 😄

看到一种新实现

function compose(...fns) {
  fns.reduce( (a, b) => (...args) => a(b(...args)));
}

Author

回答者: nieyao (opens new window)

const compose = (...fns) => (...params) => fns.reduce((prev, current) => current(prev), ...params);

实现一个从右向左(right to left)计算的组合函数:

const compose = (...fns) =>
  // 注意 f、g 的位置,如果实现从左到右计算,则置换顺序
  fns.reduce(
    (f, g) =>
      (...args) =>
        f(g(...args))
  );

跑一个示例

const add5 = (x) => x + 5;
const multiply = (x) => x * 10;
const multiply10AndAdd5 = compose(add5, multiply);
multiply10AndAdd5(10); // 105

Redux 中广泛使用了 compose 函数,其中的实现如下

export default function compose(...funcs: Function[]) {
  if (funcs.length === 0) {
    // infer the argument type so it is usable in inference down the line
    return <T>(arg: T) => arg;
  }

  if (funcs.length === 1) {
    return funcs[0];
  }

  return funcs.reduce(
    (a, b) =>
      (...args: any) =>
        a(b(...args))
  );
}

@nieyao params 应该置后,测试示例时没有通过

Author

回答者: nieyao (opens new window)

@nieyao params 应该置后,测试示例时没有通过

确实,忘了 compose 是从右往左执行的,那加个 reverse 好了。 const compose = (...fns) => (...params) => fns.reverse().reduce((prev, current) => current(prev), ...params) 或者用 reduceRight const compose = (...fns) => (...params) => fns.reduceRight((prev, current) => current(prev), ...params)

Author

回答者: Kiera569 (opens new window)

function compose(...fn) {
  return (...args) =>
    fn
      .reverse()
      .slice(1)
      .reduce((acc, cur) => cur(acc), fn[0](...args));
}
Last Updated: 11/27/2021, 10:11:48 AM