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

时间:2016-05-14 08:36:38

标签: javascript recursion tail-recursion

我一直在尝试在JavaScript的上下文中理解Tail call optimization,并为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)
}

但我不确定JavaScript编译器是否会优化该函数的tail-recursive版本,因为它在Scala等其他语言中完成。有人可以帮我解决这个问题吗?

4 个答案:

答案 0 :(得分:32)

更新:截至2018年3月13日,Safari是唯一支持尾部呼叫优化的浏览器。

铬团队明确指出,尾部调用优化尚未得到积极开发,可以跟踪here

可以跟踪Firefox的实施here

原帖

是的,ES2015在严格模式下提供尾调用优化。 Axel Rauschmayer博士在下面的链接中精美地展示了它,所以我不会在这里重复他的话。

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

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

答案 1 :(得分:12)

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

在实践中,截至2017年7月,只有Safari支持它。

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

答案 2 :(得分: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

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

答案 3 :(得分:0)

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

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


factorial(555)

按照LINK