检测无限递归?

时间:2012-03-08 15:17:32

标签: javascript recursion pass-by-reference

假设我有一个爬过数组的函数......

flatten([a, b, c, d, [e, f, g, [h, i, j, k], l], m, n, o, p])
>> [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p]

Flatten会爬过代码,遇到的每个数组都会递归进入该数组,并返回值,使得你有一个平面数组。

这有效,直到我们有一个数组,如:

a    = [];
a[0] = a;

这显然会产生无限递归:

Array[1]
0: Array[1]
 0: Array[1]
  0: Array[1]
   0: Array[1]
    0: Array[1]
     0: Array[1]
      ...

如何在不修改数组的情况下检测此行为,以便函数可以处理此问题?

5 个答案:

答案 0 :(得分:5)

如果检测递归是必需的,那么你将不得不为它交换内存空间:创建一个你解析的对象数组(递归发送的参数)并检查每个新参数。如果您已经解析了它,请立即返回。

答案 1 :(得分:2)

你必须在flatten()函数中保留一个访问过的数组数组,并在你重新诅咒之前检查它们是否存在。您必须将访问过的元素列表作为第二个参数传递给recurse

function recurse(ar, visited) {
    visited = visited || [];

    function isVisited(obj) {
        for (var i=0;i<visited.length;i++) {
            if (visited[i] == obj) {
                return true;
            }
        }

        visted.push(obj); // but we've visited it now
        return false;
    }

    // blah blah blah, do your thing... check isVisted[i]
} 

检查你的数组是否很深会变得很昂贵,所以你可以在你访问的每个数组上作弊并设置一个属性,并检查它(但当然,你正在修改数组(但不是很显着) )。

function recurse(ar) {  
    function isVisited(obj) {
        var key = 'visited';
        var visited = obj.hasOwnProperty(key);

        obj[key] = true; // but we've visited it now

        return visited;
    }

    // blah blah blah, do your thing... check isVisted[i]
} 

答案 2 :(得分:2)

跟踪已访问过的数组的一种便捷方法是添加一个&#34; flat&#34;每个属性的属性,可能会为每个操作设置一个唯一值。当每个数组已经是一个非常好的对象时,没有必要弄乱单独的地图。

答案 3 :(得分:1)

另一种更肮脏的方式(但最好的方法是使用JSON编码器):

var is_recursive = false;

try {
    JSON.stringify(my_recursive_object);
} catch (e) {
    if (e.name = 'TypeError')
        is_recursive = true;
    else
        throw e;
}

我确实发现这个问题寻找更好的答案, - 虽然这可能有助于某人想要一个好的黑客; - )

答案 4 :(得分:0)

在现实世界中,第一步是找到那个让你自我引用的对象并用棍子击打它们的冒犯者。

然而,通过将它们作为自引用消除,问题得以解决。把它们变成副本。 Array.slice返回部分数组(包括完整副本)而不更改原始数据。

if(thisElement.constructor.prototype.slice){ //is it an array
    thisElement = thisElement.slice(0); //now it's a new but identical array
}

请注意,这仅适用于主数组引用本身。内部数组引用仍然需要更改,因为复制的引用仍指向相同的内容。

此外,如果您可以对绝对不存在的字符进行假设,您可能会发现切片/连接非常有用。