JS: iterazione del risultato di getElementsByClassName usando Array.forEach

Voglio ripetere su alcuni elementi DOM, sto facendo questo:

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

ma ottengo un errore: document.getElementsByClassName (“myclass”). forEach non è una funzione

Sto usando Firefox 3 quindi so che sono presenti sia getElementsByClassName che Array.forEach . Questo funziona bene:

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

Il risultato di getElementsByClassName una matrice? Se no, cos’è?

    No. Come specificato in DOM4 , è un HTMLCollection (nei browser moderni, almeno. I browser più vecchi hanno restituito un NodeList ).

    In tutti i browser moderni (praticamente qualsiasi altro IE <= 8), puoi chiamare il metodo forEach di Array, passandogli l’elenco di elementi (sia HTMLCollection o NodeList ) come this valore:

     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) {...}); 

    È ansible utilizzare Array.from per convertire la raccolta in array, che è molto più pulito di Array.prototype.forEach.call :

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

    Nei browser più vecchi che non supportano Array.from , è necessario utilizzare qualcosa come Babel.


    ES6 aggiunge anche questa syntax:

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

    Resto destrutturando con ... funziona su tutti gli oggetti tipo array, non solo sugli array stessi, quindi una buona syntax del vecchio array viene usata per build un array dai valori.


    Mentre la funzione alternativa querySelectorAll (che kinda rende obsoleto getElementsByClassName ) restituisce una raccolta che ha forEach nativamente, forEach altri metodi come map o filter , quindi questa syntax è ancora utile:

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

    Modifica: Sebbene il tipo di ritorno sia cambiato nelle nuove versioni di HTML (vedi la risposta aggiornata di Tim Down), il codice sottostante funziona ancora.

    Come altri hanno già detto, è una NodeList. Ecco un esempio completo e funzionante che puoi provare:

            

    getElementsByClassName Test

    This is an odd para.

    This is an even para.

    This one is also odd.

    This one is not odd.

    Funziona in IE 9, FF 5, Safari 5 e Chrome 12 su Windows 7.

    Oppure puoi usare querySelectorAll che restituisce NodeList :

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

    Supportato da browser moderni (incluso Edge, ma non IE):
    Posso usare querySelectorAll
    NodeList.prototype.forEach ()

    MDN: Document.querySelectorAll ()

    Il risultato di getElementsByClassName è una matrice?

    No

    Se no, cos’è?

    Come con tutti i metodi DOM che restituiscono più elementi, si tratta di una NodeList, vedere https://developer.mozilla.org/en/DOM/document.getElementsByClassName

    Il risultato di getElementsByClassName() non è una matrice, ma un object tipo array . In particolare si chiama HTMLCollection , da non confondere con NodeList ( che ha il proprio metodo forEach() ).

    Un modo semplice con ES2015 per convertire un object di tipo array per l’uso con Array.prototype.forEach() che non è stato ancora menzionato è quello di utilizzare l’operatore di spread o la syntax di diffusione :

     const elementsArray = document.getElementsByClassName('myclass'); [...elementsArray].forEach((element, index, array) => { // do something }); 

    Come già detto, getElementsByClassName restituisce un HTMLCollection , che è definito come

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

    In precedenza, alcuni browser restituivano invece un NodeList .

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

    La differenza è importante, perché DOM4 ora definisce NodeList come iterabile.

    Secondo la bozza di Web IDL ,

    Oggetti che implementano un’interfaccia dichiarata come supporto iterabile che viene iterata per ottenere una sequenza di valori.

    Nota : nel binding del linguaggio ECMAScript, un’interfaccia che è iterabile avrà “voci”, “forEach”, “chiavi”, “valori” e proprietà @ iterator sul suo object prototipo di interfaccia .

    Ciò significa che, se si desidera utilizzare forEach , è ansible utilizzare un metodo DOM che restituisce un NodeList , come querySelectorAll .

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

    Nota che questo non è ancora ampiamente supportato. Vedi anche un metodo per Node.childNode?

    Non restituisce una Array , restituisce una NodeList .