阶乘尾调用的连续式实现是否优化(TCO)?

Is continuation style implementation of factorial tail call optimized (TCO)?

这里有两个阶乘实现from this site:

尾调用优化 (TCO):

function fact(n) {
  return tail_fact(n,1) ;
}

function tail_fact(n,a) {
  if (n == 0)
    return a ;
  else
    return tail_fact(n-1,n*a) ;
}

以及在连续风格编程(回调)中重写的那个:

function fact(n,ret) {
  tail_fact(n,1,ret) ;
} 

function tail_fact(n,a,ret) {
  if (n == 0)
    ret(a) ;
  else
    tail_fact(n-1,n*a,ret) ;
}

似乎教程建议第二个也是TCO,但是第二个版本returns的最后一件事是undefined,根据[=15,它的调用不在尾部位置=].

然而,这里似乎根本没有使用 return,因此无需在堆栈上创建一个地址为 return 的新帧。这就是第二次实施 TCO 的原因吗?

具有 --harmony_tailcalls 的 Node7 不认为第二个对 TCO 有效,但 TCO 在 V8 中并非 100% 完成(因此落后于运行时标志)。

Axel Rauschmayer says no, it's not a tail call,因为有一个隐含的 return undefined;在它之后:

The function call bar() in the following code is not in tail position:

function foo() {
    bar(); // this is not a tail call in JS
}

The reason is that the last action of foo() is not the function call bar(), it is (implicitly) returning undefined. In other words, foo() behaves like this:

function foo() {
    bar();
    return undefined;
}

Callers can rely on foo() always returning undefined. If bar() were to return a result for foo(), due to tail call optimization, then that would change foo’s behavior.

所以换句话说,在foo的末尾,我们不能直接跳转到bar,因为bar可能会发出一个return带有一个值除了 undefined,而 foo 根本没有 return 任何值(因此调用它保证产生 undefined)。 当我们打电话给 bar 说“但不要 return bar 的 return 值。”那是一个堆栈框架。

理论上,JavaScript引擎在调用bar时可以传递某种标志告诉自己丢弃任何值bar returns,因此在这种情况下允许 TCO,但我在规范中没有看到任何这样做的内容。