使用 Array.forEach 迭代 getElementsByClassName 的结果

发布于 2024-09-26 11:18:40 字数 537 浏览 7 评论 0原文

我想迭代一些 DOM 元素,我正在这样做:

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});

但出现错误:

document.getElementsByClassName("myclass").forEach 不是函数

我使用 Firefox 3 的函数,因此我知道 getElementsByClassNameArray.forEach 都存在。这工作正常:

[2, 5, 9].forEach( function(element, index, array) {
  //do stuff
});

getElementsByClassName 的结果是一个数组吗?如果不是,那是什么?

I want to iterate over some DOM elements, I'm doing this:

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});

but I get an error:

document.getElementsByClassName("myclass").forEach is not a function

I am using Firefox 3 so I know that both getElementsByClassName and Array.forEach are present. This works fine:

[2, 5, 9].forEach( function(element, index, array) {
  //do stuff
});

Is the result of getElementsByClassName an Array? If not, what is it?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

太阳男子 2024-10-03 11:18:40

不,这不是一个数组。正如 在 DOM4 中指定的,它是一个 HTMLCollection (至少在现代浏览器中。旧版浏览器返回NodeList)。

在所有现代浏览器(几乎任何其他 IE <= 8)中,您可以调用 Array 的 forEach 方法,向其传递元素列表(无论是 HTMLCollection 还是 NodeList) 作为 this 值:

var els = document.getElementsByClassName("myclass");

Array.prototype.forEach.call(els, function(el) {
    // Do stuff here
    console.log(el.tagName);
});

// Or
[].forEach.call(els, function (el) {...});

如果您很高兴能够使用 ES6(即您可以安全地忽略 Internet Explorer 或者您正在使用 ES5 转译器) ,您可以使用 Array.from< /代码>

Array.from(els).forEach((el) => {
    // Do stuff here
    console.log(el.tagName);
});

No, it's not an array. As specified in DOM4, it's an HTMLCollection (in modern browsers, at least. Older browsers returned a NodeList).

In all modern browsers (pretty much anything other IE <= 8), you can call Array's forEach method, passing it the list of elements (be it HTMLCollection or NodeList) as the this value:

var els = document.getElementsByClassName("myclass");

Array.prototype.forEach.call(els, function(el) {
    // Do stuff here
    console.log(el.tagName);
});

// Or
[].forEach.call(els, function (el) {...});

If you're in the happy position of being able to use ES6 (i.e. you can safely ignore Internet Explorer or you're using an ES5 transpiler), you can use Array.from:

Array.from(els).forEach((el) => {
    // Do stuff here
    console.log(el.tagName);
});
天煞孤星 2024-10-03 11:18:40

您可以使用 Array.from 将集合转换为数组,这比 Array.prototype.forEach.call 更干净:

Array.from(document.getElementsByClassName("myclass")).forEach(
    function(element, index, array) {
        // do stuff
    }
);

在不支持 的旧版浏览器中Array.from,你需要使用Babel之类的东西。


ES6 还添加了此语法:

[...document.getElementsByClassName("myclass")].forEach(
    (element, index, array) => {
        // do stuff
    }
);

使用 ... 进行剩余解构适用于所有类似数组的对象,而不仅仅是数组本身,然后使用良好的旧数组语法从值构造数组。


虽然替代函数 querySelectorAll (这有点使得 getElementsByClassName 过时)返回一个本身具有 forEach 的集合,但其他方法如 map< /code> 或 filter 丢失,因此此语法仍然有用:

[...document.querySelectorAll(".myclass")].map(
    (element, index, array) => {
        // do stuff
    }
);

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);

You can use Array.from to convert collection to array, which is way cleaner than Array.prototype.forEach.call:

Array.from(document.getElementsByClassName("myclass")).forEach(
    function(element, index, array) {
        // do stuff
    }
);

In older browsers which don't support Array.from, you need to use something like Babel.


ES6 also adds this syntax:

[...document.getElementsByClassName("myclass")].forEach(
    (element, index, array) => {
        // do stuff
    }
);

Rest destructuring with ... works on all array-like objects, not only arrays themselves, then good old array syntax is used to construct an array from the values.


While the alternative function querySelectorAll (which kinda makes getElementsByClassName obsolete) returns a collection which does have forEach natively, other methods like map or filter are missing, so this syntax is still useful:

[...document.querySelectorAll(".myclass")].map(
    (element, index, array) => {
        // do stuff
    }
);

[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);
娇柔作态 2024-10-03 11:18:40

或者您可以使用querySelectorAll,它返回 NodeList

document.querySelectorAll('.myclass').forEach(...)

现代浏览器支持(包括Edge,但不支持IE):
我可以使用 querySelectorAll
NodeList.prototype.forEach()

MDN: Document.querySelectorAll()

Or you can use querySelectorAll which returns NodeList:

document.querySelectorAll('.myclass').forEach(...)

Supported by modern browsers (including Edge, but not IE):
Can I use querySelectorAll
NodeList.prototype.forEach()

MDN: Document.querySelectorAll()

唠甜嗑 2024-10-03 11:18:40

getElementsByClassName() 的结果不是一个数组,而是一个类似数组的对象。具体来说,它称为 HTMLCollection,不要与 NodeList 混淆(它有自己的 forEach() 方法)。

使用 ES2015 转换类数组对象以便与 Array.prototype.forEach() 一起使用的一种简单方法(尚未提及)是使用展开运算符或 传播语法

const elementsArray = document.getElementsByClassName('myclass');

[...elementsArray].forEach((element, index, array) => {
    // do something
});

The result of getElementsByClassName() is not an Array, but an array-like object. Specifically it's called an HTMLCollection, not to be confused with NodeList (which has it's own forEach() method).

One simple way with ES2015 to convert an array-like object for use with Array.prototype.forEach() that hasn't been mentioned yet is to use the spread operator or spread syntax:

const elementsArray = document.getElementsByClassName('myclass');

[...elementsArray].forEach((element, index, array) => {
    // do something
});
匿名的好友 2024-10-03 11:18:40

getElementsByClassName 在现代浏览器中返回 HTMLCollection

这是
类似于参数的数组对象,可通过 for...of 循环进行迭代,请参阅下面的内容MDN 文档对此是这么说的:

for...of 语句创建一个迭代可迭代对象的循环
包括:内置字符串、数组、类数组对象(例如参数)
或 NodeList)、TypedArray、Map、Set 和用户定义的迭代。它
调用自定义迭代挂钩,其中包含要执行的语句
对象的每个不同属性的值。

Javascript 示例

for (const element of document.getElementsByClassName("classname")){
   element.style.display="none";
}

Typescript 示例

let elements = document.getElementsByClassName('classname');
let i;

for (i = 0; i < elements.length; i++) {

  if (elements[i] instanceof HTMLElement) {
    elements[i].style.display = "none";
  }

}

getElementsByClassName returns HTMLCollection in modern browsers.

which is
array-like object similar to arguments which is iteratable by for...of loop see below what MDN doc is saying about it:

The for...of statement creates a loop iterating over iterable objects,
including: built-in String, Array, Array-like objects (e.g., arguments
or NodeList), TypedArray, Map, Set, and user-defined iterables. It
invokes a custom iteration hook with statements to be executed for the
value of each distinct property of the object.

Javascript Example

for (const element of document.getElementsByClassName("classname")){
   element.style.display="none";
}

Typescript Example

let elements = document.getElementsByClassName('classname');
let i;

for (i = 0; i < elements.length; i++) {

  if (elements[i] instanceof HTMLElement) {
    elements[i].style.display = "none";
  }

}
听你说爱我 2024-10-03 11:18:40

编辑:尽管新版本的 HTML 中的返回类型已更改(请参阅 Tim Down 的更新答案),但下面的代码仍然有效。

正如其他人所说,它是一个 NodeList。这是一个完整的、有效的示例,您可以尝试:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script>
            function findTheOddOnes()
            {
                var theOddOnes = document.getElementsByClassName("odd");
                for(var i=0; i<theOddOnes.length; i++)
                {
                    alert(theOddOnes[i].innerHTML);
                }
            }
        </script>
    </head>
    <body>
        <h1>getElementsByClassName Test</h1>
        <p class="odd">This is an odd para.</p>
        <p>This is an even para.</p>
        <p class="odd">This one is also odd.</p>
        <p>This one is not odd.</p>
        <form>
            <input type="button" value="Find the odd ones..." onclick="findTheOddOnes()">
        </form>
    </body>
</html>

这适用于 Win 7 上的 IE 9、FF 5、Safari 5 和 Chrome 12。

Edit: Although the return type has changed in new versions of HTML (see Tim Down's updated answer), the code below still works.

As others have said, it's a NodeList. Here's a complete, working example you can try:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <script>
            function findTheOddOnes()
            {
                var theOddOnes = document.getElementsByClassName("odd");
                for(var i=0; i<theOddOnes.length; i++)
                {
                    alert(theOddOnes[i].innerHTML);
                }
            }
        </script>
    </head>
    <body>
        <h1>getElementsByClassName Test</h1>
        <p class="odd">This is an odd para.</p>
        <p>This is an even para.</p>
        <p class="odd">This one is also odd.</p>
        <p>This one is not odd.</p>
        <form>
            <input type="button" value="Find the odd ones..." onclick="findTheOddOnes()">
        </form>
    </body>
</html>

This works in IE 9, FF 5, Safari 5, and Chrome 12 on Win 7.

一绘本一梦想 2024-10-03 11:18:40

对于打字稿,我更喜欢迭代

for(let element of Array.from(document.querySelectorAll('.myclass'))){
   //my code
}

for typescript I prefer iterating for

for(let element of Array.from(document.querySelectorAll('.myclass'))){
   //my code
}
风轻花落早 2024-10-03 11:18:40

如前所述,getElementsByClassName 返回一个 HTMLCollection,其定义为

[Exposed=Window]
interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

以前,某些浏览器返回 NodeList< /em> 相反。

[Exposed=Window]
interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

区别很重要,因为 DOM4 现在将 NodeList 定义为可迭代的。

根据 Web IDL 草案,

实现声明为可迭代的接口的对象
支持迭代以获得一系列值。

<块引用>

注意:在 ECMAScript 语言绑定中,接口
iterable 将具有“entries”、“forEach”、“keys”、“values” 和
@@iterator 属性 < a href="http://heycam.github.io/webidl/#dfn-interface-prototype-object" rel="nofollow noreferrer">接口原型对象。

这意味着,如果您想使用 forEach,您可以使用返回 NodeList 的 DOM 方法,例如 querySelectorAll

document.querySelectorAll(".myclass").forEach(function(element, index, array) {
  // do stuff
});

请注意,这尚未得到广泛支持。另请参阅 Node.childNodes 的 forEach 方法?

As already said, getElementsByClassName returns a HTMLCollection, which is defined as

[Exposed=Window]
interface HTMLCollection {
  readonly attribute unsigned long length;
  getter Element? item(unsigned long index);
  getter Element? namedItem(DOMString name);
};

Previously, some browsers returned a NodeList instead.

[Exposed=Window]
interface NodeList {
  getter Node? item(unsigned long index);
  readonly attribute unsigned long length;
  iterable<Node>;
};

The difference is important, because DOM4 now defines NodeLists as iterable.

According to Web IDL draft,

Objects implementing an interface that is declared to be iterable
support being iterated over to obtain a sequence of values.

Note: In the ECMAScript language binding, an interface that is
iterable will have “entries”, “forEach”, “keys”, “values” and
@@iterator properties on its interface prototype object.

That means that, if you want to use forEach, you can use a DOM method which returns a NodeList, like querySelectorAll.

document.querySelectorAll(".myclass").forEach(function(element, index, array) {
  // do stuff
});

Note this is not widely supported yet. Also see forEach method of Node.childNodes?

別甾虛僞 2024-10-03 11:18:40

getElementsByClassName 的结果是数组吗?

如果不是,那是什么?

与所有返回多个元素的 DOM 方法一样,它是一个 NodeList,请参阅 https:// developer.mozilla.org/en/DOM/document.getElementsByClassName

Is the result of getElementsByClassName an Array?

No

If not, what is it?

As with all DOM methods that return multiple elements, it is a NodeList, see https://developer.mozilla.org/en/DOM/document.getElementsByClassName

最美的太阳 2024-10-03 11:18:40

这是更安全的方法:

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);

This is the safer way:

var elements = document.getElementsByClassName("myclass");
for (var i = 0; i < elements.length; i++) myFunction(elements[i]);
狼性发作 2024-10-03 11:18:40

最简单的解决方案:

Object.assign(HTMLCollection.prototype, {
  forEach(event) {
    Array.prototype.forEach.call(this, (element) => event(element));
  },
});

之后你可以这样写:

document
  .getElementsByClassName("disable")
  .forEach((element) => alert(element.classList[0]));

The simplest solution:

Object.assign(HTMLCollection.prototype, {
  forEach(event) {
    Array.prototype.forEach.call(this, (element) => event(element));
  },
});

After that you can write like this:

document
  .getElementsByClassName("disable")
  .forEach((element) => alert(element.classList[0]));

????

好多鱼好多余 2024-10-03 11:18:40

这是我在 jsperf 上创建的测试:
https://jsperf.com/vanillajs-loop-through-elements-of- class

Chrome 和 Firefox 中性能最好的版本是旧的 for 循环与 document.getElementsByClassName 的结合:

var elements = document.getElementsByClassName('testClass'), elLength = elements.length;
for (var i = 0; i < elLength; i++) {
    elements.item(i).textContent = 'Tested';
};

在 Safari 中,这个变体是赢家:

var elements = document.querySelectorAll('.testClass');
elements.forEach((element) => {
    element.textContent = 'Tested';
});

如果您想要所有浏览器中性能最好的变体,它可能是这个:

var elements = document.getElementsByClassName('testClass');
Array.from(elements).map(
    (element) => {
        return element.textContent = 'Tested';
    }
);

Here is a test I created on jsperf:
https://jsperf.com/vanillajs-loop-through-elements-of-class

The most perfomant version in Chrome and Firefox is the good old for loop in combination with document.getElementsByClassName:

var elements = document.getElementsByClassName('testClass'), elLength = elements.length;
for (var i = 0; i < elLength; i++) {
    elements.item(i).textContent = 'Tested';
};

In Safari this variant is the winner:

var elements = document.querySelectorAll('.testClass');
elements.forEach((element) => {
    element.textContent = 'Tested';
});

If you want the most perfomant variant for all browsers it might be this one:

var elements = document.getElementsByClassName('testClass');
Array.from(elements).map(
    (element) => {
        return element.textContent = 'Tested';
    }
);
爱冒险 2024-10-03 11:18:40

使用此代码将 forEach 方法添加到 HTMLCollection

/**
 *
 * @type {Function}
 */
HTMLCollection.prototype.forEach = HTMLCollection.prototype.forEach ||
    function (callBack) {
        for (let i = 0; i < this.length; i++) {
            callBack(this[i])
        }
    };

然后您的代码将起作用:

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});

Use this code to add forEach method to HTMLCollection

/**
 *
 * @type {Function}
 */
HTMLCollection.prototype.forEach = HTMLCollection.prototype.forEach ||
    function (callBack) {
        for (let i = 0; i < this.length; i++) {
            callBack(this[i])
        }
    };

Then your code will work:

document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
  //do stuff
});
淡莣 2024-10-03 11:18:40

它不返回Array,而是返回NodeList

It does not return an Array, it returns a NodeList.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文