【问题标题】:How to loop through all the elements returned from getElementsByTagName [duplicate]如何遍历从 getElementsByTagName 返回的所有元素 [重复]
【发布时间】:2013-10-19 22:06:18
【问题描述】:

我正在尝试使用 forEach 遍历从 getElementsByTagName("input") 重新提取的所有元素。任何想法为什么这在 FF、Chrome 或 IE 中不起作用?

<html>
    <head>
    </head>
    <body>
        <input type="text" value="" />
        <input type="text" value="" />
        <script>
            function ShowResults(value, index, ar) {
                alert(index);
            }
            var input = document.getElementsByTagName("input");
            alert(input.length);
            input.forEach(ShowResults);
    </script>
    </body>
</html>

【问题讨论】:

  • 为什么没有forEach: stackoverflow.com/questions/13433799/…的理由
  • 现在在 ES6 NodeList 中有forEach,但 HTMLCollection 仍然没有。不幸的是,getElementsByTagName 返回 HTMLCollection。考虑使用querySelectorAll
  • 有错误提示吗?

标签: javascript arrays foreach getelementsbytagname


【解决方案1】:

您需要将节点列表转换为数组:

<html>
    <head>
    </head>
    <body>
        <input type="text" value="" />
        <input type="text" value="" />
        <script>
            function ShowResults(value, index, ar) {
                alert(index);
            }
            var input = document.getElementsByTagName("input");
            var inputList = Array.prototype.slice.call(input);
            alert(inputList.length);
            inputList.forEach(ShowResults);
    </script>
    </body>
</html>

或使用 for 循环。

for(let i = 0;i < input.length; i++)
{
    ShowResults(input[i].value);
}

并将 ShowResults 函数更改为:

function ShowResults(value) {
   alert(value);
}

为什么我们需要这样做?
JavaScript 中的一些对象看起来像一个数组,但它们不是一个。这通常意味着它们具有索引访问和长度属性,但没有数组方法。示例包括特殊变量参数、DOM 节点列表和字符串。类数组对象和通用方法提供了使用类数组对象的技巧。 source

2019 年 7 月 10 日更新
现在有了 ES6,你可以使用 [...inputList].forEachArray.from(inputList)

【讨论】:

  • 我在表单上有 > 1000 个隐藏的输入字段。在这种情况下,哪个选项最有效?
  • 两者相同。随意使用任何你想要的东西。
  • 对于Array.prototype.slice.call(input),您可以使用简写[].slice.call(input)
  • 我想你忘记了 for 循环中的 let i
【解决方案2】:

这是因为input是html集合。 html 集合没有 forEach。

您可以通过 Array.prototype.slice 轻松将其转换为数组

示例:

function ShowResults(value, index, ar) {
            alert(index);
        }
        var input = document.getElementsByTagName("input");
        alert(input.length);
input = Array.prototype.slice.call(input)
        input.forEach(ShowResults);

http://jsfiddle.net/fPuKt/1/

【讨论】:

    【解决方案3】:

    因为input 不是数组,所以它是HTMLCollection 使用for 循环会更好。

    由于HTMLCollections 是类似数组的对象,您可以像这样在call Array#forEach 上使用它

    Array.prototype.forEach.call(input, ShowResults);
    

    【讨论】:

      【解决方案4】:

      HTMLCollections 没有与数组相同的方法。您可以通过在浏览器的 javascript 控制台中提示此内容来检查此内容。

      var elements = document.getElementsByClassName('some-class');
      'forEach' in elements;
      

      如果elements(在这种情况下)有一个名为forEach的方法可以调用,控制台将返回true

      【讨论】:

        【解决方案5】:

        在 ES6 中,您可以使用 spread 运算符将 HtmlCollection 转换为数组。看到这个问题Why can't I use Array.forEach on a collection of Javascript elements?

        input = [...input]
        input.forEach(ShowResults)
        

        【讨论】:

          【解决方案6】:

          是的,ES6:

          const children = [...parent.getElementsByTagName('tag')];
          children.forEach((child) => { /* Do something; */ });
          

          MDN Doc for Spread Operator (...)

          【讨论】:

          • 现在在 ES6 中,您可以将 forEach 用于 NodeList,但不能用于 HTMLCollection。 getElementsByTagName 返回 HTMLCollection,而 querySelectorAll 返回 NodeList。
          【解决方案7】:

          原因,这不起作用是因为 'getElementsByTagName' 返回一个数组 - 像 Object 而不是实际的数组。如果您不知道,它们的外观如下:-

          var realArray = ['a', 'b', 'c'];
          var arrayLike = {
            0: 'a',
            1: 'b',
            2: 'c',
            length: 3
          };
          

          因此,由于类数组对象继承自'Object.prototype'而不是'Array.prototype',这意味着类数组对象无法访问常见的 Array 原型方法,如 forEach()、push()、map()、filter() 和 slice()。

          希望有帮助!

          【讨论】:

          • 这个解释很好
          【解决方案8】:

          我这样做了:

          HTMLCollection.prototype.map = Array.prototype.map;
          

          您现在可以在每个HTMLCollection 上使用地图。

          document.getElementsByTagName("input").map(
              input => console.log(input)
          );
          

          【讨论】:

          • 简洁的解决方案,谢谢
          【解决方案9】:

          getElementsByTagName 返回一个HTMLCollection,它没有forEach 方法。但是,有一个简单的调整可以让您使用forEach 进行迭代而不创建中间数组:改用querySelectorAllquerySelectorAll 返回一个NodeList,现代浏览器有一个NodeList.prototype.forEach 方法:

          document.querySelectorAll('input')
            .forEach((input) => {
              console.log(input.value);
            });
          <input type="text" value="foo">
          <input type="text" value="bar">

          使用querySelectorAll 的另一个好处是它接受逗号分隔的CSS 选择器,这比标签名称更加灵活和精确。比如选择器

          .container1 > span, .container2 > span
          

          只会匹配spans,它们是类为container1container2的元素的子元素:

          document.querySelectorAll('.container1 > span, .container2 > span')
            .forEach((span) => {
              span.classList.add('highlight');
            });
          .highlight {
            background-color: yellow;
          }
          <div class="container1">
            <span>foo</span>
            <span>bar</span>
          </div>
          <div class="container2">
            <span>baz</span>
          </div>
          <div class="container3">
            <span>buzz</span>
          </div>

          如果你想在没有内置方法的古老浏览器上使用NodeList.prototype.forEach,只需添加一个polyfill。以下 sn-p 将适用于 IE11:

          // Polyfill:
          if (window.NodeList && !NodeList.prototype.forEach) {
            NodeList.prototype.forEach = function(callback, thisArg) {
              thisArg = thisArg || window;
              for (var i = 0; i < this.length; i++) {
                callback.call(thisArg, this[i], i, this);
              }
            };
          }
          
          // Main code:
          document.querySelectorAll('.container1 > span, .container2 > span')
            .forEach(function(span) {
              span.classList.add('highlight');
            });
          .highlight {
            background-color: yellow;
          }
          <div class="container1">
            <span>foo</span>
            <span>bar</span>
          </div>
          <div class="container2">
            <span>baz</span>
          </div>
          <div class="container3">
            <span>buzz</span>
          </div>

          【讨论】:

            【解决方案10】:

            如果你可以使用ES2015,你可以使用Array.from()getElementsByTagName()返回的HTMLCollection转换成一个真正的数组。如果您将第 11 行更改为以下内容,则其余代码将按原样运行:

            var input = Array.from(document.getElementsByTagName("input"));
            

            【讨论】:

              猜你喜欢
              • 2020-02-14
              • 2015-02-14
              • 2019-06-24
              • 2019-05-14
              • 1970-01-01
              • 2020-02-10
              • 1970-01-01
              • 2021-03-15
              • 1970-01-01
              相关资源
              最近更新 更多