【问题标题】:Loop through childNodes循环子节点
【发布时间】:2014-09-06 16:23:25
【问题描述】:

我正在尝试像这样循环遍历子节点:

var children = element.childNodes;
children.forEach(function(item){
    console.log(item);
});

但是,由于forEach 函数,它会输出Uncaught TypeError: undefined is not a function。我也尝试使用children 而不是childNodes,但没有任何改变。

有人知道怎么回事吗?

【问题讨论】:

    标签: javascript loops children


    【解决方案1】:

    忍不住添加了另一种方法,使用childElementCount。它返回给定父节点的子元素节点数,因此您可以循环遍历它。

    for(var i=0, len = parent.childElementCount ; i < len; ++i){
        ... do something with parent.children[i]
        }
    

    【讨论】:

    • 当心,parent.childElementCount != parent.childNodes.lengthchildElementCount返回Element节点数,不包括文本和评论节点等。见:w3schools.com/jsref/prop_element_childelementcount.asp
    • @Mark 正如答案中所说:“返回子元素的数量 元素 节点”。但强调它是好的。
    • 不用担心。从技术上讲,您的答案是正确的,它是关于 element 计数和 children,但我只是想补充一下,因为最初的问题是关于 nodes 。有太多方法可以让自己在脚上开枪:)
    【解决方案2】:
    const results = Array.from(myNodeList.values()).map(parser_item);
    

    NodeList is not Array 但是 NodeList.values() 返回一个 Array Iterator,所以可以将其转换为 Array。

    【讨论】:

      【解决方案3】:

      这是一种迭代 NodeList 的函数式 ES6 方法。此方法使用ArrayforEach,如下所示:

      Array.prototype.forEach.call(element.childNodes, f)
      

      其中f 是迭代器函数,它接收子节点作为它的第一个参数和索引作为第二个参数。

      如果您需要多次迭代 NodeLists,您可以创建一个小的功能实用程序方法:

      const forEach = f => x => Array.prototype.forEach.call(x, f);
      
      // For example, to log all child nodes
      forEach((item) => { console.log(item); })(element.childNodes)
      
      // The functional forEach is handy as you can easily created curried functions
      const logChildren = forEach((childNode) => { console.log(childNode); })
      logChildren(elementA.childNodes)
      logChildren(elementB.childNodes)
      

      (您可以对 map() 和其他 Array 函数执行相同的技巧。)

      【讨论】:

        【解决方案4】:

        如果你做了很多这样的事情,那么你自己定义函数可能是值得的。

        if (typeof NodeList.prototype.forEach == "undefined"){
            NodeList.prototype.forEach = function (cb){
                for (var i=0; i < this.length; i++) {
                    var node = this[i];
                    cb( node, i );
                }
            };
        }
        

        【讨论】:

          【解决方案5】:

          变量children 是一个NodeList 实例,而NodeLists 不是真的Array,因此它们不继承forEach 方法。

          还有一些浏览器实际上支持它nodeList.forEach


          ES5

          您可以使用 sliceArrayNodeList 转换为正确的 Array

          var array = Array.prototype.slice.call(children);

          您也可以简单地使用call 调用forEach 并将NodeList 作为上下文传递给它。

          [].forEach.call(children, function(child) {});


          ES6

          您可以使用from 方法将您的NodeList 转换为Array

          var array = Array.from(children);

          或者你也可以像这样使用spread syntax ...

          let array = [ ...children ];


          可以使用的 hack 是 NodeList.prototype.forEach = Array.prototype.forEach,然后您可以将 forEach 与任何 NodeList 一起使用,而无需每次都转换它们。

          NodeList.prototype.forEach = Array.prototype.forEach
          var children = element.childNodes;
          children.forEach(function(item){
              console.log(item);
          });
          

          请参阅A comprehensive dive into NodeLists, Arrays, converting NodeLists and understanding the DOM 以获得很好的解释和其他方法。

          【讨论】:

          • 如何将 NodeList 转换为纯数组?
          • 已更新示例,但请阅读我发布的链接,它解释了一切:)
          • 或者,您可以这样做:[].forEach.call(element.childNodes, child =&gt; console.log(child))
          • 更酷的 es6 方式:let items = [ ...children ] 将把它变成一个数组
          • 将 Array 方法应用于 NodeList 有一个主要问题:NodeList(如 node.childNodes)是实时列表,如果您在循环期间操作 DOM,NodeList 可能会发生变化,这意味着回调forEach() 我不会在列表的每个元素上调用 - 或者比列表中最初的元素更多 - 导致不可预测的结果。最好在循环之前将 NodeList 转换为数组。
          【解决方案6】:

          我参加聚会很晚了,但是自从element.lastChild.nextSibling === null 之后,以下对我来说似乎是最直接的选择:

          for(var child=element.firstChild; child!==null; child=child.nextSibling) {
              console.log(child);
          }
          

          【讨论】:

          • 最直接的选择是使用常规的“for”循环。但你的选择很有趣。
          • 我最喜欢这个,正计划实施相同的......合乎逻辑且不需要转换
          【解决方案7】:

          尝试使用for 循环。它在forEach 中给出错误,因为它是节点nodelist 的集合。

          或者这应该将节点列表转换为数组

          function toArray(obj) {
            var array = [];
            for (var i = 0; i < obj.length; i++) { 
              array[i] = obj[i];
            }
          return array;
          }
          

          或者你可以使用这个

          var array = Array.prototype.slice.call(obj);
          

          【讨论】:

            【解决方案8】:

            试试这个[逆序遍历]:

            var childs = document.getElementById('parent').childNodes;
            var len = childs.length;
            if(len --) do {
                console.log('node: ', childs[len]);
            } while(len --);
            

            OR [按顺序遍历]

            var childs = document.getElementById('parent').childNodes;
            var len = childs.length, i = -1;
            if(++i < len) do {
                console.log('node: ', childs[i]);
            } while(++i < len);
            

            【讨论】:

            • 简单的 for 循环比 while 循环更具可读性。作者不要求逆序/逆序遍历。
            【解决方案9】:

            下面是使用for-in 循环的方法。

            var children = element.childNodes;
            
            for(child in children){
                console.log(children[child]);
            }
            

            【讨论】:

            • 你忘了 check: if (children.hasOwnProperty(child)) { //code here } 否则你会遍历不需要的 props,比如 "length" 等等!
            • 更好:使用for ... of ...,虽然它是 ES6 语法。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-07-13
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-08-10
            • 1970-01-01
            • 2018-02-12
            相关资源
            最近更新 更多