javascript 向下递归 DOM 树

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6969604/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 22:31:22  来源:igfitidea点击:

Recursion down DOM tree

javascriptdomrecursion

提问by dopatraman

This is code from Crockford's JavaScript: The Good Parts.

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

    };

I understand the code except for func(node). I guess the point is to pass nodeas a parameter in function func, but how will the browser understand it this way? nodeand funccould be anything--so when the function is called it could read like this:

我理解除了func(node). 我想重点是node在 function 中作为参数传递func,但浏览器将如何理解它?node并且func可以是任何东西——所以当函数被调用时,它可以是这样的:

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

When funcis passed, walkDOMwill process function(att) {...}(document.body)--which wouldn't make any sense. So why has Crockford chosen to include func(node)?

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

回答by Javarome

Yes this tree traversal function makes sense since :

是的,这个树遍历函数是有道理的,因为:

  • the function argument is supposed to know how to handle (any) nodes
  • the first call argument is supposed to be a supported node (not document.bodyfor instance, if func doesn't know how to handle it)
  • 函数参数应该知道如何处理(任何)节点
  • 第一个调用参数应该是受支持的节点(不是document.body例如,如果 func 不知道如何处理它)

That said, this algorithm still looks incorrect to me, as it only explores through the first sibling ; other siblings will be simply ignored. So I would recommend using this more traditional approach instead :

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

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);
}

Note that version is "deep first" (i.e. not calling call func()before processing children), but I'd rather recommend it since funcis likely to change nodes. This way the processing of a parent will be able to consider the latest state of its already-processed children before issuing possibly un-appropriate changes.

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

回答by Sean Adkinson

Looks to me like the funcis used for doing something to every node in the tree.

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

For example, if I wanted to alert the tag name for every node in the entire tree:

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

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

In your example function:

在您的示例函数中:

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

... you have named the nodeparameter to att, but that doesn't magically make in a name of an attribute. I would expect a "variable 'node' is not defined" when node.getAttribute(att)is ran, because node is being set to att... there is no nodein that function's scope.

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

回答by Jamil Lawrence

The functhat's in the

func这在

func(node)

line is what is typically known as a callback function. It a function that is available for use by the walkDOMfunction. It might make sense with a more verbose function name:

line 就是通常所说的回调函数。它是一个可供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;
    }

};

Hope this clears things up for you.

希望这可以为您解决问题。

回答by Coder

Crockford's code is passing a callback to walkDOM which can be used in many ways to process the arguments passed to it.

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

An example could be a method which returns the count of all DOM elements with the specified tagName:

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

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