JS: itération du résultat de getElementsByClassName en utilisant Array.forEach
je veux itérer sur quelques éléments DOM, je fais ceci:
document.getElementsByClassName( "myclass" ).forEach( function(element, index, array) {
//do stuff
});
mais je reçois une erreur: document.getElementsByClassName ("myclass").forEach n'est pas une fonction
J'utilise Firefox 3 donc je sais que les deux getElementsByClassName
et Array.forEach
sont présents. Cela fonctionne très bien:
[2, 5, 9].forEach( function(element, index, array) {
//do stuff
});
est-ce que le résultat de getElementsByClassName
est un tableau? Si non, quel est-il?
8 réponses
Pas de. Comme spécifié dans DOM4 , c'est un HTMLCollection
(dans les navigateurs modernes, au moins. Les navigateurs plus anciens ont retourné un NodeList
).
dans tous les navigateurs modernes (à peu près tout autre IE < = 8), Vous pouvez appeler la méthode forEach
de Array, en lui passant la liste des éléments (que ce soit HTMLCollection
ou NodeList
) comme la valeur 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) {...});
vous pouvez utiliser Array.from
pour convertir la collection en tableau, qui est beaucoup plus propre que Array.prototype.forEach.call
:
Array.from(document.getElementsByClassName("myclass")).forEach(
function(element, index, array) {
// do stuff
}
);
dans les navigateurs plus anciens qui ne prennent pas en charge Array.from
, vous devez utiliser quelque chose comme Babel.
ES6 ajoute également cette syntaxe:
[...document.getElementsByClassName("myclass")].forEach(
(element, index, array) => {
// do stuff
}
);
Rest destructuring with ...
fonctionne sur tous les objets en forme de tableau, non seulement les tableaux eux-mêmes, puis bon vieux tableau la syntaxe est utilisée pour construire un tableau de valeurs.
alors que la fonction alternative querySelectorAll
(qui rend en quelque sorte getElementsByClassName
obsolète) renvoie une collection qui a forEach
nativement, d'autres méthodes comme map
ou filter
sont manquantes, donc cette syntaxe est encore utile:
[...document.querySelectorAll(".myclass")].map(
(element, index, array) => {
// do stuff
}
);
[...document.querySelectorAll(".myclass")].map(element => element.innerHTML);
Edit: bien que le type de retour ait changé dans les nouvelles versions de HTML (voir la réponse mise à jour de Tim Down), le code ci-dessous fonctionne toujours.
comme d'autres l'ont dit, c'est un NodeList. Voici un exemple complet et fonctionnel que vous pouvez essayer:
<!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>
cela fonctionne dans IE 9, FF 5, Safari 5, et Chrome 12 sur Win 7.
ou vous pouvez utiliser querySelectorAll
qui retourne NodeList :
document.querySelectorAll('.myclass').forEach(...)
pris en charge par les navigateurs modernes (y compris Edge, mais pas IE):
puis-je utiliser querySelectorAll
NodeList.prototype.forEach ()
est-ce que le résultat de getElementsByClassName est un tableau?
Non
sinon, qu'est-ce que c'est?
comme pour toutes les méthodes DOM qui renvoient plusieurs éléments, C'est une NodeList, voir https://developer.mozilla.org/en/DOM/document.getElementsByClassName
le résultat de getElementsByClassName()
n'est pas un tableau, mais un objet semblable à un tableau . Spécifiquement, il est appelé un HTMLCollection
, à ne pas confondre avec NodeList
( qui a son propre forEach()
méthode ).
un moyen simple avec ES2015 pour convertir un objet de type tableau pour une utilisation avec Array.prototype.forEach()
qui n'a pas encore été mentionné est d'utiliser l'opérateur de propagation ou syntaxe de propagation :
const elementsArray = document.getElementsByClassName('myclass');
[...elementsArray].forEach((element, index, array) => {
// do something
});
comme déjà dit, getElementsByClassName
retourne un HTMLCollection , qui est défini comme
[Exposed=Window]
interface HTMLCollection {
readonly attribute unsigned long length;
getter Element? item(unsigned long index);
getter Element? namedItem(DOMString name);
};
auparavant, certains navigateurs renvoyaient un NodeList à la place.
[Exposed=Window]
interface NodeList {
getter Node? item(unsigned long index);
readonly attribute unsigned long length;
iterable<Node>;
};
la différence est importante, car DOM4 définit maintenant NodeList s comme itérable.
selon Web IDL draft,
Objets implémentant une interface qui est déclarée itérable soutien itéré pour obtenir une séquence de valeurs.
Note : dans la reliure du langage ECMAScript, une interface qui est itérable aura des "entrées", "forEach", "touches", "valeurs" et @@iterator propriétés sur son interface objet prototype .
cela signifie que, si vous voulez utiliser forEach
, vous pouvez utiliser une méthode DOM qui retourne un NodeList , comme querySelectorAll
.
document.querySelectorAll(".myclass").forEach(function(element, index, array) {
// do stuff
});
notez que cela n'est pas encore largement soutenu. Voir aussi pour chaque méthode de Noeud.childNodes?