ES6 缩减了严格模式下尾调用栈的大小,如果满足以下条件,尾调用不再创建新的栈帧,而是清除并重用当前栈帧。

    ES6标准入门教程中,有对栈帧通俗的解释。函数调用会在内存中形成一个“调用记录”,又称“调用帧”,保存调用位置和内部变量等信息。如果在函数 A 的内部调用函数 B,那么在 A 的调用帧上方还会形成一个 B 的调用帧。等到 B 运行结束,将结果返回到 A,B 的调用帧才会消失。如果函数 B 内部还调用函数 C,那就还有一个 C 的调用帧,以此类推。所有的调用帧就形成一个“调用栈”。

    • 尾调用不访问当前栈帧的变量(也就是说函数不是一个闭包)。

    • 在函数内部,尾调用是最后一条语句。

    • 尾调用的结果作为函数值返回。

    实际上,尾调用的优化发生在引擎背后,除非你尝试优化一个函数,否则无需思考此类问题。递归函数是其最主要的应用场景,此时尾调用优化的效果最显著。

    1. "use strict"
    2. function factorial(n) {
    3. if (n <= 1) {
    4. return 1;
    5. } else {
    6. // 无法优化,因为在返回后执行乘法操作
    7. return n * factorial(n-1);
    8. }
    9. }
    1. "use strict"
    2. function factorial(n, p = 1) {
    3. if (n <=1 ) {
    4. return 1 * p;
    5. } else {
    6. let result = n * p;
    7. // ES6 引擎会进行尾调用优化,如果递归计算量足够大,则尾递归优化可以大幅提升程序的性能。
    8. return factorial(n - 1, result);
    9. }
    10. }