这个传递给 Javascripts reduce 的 compose 函数的执行流程是什么?

What is the flow of execution with this compose function passed into Javascripts reduce?

我只想知道 reduce 在下面代码的情况下是如何工作的(这是我上一个问题中由 Whosebug 用户提供的,我问这个问题是因为他的代码片段让我有更多的问题' 清理干净并且太长而无法放入评论部分)。函数数组被传递到 reducer 中。有一个在函数数组上运行的组合函数。根据我的理解,f 是累加器,g 是数组中的下一项。 reduce 的每个循环返回的内容成为下一个循环的累加器。如果没有将 initalValue 参数传递给 reduce,则数组中的第一项将用作初始累加器值。

const compose = (f, g, i) => (...args) =>  {
  console.log(i, g);
  console.log(i, f);
  return f(g(...args));
}

const f_xe = (x) => x + 'e', 
      f_xd = (x) => x + 'd', 
      f_xc = (x) => x + 'c',
      f_xy = (x, y) => x + y;

console.log([f_xe, f_xd, f_xc, f_xy].reduce(compose)('a','b'));

// 3 [Function: f_xy]
// 3 [Function]
// 2 [Function: f_xc]
// 2 [Function]
// 1 [Function: f_xd]
// 1 [Function: f_xe]
// abcde

我是这样想象的:

cycle #1:
f = f_xe
g = f_xd
return f(g(...args))
^ which is f_xe(f_xd('a', 'b'))

cycle #2:
f = what was returned previously
^^ which will be f_xe(f_xd('a', 'b'))

g = f_xc

return f(g(...args))
^^ which is f_xe(f_xd('a', 'b'))(f_xc('a', 'b'))

我已经知道这种思路是错误的,因为流程以封装的方式工作,就像这样:f_xe(f_xd((f_xc(f_xy('a', 'b'))))) 但为什么会这样。如果有人可以复杂地解释为什么它以这种方式包装并逐步分解 reduce 的每个循环,将不胜感激。我想知道的另一件事是,为什么 f 不尝试在第一个周期立即评估? f_xe(f_xd('a', 'b')) 当返回这段代码时,它不会尝试对其求值并产生错误,而不是继续处理数组中的下一项吗?相反,代码从数组中的最后一项开始计算,即使 compose 函数被指示从头开始应用。我确实理解为组合函数,最后一项将是 运行,然后依此类推,但是控制台日志语句不应该按从前到后的顺序 运行 吗?

同样,我知道我的思路与这个完全不同,但我希望如果我分享我的思路,有人可以将它推向正确的方向。感谢任何可以阐明这一点的人。

首先忘记 'a''b' 参数。重要的部分是

const f = [f_xe, f_xd, f_xc, f_xy].reduce(compose);

这是我们需要查看的内容,也是我们可以应用 reduce 定义的地方。 f('a','b')的电话稍后来。

展开reduce调用时,我们发现

const f = compose(compose(compose(f_xe, f_xd, 1), f_xc, 2), f_xy, 3);

(这实际上有点奇怪。我建议使用 reduceRight 来组合函数。同时传递识别函数作为累加器的初始值。)

现在我们可以扩展 compose 个调用:

const f1 = (...args) => {
  console.log(1, f_xe);
  console.log(1, f_xd);
  return f_xe(f_xd(...args));
}
const f2 = (...args) => {
  console.log(2, f1);
  console.log(2, f_xc);
  return f1(f_xc(...args));
}
const f3 = (...args) => {
  console.log(3, f2);
  console.log(3, f_xy);
  return f2(f_xy(...args));
}
const f = f3;

现在当您调用 f3('a', 'b') 时,您可以看到为什么日志发生“倒退”。

shouldn't the console log statements be ran in the order of first to last?

如果需要,最好将它们放在 compose 函数中,而不是放在 returns 的闭包中。试试

const compose = (f, g, i) =>  {
  console.log(i, g);
  console.log(i, f);
  return  (...args) => f(g(...args));
}