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