简体   繁体   English

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

[英]Are functions in JavaScript tail-call optimized?

I have been trying to understand Tail call optimization in context of JavaScript and have written the below recursive and tail-recursive methods for factorial() .我一直在尝试了解 JavaScript 上下文中的Tail call optimization ,并为factorial()编写了以下递归和尾递归方法。

Recursive:递归:

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

Tail-recursive:尾递归:

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

  return fact(n, 1)
}

But I am not sure if the tail-recursive version of the function will be optimised by JavaScript compiler as it is done in other languages like Scala etc. Can someone help me out on this one?但我不确定该函数的tail-recursive版本是否会像在其他语言(如 Scala 等)中一样由 JavaScript 编译器优化。有人可以帮我解决这个问题吗?

Update: As of January 1, 2020 Safari is the only browser that supports tail call optimization.更新:截至 2020 年 1 月 1 日,Safari 是唯一支持尾调用优化的浏览器。

The chromium team explicitly states that Tail Call Optimization is not under active development and can be tracked here . Chromium 团队明确指出,Tail Call Optimization 未在积极开发中,可以在此处进行跟踪。

The implementation for Firefox can be tracked here可以在此处跟踪 Firefox 的实现

Original Post原帖

Yes, ES2015 offers tail call optimization in strict mode.是的,ES2015 在严格模式下提供尾调用优化。 Dr. Axel Rauschmayer lays it out beautifully at the link below so I shall not repeat his words here. Axel Rauschmayer 博士在下面的链接中对其进行了精美的阐述,因此我不会在这里重复他的话。

Note: ES 5 does not optimize tail calls.注意:ES 5 没有优化尾调用。

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

In theory yes.理论上是的。 As the other answer states.正如另一个答案所述。

In practice though, as of July 2017, No. Only Safari supports it.但实际上,截至 2017 年 7 月,否。只有 Safari 支持它。

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

As the other answers have said, not in practice.正如其他答案所说,实际上并非如此。 However, you can define a utility to help out.但是,您可以定义一个实用程序来提供帮助。

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

As you can see, this allows you to write tail recursive functions with only a small difference in syntax, without running into a max call stack error.如您所见,这允许您编写仅在语法上有很小差异的尾递归函数,而不会遇到最大调用堆栈错误。

Safari is the only browser that supports tail call optimization. Safari 是唯一支持尾调用优化的浏览器。 ES2015 offers tail call optimization in strict mode ES2015 在严格模式下提供尾调用优化

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


factorial(555)

Follow the LINK按照链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM