向下递归DOM树

时间:2011-08-06 23:11:17

标签: javascript dom recursion

这是来自Crockford的JavaScript:The Good Parts的代码。

var results = [];

var walkDOM = function (node,func) {
        func(node);                     //What does this do?
        node = node.firstChild;
        while(node) {
            walkDOM(node,func);
            node = node.nextSibling;
        }

    };

我理解除func(node)之外的代码。我想重点是将node作为函数func中的参数传递,但浏览器将如何理解它? nodefunc可以是任何内容 - 所以当调用该函数时,它可以如下所示:

walkDOM(document.body,function(att) {
          node.getAttribute(att);
          results.push(node);
          });

func通过时,walkDOM将处理函数(att){...}(document.body) - 这没有任何意义。那么为什么Crockford选择包含func(node)?

4 个答案:

答案 0 :(得分:8)

是的,这个树遍历功能是有道理的,因为:

  • 函数参数应该知道如何处理(任何)节点
  • 第一个调用参数应该是受支持的节点(例如,如果func不知道如何处理它,则不是document.body)

那就是说,这个算法对我来说看起来仍然不正确,因为它只是通过第一个兄弟来探索;其他兄弟姐妹将被忽略。所以我建议使用这种更传统的方法:

function walk(node, func) {
   var children = node.childNodes;
   for (var i = 0; i < children.length; i++)  // Children are siblings to each other
       walk(children[i], func);
   func(node);
}

请注意,版本是“深度优先”(即在处理子代之前不调用call func()),但我宁愿推荐它,因为func可能会更改节点。这样,父母的处理将能够在发出可能不合适的更改之前考虑其已经处理的子项的最新状态。

答案 1 :(得分:5)

在我看来,func用于对树中的每个节点执行某些操作。

例如,如果我想提醒整个树中每个节点的标记名称:

walkDOM(document.body, function(node) {
    alert(node.tagName);
});

在你的示例函数中:

walkDOM(document.body,function(att) {
      node.getAttribute(att);
      results.push(node);
      });

...您已将node参数命名为att,但这并不会在属性名称中神奇地生成。我希望在运行node.getAttribute(att)时“未定义”变量'节点',因为节点被设置为att ...该函数的范围内没有node。 / p>

答案 2 :(得分:3)

中的func
func(node)

行通常称为回调函数。它是一个可供walkDOM函数使用的函数。使用更详细的函数名称可能有意义:

var results = [];

var walkDOM = function (node, iCanBeCalledOnANode) {
    iCanBeCalledOnANode(node); // Will be called on every DOM element 
    node = node.firstChild;
    while(node) {
        walkDOM(node,func);
        node = node.nextSibling;
    }

};

希望这能为你解决问题。

答案 3 :(得分:0)

Crockford的代码将回调传递给walkDOM,可以通过多种方式处理传递给它的参数。

示例可以是一个方法,它返回具有指定tagName的所有DOM元素的计数:

var getTagNameCount = function(tagName) {
    var count = 0;
    walkDOM(document.body, function(node) {
       if (node.tagName === tagName) {
          count++;
       }
    });
    return count;
};