JavaScript尾部调用中的函数是否已优化?


72

我一直试图Tail call optimization在JavaScript上下文中进行理解,并为编写了以下递归和尾递归方法factorial()

递归:

function factorial (n) {
  if (n < 2) {
    return 1;
  } else {
    return n * factorial(n-1);
  }
}

尾递归:

function factorial (n) {
  function fact(n, acc) {
    if (n < 2) {
      return acc;
    } else {
      return fact(n-1, n * acc);
    }
  }

  return fact(n, 1)
}

但是我不确定tail-recursive该函数的版本是否会像其他Scala等语言那样通过JavaScript编译器进行优化。有人可以帮我解决这个问题吗?

Answers:


64

更新:自2020年1月1日起,Safari是唯一支持尾叫优化的浏览器。

铬小组明确指出尾声调用优化尚未积极开展,可以在这里进行跟踪。

可以在此处跟踪Firefox的实现

原始帖子

是的,ES2015在严格模式下提供了尾部呼叫优化。Axel Rauschmayer博士在下面的链接中详细介绍了它,因此在此我不再赘述。

注意:ES 5不会优化尾调用。

http://www.2ality.com/2015/06/tail-call-optimization.html


重要警告:只能在严格模式下对其进行优化。
巴马尔

15
在ES2015中进行尾部调用优化与所有或什至大多数实现都声称与ES2015兼容的,进行适当的尾部调用优化的实现明显不同。“ JavaScript尾部调用中的函数是否已优化?”这个问题的正确答案。是“如果有,则为真,否则为否。” 请参阅chromestatus.com/feature/5516876633341952

5
我很确定浏览器在为ES6实施ES5代码时也会对它们进行尾部调用优化。只是ES6规范现在明确要求它了(而且,还没有引擎实现它)。
Bergi '16

1
“ ECMAScript兼容性表”是检查兼容性的好资源。 kangax.github.io/compat-table/es6
Eldho NewAge

15

理论上是。作为其他答案的状态。

不过实际上,截至2017年7月,没有。只有Safari支持它。

Javascript ES6(ES2015)兼容性:https ://kangax.github.io/compat-table/es6/


2
正确-而且由于Chrome根本无法使用,因此极有可能在生产代码中永远无法使用尾部调用。 chromestatus.com/feature/5516876633341952
Freewalker

4

就像其他答案所说的那样,不是在实践中。但是,您可以定义一个实用程序来提供帮助。

class Tco {
  constructor(func) {
    this.func = func;
  }
  execute() {
    let value = this;
    while (value instanceof Tco)
      value = value.func();
    return value;
  }
}

const tco = (f) => new Tco(f);
function factorial (n) {
  const fact = (n, acc) => tco(() => {
    if (n < 2) {
      return acc;
    } else {
      return fact(n-1, n * acc);
    }
  });

  return fact(n, 1).execute();
}

console.log(factorial(2000000)); // Infinity

如您所见,这使您可以编写尾部递归函数,而语法只有很小的不同,而不会遇到最大调用堆栈错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.