web-dev-qa-db-fra.com

JS: itération sur le résultat de getElementsByClassName à l'aide de Array.forEach

Je veux parcourir quelques éléments du DOM, je fais ceci:

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

mais j'obtiens une erreur: document.getElementsByClassName ("myclass"). forEach n'est pas une fonction

J'utilise Firefox 3, donc je sais que getElementsByClassName et Array.forEach sont tous deux présents. Cela fonctionne bien:

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

Le résultat de getElementsByClassName est-il un tableau? Si non, c'est quoi?

191
Steve Claridge

N ° Comme spécifié dans DOM4 , il s'agit d'un HTMLCollection (dans les navigateurs modernes Les navigateurs plus anciens donnaient 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 transmettant la liste des éléments (que ce soit HTMLCollection ou NodeList) en tant que 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) {...});
_

Si vous êtes capable d’utiliser ES6 (c’est-à-dire que vous pouvez ignorer Internet Explorer ou utiliser un transpiler ES5 en toute sécurité), vous pouvez utiliser Array.from :

_Array.from(els).forEach((el) => {
    // Do stuff here
    console.log(el.tagName);
});
_
311
Tim Down

Vous pouvez utiliser Array.from pour convertir une collection en tableau, ce qui est plus propre que Array.prototype.forEach.call:

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

Dans les anciens navigateurs qui ne supportent pas Array.from, vous devez utiliser quelque chose comme Babel.


ES6 ajoute également cette syntaxe:

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

La déstructuration des restes avec ... fonctionne sur tous les objets ressemblant à des tableaux, et pas seulement sur les tableaux eux-mêmes, puis la bonne syntaxe de tableau ancienne est utilisée pour construire un tableau à partir des valeurs.


Tandis que la fonction alternative querySelectorAll (qui rend un peu getElementsByClassName obsolète) renvoie une collection qui possède forEach de manière native, d'autres méthodes telles que map ou filter manquent, donc cette syntaxe est toujours utile:

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

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

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 ()

MDN: Document.querySelectorAll ()

18
icl7126

Éditer: 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 une liste de noeuds. Voici un exemple de travail complet 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.

14
james.garriss

Le résultat de getElementsByClassName() n'est pas un tableau, mais un objet semblable à un tableau . Plus précisément, il est appelé HTMLCollection, à ne pas confondre avec NodeList ( qui a sa propre méthode forEach() ).

Un moyen simple avec ES2015 de convertir un objet de type tableau à utiliser avec Array.prototype.forEach() qui n'a pas encore été mentionné consiste à utiliser l'opérateur étalé ou syntaxe étalée :

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

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

Le résultat de getElementsByClassName est-il un tableau?

Non

Si non, c'est quoi?

Comme avec toutes les méthodes DOM qui renvoient plusieurs éléments, il s’agit d’un NodeList, voir https://developer.mozilla.org/en/DOM/document.getElementsByClassName

5
Quentin

Comme déjà dit, getElementsByClassName renvoie un HTMLCollection , 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 plutôt NodeList .

[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 étant itérable.

Selon Web IDL projet,

Les objets implémentant une interface déclarée être itérable prennent en charge l'itération pour obtenir une séquence de valeurs.

Remarque : dans la liaison en langage ECMAScript, une interface qui est itérable aura "entrées", "forEach", "clés", "valeurs" et - @@ iterator propriétés sur ses objet prototype d'interface .

Cela signifie que si vous souhaitez utiliser forEach, vous pouvez utiliser une méthode DOM qui renvoie un NodeList , comme querySelectorAll .

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

Notez que ceci n'est pas encore largement supporté. Voir aussi pourChaque méthode de Node.childNodes?

3
Oriol

Il ne retourne pas un Array, il retourne un NodeList .

0
reko_t

C'est le moyen le plus sûr:

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

getElementsByClassName renvoie HTMLCollection dans les navigateurs modernes.

qui est un objet semblable à un tableau similaire aux arguments qui peut être itéré par la boucle for...of, voyez ci-dessous quoi MDN doc en dit:

L'instruction pour ... de crée une boucle qui parcourt des objets itératifs , y compris: une chaîne intégrée, un tableau, Objets ressemblant à des tableaux (par exemple, arguments ou NodeList), TypedArray, Map, Set et iterables définis par l’utilisateur. Il appelle un crochet d'itération personnalisé avec des instructions à exécuter pour la valeur de chaque propriété distincte de l'objet.

exemple

for (let element of getElementsByClassName("classname")){
   element.style.display="none";
}
0
Haritsinh Gohil