Javascript递归检查

时间:2014-05-02 19:37:00

标签: javascript recursion

是否有内置的方法来检查javascript函数是否已被递归(直接或间接)调用?

通过递归,我的意思是函数可以在递归链中的任何地方(函数不必是直接调用者)。

修改

显然,没有内置的方法来实现我想做的事情。我虽然计划B很容易实现,所以我提出了这个解决方案(类似于Paolo答案):

    function checkRecursion() {

        var f = arguments.callee.caller;

        var caller = f;
        while (caller) {
            caller = caller.caller;
            if (caller === f) {
                return true;
            }
        }

        return false;

    };

如果您尝试搜索第一个递归级别,此函数可以正常工作。

    function fA() {
        if (checkRecursion()) {
            alert("End of recursion");
        }
        else {
            fB();
        }

    }

    function fB() {
        fA();
    }

    fA();

但是,如果你需要对另一个递归之后执行的函数执行相同的检查,你将最终进入无限循环:

    var count = 0;

    function fA() {
        if (checkRecursion()) {
            //I should get here but I get stuck in the checkRecursion()
            alert("End of recursion");
        }
        else {
            fB();
        }

    }

    function fB() {

        if (count > 2) {
            fA();
        } else
        {
            count++;
            fC();
        }

    }

    function fC() {
        fB();
    }

    fA();

由于某种原因,fB调用者是fC,fC调用者是fB所以我不能作为fB的调用者返回fA函数。这个问题比我更复杂。

3 个答案:

答案 0 :(得分:1)

如果你反思一下,你所得到的就是,因为代码中的每个功能都是一个单一的对象
caller是对该对象的引用,后者总是相同的,因此它们是实例变量的值。

换句话说,如果一个函数在堆栈跟踪中出现多次,那么它的“调用者出现始终是最近的调用者。这就是为什么你的函数无法上升到堆栈跟踪并在上面的情况下以无限循环结束。

我们举个例子:

a => b => c => d => b => e => checkRecursion

以上是最深层checkRecursion结束的堆栈跟踪。 第b次来自ad第一次调用caller。 但是,您从b得到的是d始终从e调用! 它不能有两个调用者,因为对象/函数总是相同的。

爬上堆栈痕迹你得到了 b< = d< = c< = b< = d < = {{1 }< = c< = b < = d ...
你永远不会到达a


为了实现您的需求,您可以使用另一种技术获取堆栈跟踪,遗憾的是,该技术不是跨浏览器。

下面是使用该技术的checkRecursion的修改版本。我在Firefox上测试过,它在Safari上不起作用。

// returns true if the caller appears more than once
// in the stack trace

function checkRecursion()
{
    // the name of the calling function 

    var fname = checkRecursion.arguments.callee.caller.name;


    // obtain the stack trace ***not cross browser***
    // tested on Firefox

    var err = new Error();
    var stack = err.stack.split('\n');


    // returns true if the calling function appears more than once

    var i,n,cnt;
    n = stack.length;
    cnt = 0;
    for( i = 0; i < n; i++ )
    {
        if( fname == stack[i].substr(0,stack[i].indexOf('@')) )
        {
            cnt++;
            if( cnt > 1 )
            {
                return true;
            }
        }
    }

    return false;
}

答案 1 :(得分:0)

使用Function.caller,您可以检查调用您的函数的函数。检查最后一个调用者是否具有相同的功能。

var y = function() {
    console.log(this.lastCaller === y.caller);
    this.lastCaller = y.caller;
}
var x = function(i) {
    y();    
    if(i) {
        x(--i);
    }
}
x(3);

输出:

false, true, true, true

答案 2 :(得分:0)

您可以使用Chrome开发者工具(如果您使用Chrome)并启动新的&#34;时间轴&#34;审计。

如果过滤结果以仅显示函数,则应该能够找到一些按时间调用的函数。

另一件要尝试的是&#34;个人资料&#34;审计以收集JavaScript CPU配置文件。如果您看到具有高百分比的函数名称,则意味着它使用了更多资源,并且也可能多次调用它。