Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript递归性检查_Javascript_Recursion - Fatal编程技术网

Javascript递归性检查

Javascript递归性检查,javascript,recursion,Javascript,Recursion,是否有内置的方法来检查javascript函数是否被递归调用(直接或间接) 通过递归,我的意思是函数可以位于递归链中的任何位置(函数不必是直接调用程序) 编辑 显然,没有内在的方式来实现我想要做的事情。我认为B计划很容易实施,所以我提出了这个解决方案(类似于保罗的回答): 如果您尝试搜索第一个递归级别,则此函数工作正常 function fA() { if (checkRecursion()) { alert("End of recursion")

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

通过递归,我的意思是函数可以位于递归链中的任何位置(函数不必是直接调用程序)

编辑

显然,没有内在的方式来实现我想要做的事情。我认为B计划很容易实施,所以我提出了这个解决方案(类似于保罗的回答):

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

    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函数。这个问题比我想象的要复杂得多。

使用,您可以检查哪个函数调用了您的函数。对照最后一个调用方检查它们是否是相同的函数

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


假、真、真、真

如果你仔细思考一下,你得到的东西是完全有意义的,因为你代码中的每个函数都是一个单一的对象
调用者
是对该对象的引用,后者总是相同的,因此它们是其实例变量的值

换句话说,如果一个函数在堆栈跟踪中多次出现,那么它的“调用方””似乎总是最近的调用方。这就是为什么在上述情况下,您的函数无法沿着堆栈跟踪上升,并以无限循环结束

让我们举个例子:

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

上面是以最深层的
checkRecursion
结尾的堆栈跟踪。
b
第一次从
a
调用,第二次从
d
调用。 但是您从调用方
得到的是
b
总是从
d
调用
它不能有两个调用者,因为对象/函数总是相同的

爬上您得到的堆栈跟踪

e
您可以使用Chrome开发者工具(如果您使用Chrome)并启动新的“时间线”审计

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


另一件要尝试的事情是“概要文件”审计,以收集JavaScript CPU概要文件。如果您看到一个函数名的百分比很高,这意味着它使用了更多的资源,还可能被多次调用。

“function.caller属性返回调用指定函数的函数。”(来自MDN文档)。所以你可以沿着回溯线走,看看你是否找到了自己。顺便说一句,如果你“使用严格”,这将不起作用。你可以简单地用一个附加参数再次调用该函数,然后在同一个函数中检查该参数。我用一个更好的解决方案完全编辑了我的答案另一个解决方案。。。请看我的回答:“我的意思是函数可以在递归链中的任何位置(函数不必是直接调用程序)”@Paolo ah我明白了-我误解了这个问题。听起来他们想看看函数是否在任何递归函数中,而不是递归函数本身@Paolo@megawac-你能详细说明一下吗?这似乎与此相矛盾:如果您返回另一个函数的结果,但该函数最终递归调用您,该怎么办?与中一样,
返回someFunc()
在这种情况下,您需要将
someFunc()
返回的值存储在变量中,减少计数器,返回存储在变量中的值。我完全编辑了答案,提出的第一个解决方案太难看了。我们提出了类似的解决方案,但我确实发现了一个非常有趣的错误。请参阅我的问题更新。是的,
参数。callee.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);
// 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;
}