JavaScript 尾调用中的函数是否经过优化?

IT技术 javascript recursion tail-recursion
2021-02-04 01:13:35

我一直试图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 编译器优化。有人可以帮我解决这个问题吗?

4个回答

更新:截至 2020 年 1 月 1 日,Safari 是唯一支持尾调用优化的浏览器。

Chromium 团队明确指出,Tail Call Optimization 未在积极开发中,可以在此处进行跟踪

可以在此处跟踪 Firefox 的实现

原帖

是的,ES2015 在严格模式下提供尾调用优化。Axel Rauschmayer 博士在下面的链接中对其进行了精美的介绍,因此我不会在这里重复他的话。

注意:ES 5 没有优化尾调用。

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

重要警告:它只能在严格模式下进行优化。
2021-03-14 01:13:35
我很确定浏览器在为 ES6 实现 ES5 代码时也会对其进行尾调用优化。只是 ES6 规范现在明确要求它(并且仍然没有引擎实现它)。
2021-03-24 01:13:35
在 ES2015 中进行尾调用优化与所有甚至大多数实现明显不同,这些实现在其他方面声称符合 ES2015 进行适当的尾调用优化。“JavaScript 尾调用中的函数是否已优化?”问题的正确答案 是“如果引擎是,他们是,否则他们不是。” 请参阅chromestatus.com/feature/5516876633341952
2021-03-27 01:13:35
“ECMAScript 兼容性表”是检查兼容性的好资源。 kangax.github.io/compat-table/es6
2021-03-29 01:13:35

理论上是的。正如另一个答案所述。

但实际上,截至 2017 年 7 月,否。只有 Safari 支持它。

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

正确 - 由于 Chrome 根本没有处理它,因此尾调用在生产代码中永远无法使用的可能性似乎很大。 chromestatus.com/feature/5516876633341952
2021-03-31 01:13:35

正如其他答案所说,实际上并非如此。但是,您可以定义一个实用程序来提供帮助。

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

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

我不知道这是否是一个好主意。但这绝对是 javascript 中的 TCO。干得好!
2021-04-09 01:13:35

Safari 是唯一支持尾调用优化的浏览器。ES2015 在严格模式下提供尾调用优化

    function factorial(n, returnVal= 1) {
      'use strict';
       if (n <= 1) return returnVal;
        return factorial(n - 1, n * returnVal);
}


factorial(555)

按照链接