【问题标题】:Recursive function for going through unknown DOM遍历未知 DOM 的递归函数
【发布时间】:2016-01-14 17:44:58
【问题描述】:

我正在学习 js DOM,我想制作一个 递归函数,我可以用它来遍历任何 DOM 中的所有节点 .我做到了,但我不知道为什么我的第一次尝试不起作用:

HTML

function mostrarNodosV2(node) {
  console.log(node.nodeName);
  if (node.firstElementChild != null) {
    node = node.firstElementChild;
    mostrarNodosV2(node);
  }

  if (node.nextElementSibling != null) {
    node = node.nextElementSibling;
    mostrarNodosV2(node);
  }

}

mostrarNodosV2(document);
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <title>Exercise IV</title>
</head>

<body>
  <h1> Just a header</h1>
  <p>Nice paragraph</p>
  <ul>
    <li>Im just an element list on an unordered list</li>
  </ul>
</body>

</html>

接下来是流程:

  1. 文档节点
  2. 我们用他的第一个孩子重复这个函数:头节点
  3. 我们用他的第一个孩子重复这个函数:元节点
  4. 因为 'meta' 没有孩子,我们用他的 next 重复这个函数 兄弟:标题节点
  5. 因为 'title' 没有孩子或下一个兄弟姐妹,我们结束 函数 where node=title,我们应该结束函数 where node = meta,我们应该继续检查 head 的下一个兄弟:body node

不是这样,如果您调试或检查控制台,您会看到浏览器重复该部分:

if (node.nextElementSibling != null) {
    node = node.nextElementSibling;
    mostrarNodosV2 (node);
}

其中 node = meta,所以我们在控制台上打印了两个“TITLE”。然后它按原样进行,我们得到了“body”节点。 'LI' 元素也会出现同样的问题。

所以,我不想要另一个解决方案,我只是这样做了,我只是想知道为什么我回到那个“如果”,因为我不明白。

如果你在开发者工具上调试它会更容易理解。

【问题讨论】:

  • 我做到了 -> [].slice.call( document.querySelectorAll('*') ).forEach( ...
  • @adeneo 这不是重点,重点是调试OP已有的递归函数。
  • @PatrickRoberts 这就是为什么它是评论而不是答案,并且相关
  • @DavidBarker 不是真的。这个问题被标记为recursion 而adeneo 的sn-p 是iterative
  • @PatrickRoberts 然而不知何故,它仍然不是答案,它仍然与问题相关。

标签: javascript dom recursion


【解决方案1】:

你的递归函数重复节点的原因是因为你重新分配了node。让我们自己单步执行该函数:

document -> has a child
  html -> has a child
    head -> has a child
      meta -> has no child, has a sibling
        title -> has no child or sibling
    head -> head has been overwritten with meta, which has a sibling
      title -> has no child or sibling
  html -> html has been overwritten with head, which has a sibling
    body -> has a child
      h1 -> has no child, has a sibling
        p -> has no child, has a sibling
          ul -> has a child
            li -> has no child or sibling
          ul -> ul has been overwritten with li, which has no sibling
    body -> body has been overwritten with h1, which has a sibling
      ...

所以现在你明白为什么覆盖函数参数是不好的了。

如果您想要更健壮的方法,我将编写递归 DOM 遍历函数:

function mostrarNodosV2(node) {
  if (node == null) {
    return;
  }

  console.log(node.nodeName);

  mostrarNodosV2(node.firstElementChild);
  mostrarNodosV2(node.nextElementSibling);
}

mostrarNodosV2(document);

这里唯一的区别是我检查节点有效性的递归比你对每个节点的递归更深,这减少了你的方法的冗长。

【讨论】:

  • 再次感谢,这有帮助。我会检查它作为最佳答案,谢谢!
【解决方案2】:

您正在重新分配 node 变量,试试这个:

function mostrarNodosV2(node) {
    console.log(node.nodeName);
    if (node.firstElementChild != null) {
        var child = node.firstElementChild;
        mostrarNodosV2(child);
    }
    if (node.nextElementSibling != null) {
        var sibling = node.nextElementSibling;
        mostrarNodosV2(sibling);
    }
}
mostrarNodosV2(document);

【讨论】:

  • 不,不是我的;那行得通!我仍然需要知道发生了什么,但知道问题出在哪里会对我有很大帮助。谢谢!
  • 就我个人而言,我认为这值得赞成(我给了一个),但如果我不得不猜测,我会说它被否决了,因为你没有解释为什么会发生这种行为并提供了一个没有要求的解释。
【解决方案3】:

无需自己实现,TreeWalker DOM Level 2 API 允许遍历,选择自定义起始节点并改变方向。

【讨论】:

  • 感谢您的通知,但我认为 OP 将此视为一种学习练习,而不是出于必要编写函数。
猜你喜欢
  • 2012-02-29
  • 1970-01-01
  • 1970-01-01
  • 2011-04-21
  • 2010-12-08
  • 2020-09-26
  • 1970-01-01
  • 2013-08-02
  • 2013-07-23
相关资源
最近更新 更多