我正在JS编写递归函数并遇到一些麻烦。让我们从这个非常基本的功能开始:
function traverse(thing)
{
if (typeof traverse.depth == 'undefined')
traverse.depth = 1;
else
traverse.depth ++;
if (thing.child)
traverse(thing.child);
}
所以这很好用,depth
充当静态变量,但问题是在像C这样的语言中有适当的静态变量,当你退出函数时,这个变量会(表面上是减少,所以这是一个真正的深度。如果我有三个盒子,其中包含三个盒子,每个盒子包含三个盒子等,我们基本上钻到最深的盒子里,直到没有孩子,然后退出一个级别给一个兄弟姐妹,并穿过它的孩子。上述代码的问题在于深度不断增加和增加,即使从最老的祖先到最小的孩子,TRUTH深度可能只有3或4。如果每个级别上有80个兄弟姐妹,那个深度计数器将会飙升。
如何跟踪JS递归函数的真实深度?
答案 0 :(得分:12)
请勿将计数器安装在此功能上。计数器由所有递归调用共享,因此计数器表示函数调用的数量,而不是递归深度。
当depth
作为单独的变量传递时,计数器会显示真实的深度。
function traverse(thing, depth)
{
if (typeof depth == 'number')
depth++;
else
depth = 1;
if (thing.child)
traverse(thing, depth);
}
答案 1 :(得分:6)
另一个(也许更好的)解决方案是利用JS功能编程优势并使用高阶函数将所有与深度相关的内务处理保留在主函数之外。例如,考虑以下经典示例:
function fac(n) {
if(n < 3)
return n;
return n * fac(n - 1);
}
我们希望这个在递归超过给定值时打破递归。让我们编写一个包装器:
function wrapDepth(fn, max) {
var depth = 0
return function() {
if (++depth > max)
throw "Too much recursion"
var out = fn.apply(null, [].slice.call(arguments, 0))
depth--;
return out;
}
}
创建一个最大深度为20的包装器:
fac = wrapDepth(fac, 20)
并测试:
console.log(fac(10)) // 3628800
console.log(fac(100)) // Too much recursion
请注意,我们没有对主函数fac
本身进行任何更改,但仍然可以控制其递归深度。
答案 2 :(得分:3)
为什么不修改函数签名来获取一个东西和一个索引?所以你会这样称呼:
function traverse(thing, idx)
...
if (condition)
traverse(thing.child, ++idx)
答案 3 :(得分:1)
只需添加:
traverse.depth--;
在任何退货声明之前。所以
if(x === 5)
return thing;
会变成:
if(x === 5){
traverse.depth--;
return thing;
}
然后在功能结束traverse.depth--;
之前添加}
。
答案 4 :(得分:0)
如果我理解正确,它在我看来就像你想要跟踪递归的深度..但是在你的代码中,你在递归中完成1级时永远不会减少深度。
我尝试了一个简单的代码,我认为这就是你想要的,
<强> HTML:强>
<div id="result"></div>
<强> JS:强>
var result = document.getElementById('result');
var tmpArray = [1,2,3,4,5,6,7,8];
function depthTest() {
if (typeof depthTest.depth == 'undefined')
depthTest.depth = 0;
else
depthTest.depth++;
result.innerHTML += depthTest.depth;
if (typeof tmpArray[depthTest.depth] != 'undefined')
depthTest();
result.innerHTML += depthTest.depth;
depthTest.depth--;
}
depthTest(tmpArray);
<强>输出:强>
012345678876543210