向下递归DOM树

dop*_*man 2 javascript recursion dom

这是来自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;
        }

    };
Run Code Online (Sandbox Code Playgroud)

我理解代码除外func(node).我想重点是node在函数中作为参数传递func,但浏览器将如何理解它?node并且func可以是任何东西 - 因此当调用该函数时,它可以像这样读取:

walkDOM(document.body,function(att) {
          node.getAttribute(att);
          results.push(node);
          });
Run Code Online (Sandbox Code Playgroud)

如果func获得通过,walkDOM将处理功能(ATT){...}(document.body的) -这将没有任何意义.那么为什么Crockford选择包含func(node)?

Jav*_*ome 10

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

  • 函数参数应该知道如何处理(任何)节点
  • 第一个调用参数应该是一个受支持的节点(例如,如果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);
}
Run Code Online (Sandbox Code Playgroud)

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


Sea*_*son 5

在我看来,func它用于对树中的每个节点做一些事情.

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

walkDOM(document.body, function(node) {
    alert(node.tagName);
});
Run Code Online (Sandbox Code Playgroud)

在您的示例函数中:

walkDOM(document.body,function(att) {
      node.getAttribute(att);
      results.push(node);
      });
Run Code Online (Sandbox Code Playgroud)

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