可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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?
回答1:
No. 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) {...});
回答2:
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);
回答3:
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.
回答4:
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()
回答5:
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
回答6:
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
});
回答7:
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?
回答8:
It does not return an Array
, it returns a NodeList.