如何在函数数组上执行Javascript`reduce'实现函数组合?

问题描述 投票:-1回答:3

我在redux compose函数中遇到了这种模式。我仍然不明白在下面的例子中,如何从最后一个开始而不是从第一个开始评估函数:

function f2(a) {
  return a + a;
}
function f3(a) {
  return a + a + a;
}
function f4(a) {
  return a + a + a + a;
}
function f5(a) {
  return a + a + a + a + a;
}

function compose(...funcs) {
  return funcs.reduce(function x(a, b) {
    return function y(...args) {
      const temp = a(b(...args));
      return temp;
    };
  });
}

const composedFunction = compose(f2, f3, f4, f5);
const result = composedFunction(2);

在第一次reduce迭代中,累加器是f2所以我们将获得f2(f3(2))=12。在下一次迭代中,我们将调用f4(12)=48。在最后一次迭代中,我们将调用f5(48)=240。所以评估顺序是f5(f4(f2(f3(2))))。但是使用console.log我看到评估顺序是f2(f3(f4(f5(2)))),巧合也是240。

据我所知,为所有数组元素调用函数y所以为什么只有最后一个函数得到2作为参数?

javascript functional-programming evaluation
3个回答
2
投票

让我们通过一个非常简单的示例逐步完成代码:

 compose(f2, f3, f4)

由于没有初始值传递给reduce,它将从数组的第一个(f2)和第二个(f3)值开始并用它调用回调,x被调用af2bf3。现在x什么都不做,它只返回可以通过闭包访问a和b的函数y

Reduce现在将继续到第三个元素,第一个参数是前一个回调的结果(关闭的y),第二个参数是f4。现在再次调用x,并在y上创建另一个闭包,y从整个函数中获取最终返回。

如果我们试图想象这样关闭的函数,它将是:

 y { // closure of y
  a -> y { // a references another closure of y
    a -> f3,
    b -> f2
  },
  b -> f4
}

现在你调用封闭的y并将2传递给它,这将调用bf4)并将结果传递给调用a(关闭y)。

 a         (  b(...args))   
 y { ... } (  f4(2) )

现在关闭y会做同样的事情:

 a (  b ( ...args))
 f2( f3( f4( 2 ) ) )

提示:有时很难跟踪关闭的值,因此控制台为您提供了很好的实用程序来跟踪它们:在控制台“调试器”选项卡中打开代码,单击函数调用的行号附加断点,然后再次运行代码,只要达到断点,执行就会产生,并且您可以看到所有变量的值(包括已关闭的变量)。


1
投票

reduce不是调用函数f2,f3,f3,f5,而是从那些函数创建函数。这是每次迭代中累加器的值。请注意,该值是function,而不是执行该函数的结果。

1:a = f2; b = f3;返回值(NOT TEMP但函数y)= f2(f3(... args))

2:a(prev返回值)= f2(f3(... args)); b = f4;返回值= f2(f3(f4(... args)))

等等....


1
投票

撰写函数可以重写为:

function compose(...funcs) {
  return funcs.reduce(function (a, b) {
    return function (arg) {
      const temp = a(b(arg));
      return temp;
    };
  });
}

在第一次迭代之后,作为下一个累加器传入的返回函数是:

function (arg) {       // R1
  return f2(f3(arg));

}

在第二次迭代之后,作为下一个累加器传入的返回函数是:

function (arg) {       // R2
  return R1(f4(arg));

}

最后,分配给composedFunction的返回函数是:

function (arg) {       // composedFunction
  return R2(f5(arg));

}

所以运行composedFunction(2)并回到链上:

f5(2) returns 10

R2(10) returns R1(f4(10))
which is       R1(40)

R1(40) returns f2(f3(40))
which is   f2(120)
which is   240

希望这足够了。

它可以作为单个调用编写为:

function composedFunction(arg) {
  return f2(f3(f4(f5(arg))));
}
© www.soinside.com 2019 - 2024. All rights reserved.