以递归方式遍历DOM树填充数组

时间:2015-10-22 20:13:16

标签: javascript arrays recursion

当我将一个通用树从一个节点递归到他的所有孩子时,我必须填充一个字符串数组。实际上,在从节点到叶子匹配的每个节点上,在DOM树中插入一个字符串。 我知道这是一个微不足道的问题,但我无法解决。 这是我写的代码:

function operationsToInsert(node) {
   var operations = [];
   operationsToInsertRec(node, operations);
   return operations;
}

function operationsToInsertRec(node, operations) {
   var childNodes = node.childNodes;
   operations.push("i(" + node.nodeName + ") ");
   for(var i = 0; i < childNodes.length; i++) {
      operationsToInsertRec(childNodes[i], operations);
      operations.push("i(" + childNodes[i].nodeName + ")");
   }   
}

但是有以下错误:

未捕获的TypeError:无法读取属性&#39; push&#39;第operations.push("insert(" + node.nodeName + ") ");

的未定义

我该如何解决? 感谢

2 个答案:

答案 0 :(得分:1)

这是一种使用方便的Array.prototype.reduce函数使用一种技巧来使树行走的方法,这种技巧可以让它适用于数组:

function flatten(ops, n) {
    ops.push("i(" + n.nodeName + ") ");
    if (n.childNodes && n.childNodes.length) {
       [].reduce.call(n.childNodes, flatten, ops);
    }
    return ops;
}

var node = document.getElementById("start_here");
var ops = [node].reduce(flatten, []);

were removed

答案 1 :(得分:0)

问题是你只有一个功能,它不是你想象的那样!你重新定义了它,所以当你调用你认为的第一个时,你只提供了一个参数,其余的参数是隐含的undefined

以下是相同的代码,简化为可演示的示例:

function operationsToInsert(node) {
   console.log("Definition #1");
}

function operationsToInsert(node, operations) {
    console.log("Definintion #2");
}

operationsToInsert();

您需要更改其中一个功能的名称,以免发生碰撞。

编辑以解决新问题:

我认为你说你的新问题是大多数节点出现在列表中两次。跟踪代码,您将看到您处理除根节点之外的每个节点两次。在operationsToInsertRec()中,您将节点放在列表中(childNodes[i]),然后将其传递到operationsToInsertRec(),并将其放入列表(node)。

以下是一个简单的更改:

function operationsToInsert(node) {
   var operations = [];
   operations.push("i(" + node.nodeName + ") ");
   operationsToInsertRec(node, operations);
   return operations;
}

function operationsToInsertRec(node, operations) {
   var childNodes = node.childNodes;
   for(var i = 0; i < childNodes.length; i++) {
      operationsToInsertRec(childNodes[i], operations);
      operations.push("i(" + childNodes[i].nodeName + ")");
   }   
}

operationsToInsert()我推根节点。然后operationsToInsertRec()只处理子节点,因此只处理每个节点一次。

在对不同答案的评论中,我看到你触及遍历顺序的主题。遍历树时,这些算法有几种不同的分类:深度优先,它又细分为预订按顺序后期订单广度优先。您可以在tree traversal上的维基百科文章中找到更多信息。