如何在ES5中的递归匿名函数上应用TCO(尾调用优化)

时间:2016-09-18 21:23:59

标签: javascript node.js recursion ecmascript-6

如果我可以使用命名的递归函数,那么应该有一种方法可以使用tco匿名递归函数。如果有办法,请解释下面的方法,这是我的递归函数和TCO函数。

function recursive(length, callback) {

    tco((function (i, sum) {
        var args = arguments;
        if (i > length) {
            console.log("break statement");
            callback(sum)
            return sum
        } else {
            return args.callee(i + 1, sum + i)
        }
    }))(0, 0)
}

function tco(f) {
    var value;
    var active = false;
    var accumulated = [];

    return function accumulator() {
        accumulated.push(arguments);

        if (!active) {
            active = true;

            while (accumulated.length) {
                value = f.apply(this, accumulated.shift());
            }

            active = false;

            return value;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

尾调用优化

ES6建议改变尾调用系统,即引擎优化。尾调用是指函数被调用为另一个函数中的最后一个语句,如下所示:

function doSomething() {
    return doSomethingElse();   // tail call
}

ECMAScript 6试图在严格模式下减少某些尾调用的调用堆栈的大小。通过此优化,而不是为尾调用创建新的堆栈帧,只要满足以下条件,就会清除并重用当前堆栈帧

  1. 必须打开严格模式。
  2. 尾调用不需要访问当前堆栈帧中的变量(意味着该函数不是闭包)。
  3. 尾部调用返回后,进行尾调用的函数没有其他工作要做。
  4. 尾调用的结果作为函数值返回。
  5.   

    可能最难避免的情况是使用闭包。因为闭包可以访问包含范围中的变量,所以可以关闭尾调用优化。例如:

    "use strict";
    
    function doSomething() {
        var num = 1,
            func = () => num;
    
        // not optimized - function is a closure
        return func();
    }
    

    利用TCO优化:

    考虑这个函数,它计算阶乘:

    "use strict";
    function factorial(n) {
    
        if (n <= 1) {
            return 1;
        } else {
    
            // not optimized - must multiply after returning
            return n * factorial(n - 1);
        }
    }
    

    为了优化函数,您需要确保在最后一次函数调用后不会发生乘法。

    "use strict";
    function factorial(n, p = 1) {
    
        if (n <= 1) {
            return 1 * p;
        } else {
            let result = n * p;
    
            // optimized
            return factorial(n - 1, result);
        }
    }
    

    来源: Nicholas Zakas的 Awesome 一书,了解ECMAScript 6。