当我将一个通用树从一个节点递归到他的所有孩子时,我必须填充一个字符串数组。实际上,在从节点到叶子匹配的每个节点上,在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 + ") ");
行
我该如何解决? 感谢
答案 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, []);
答案 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上的维基百科文章中找到更多信息。