forEach non è un errore di funzione con l'array JavaScript


145

Sto cercando di fare un semplice ciclo:

const parent = this.el.parentElement
console.log(parent.children)
parent.children.forEach(child => {
  console.log(child)
})

Ma ottengo il seguente errore:

VM384: 53 Tipo non rilevato Errore: parent.children.forEach non è una funzione

Anche se parent.childrenregistri:

inserisci qui la descrizione dell'immagine

Quale potrebbe essere il problema?

Nota: ecco un JSFiddle .


Lo stesso problema si verifica con element.siblings
Daut

@Daut sì perché element.siblings restituisce un HTMLCollection e HTMLCollections non hanno il metodo forEach ()
Freddo

1
ehi tu, cercatore di google! se stai leggendo questo doppio controllo che è per Ognuno con la E maiuscola invece di foreach ....
Robert Sinclair

Risposte:


127

Prima opzione: invocare per ogni indirettamente

L'oggetto parent.childrenè un array come. Utilizzare la seguente soluzione:

const parent = this.el.parentElement;

Array.prototype.forEach.call(parent.children, child => {
  console.log(child)
});

Il parent.childrenIS NodeListtipo, che è una matrice come oggetto perché:

  • Contiene la lengthproprietà, che indica il numero di nodi
  • Ogni nodo è un valore di proprietà con nome numerico, a partire da 0: {0: NodeObject, 1: NodeObject, length: 2, ...}

Vedi maggiori dettagli in questo articolo .


Seconda opzione: utilizzare il protocollo iterabile

parent.childrenè un HTMLCollection: che implementa il protocollo iterabile . In un ambiente ES2015, è possibile utilizzare il HTMLCollectioncon qualsiasi costruzione che accetta iterables.

Utilizzare HTMLCollectioncon l'operatore di diffusione:

const parent = this.el.parentElement;

[...parent.children].forEach(child => {
  console.log(child);
});

O con il for..ofciclo (che è la mia opzione preferita):

const parent = this.el.parentElement;

for (const child of parent.children) {
  console.log(child);
}

Quando utilizzo la tua soluzione non ho più problemi, ma il codice all'interno della funzione anonima non viene eseguito. .so ..
Jérémy,

Quale browser utilizzare in modo che parent.children ti dica che è un nodeList. Su Firefox, mi dice che è un HTMLCollection. Se fosse un nodeList, .forEach () funzionerebbe
Freddo,

104

parent.childrennon è un array. È HTMLCollection e non ha forEachmetodo. Puoi prima convertirlo nell'array. Ad esempio in ES6:

Array.from(parent.children).forEach(child => {
    console.log(child)
});

o usando l'operatore spread:

[...parent.children].forEach(function (child) {
    console.log(child)
});

9
Preferisco questa soluzione molto più che fare scherzi con il prototipo di array.
Daut,

E questa risposta è (una delle) risposte corrette alla domanda dei PO. parent.children è un HTMLCollection che non ha un metodo .forEach
Freddo

18

parent.childrenrestituirà un elenco di nodi , tecnicamente una raccolta html . Questo è un array come un oggetto, ma non un array, quindi non è possibile chiamare direttamente le funzioni dell'array su di esso. In questo contesto puoi usarlo Array.from()per convertirlo in un array reale,

Array.from(parent.children).forEach(child => {
  console.log(child)
})

No, parent.children non restituisce un nodeList ma una raccolta HTML. Non è la stessa cosa Se fosse un elenco di nodi, .per ogni funzionerebbe
Freddo,

12

Una versione più ingenua , almeno sei sicuro che funzionerà su tutti i dispositivi, senza conversione ed ES6:

const children = parent.children;
for (var i = 0; i < children.length; i++){
    console.log(children[i]);
}

https://jsfiddle.net/swb12kqn/5/


2
Eseguito l'upgrade perché tutte queste nuove funzioni ES6 fanno esattamente la stessa buona vecchia cosa disponibile, ma in modo disordinato, come sempre con JS
Freddo,

8

parent.childrenè un HTMLCollectionoggetto simile a matrice. Innanzitutto, devi convertirlo Arrayin Array.prototypemetodi reali da usare .

const parent = this.el.parentElement
console.log(parent.children)
[].slice.call(parent.children).forEach(child => {
  console.log(child)
})

2
O non convertirlo, ma usa use .call () su .forEach ()?
nnnnnn,

@nnnnnn Vedi la mia risposta qui sotto.
Dmitri Pavlutin,

Esistono molti modi per convertire un oggetto simile ad un array in un array :) Questo è uno di questi
Dmitriy

@DmitriyLoskutov Non è necessario convertirlo - JavaScript è un linguaggio di digitazione anatra. Usa questa funzione.
Dmitri Pavlutin,

5

È perché parent.children è un NodeList e non supporta il .forEachmetodo (poiché NodeList è una struttura simile a un array ma non un array), quindi prova a chiamarlo convertendolo prima in array usando

var children = [].slice.call(parent.children);
children.forEach(yourFunc);

No, non è un NodeList, è una raccolta HTML
Freddo,

5

Non è necessario ilforEach , puoi iterare usando solo il fromsecondo parametro, in questo modo:

let nodeList = [{0: [{'a':1,'b':2},{'c':3}]},{1:[]}]
Array.from(nodeList, child => {
  console.log(child)
});


La triste notizia è che parent.children non è un nodeList ... .from () non funzionerà.
Freddo,

@Cedric se il tuo oggetto non è un NodeList, allora dovresti porre una nuova domanda specificamente per affrontarlo. Qui, il downvoting viene utilizzato quando la risposta è intrinsecamente sbagliata o dannosa e, come si può vedere dallo snippet di codice, tutti gli elementi dell'oggetto vengono ripetuti e stampati, che era l'obiettivo della domanda del PO.
Armfoot,

Sì, il problema è che la domanda del PO si riferiva a una raccolta HTML, non a un elenco di nodi ... Quindi la risposta non stava semplicemente rispondendo alla domanda
Freddo,

@Cedric questa risposta verrà ripetuta anche su una raccolta HTML poiché Array.fromconverte l'oggetto indicato nel primo parametro in un array. Il risultato è lo stesso della risposta di madox2 senza bisogno di un forEachloop aggiuntivo ( documenti Array.fromMDN ).
Armfoot,

4

Se stai cercando di eseguire il loop su un NodeListsimile:

const allParagraphs = document.querySelectorAll("p");

Consiglio vivamente di farlo in questo modo:

Array.prototype.forEach.call(allParagraphs , function(el) {
    // Write your code here
})

Personalmente, ho provato diversi modi, ma la maggior parte di loro non ha funzionato come volevo fare un giro NodeList, ma questo funziona come un incantesimo, provalo!

Non NodeListè un array, ma lo trattiamo come un array, usando Array.So, devi sapere che non è supportato nei browser più vecchi!

Hai bisogno di maggiori informazioni su NodeList? Si prega di leggere la sua documentazione su MDN .


1
Questa risposta ovviamente funziona su nodeList. Il problema è che parent.children restituisce una raccolta HTML, che non è un nodeList ...
Freddo

3

Dato che stai usando le funzionalità di ES6 ( funzioni freccia ), puoi anche semplicemente usare un ciclo for in questo modo:

for(let child of [{0: [{'a':1,'b':2},{'c':3}]},{1:[]}]) {
  console.log(child)
}


Upvoted. Che contorsione, la sintassi ES6, però ... Mi fa venire voglia di piangere, e vengo da uno sfondo C ++ ...
Freddo

1

È possibile controllare se si è digitato forEach correttamente, se si è digitato foreach come in altri linguaggi di programmazione non funzionerà.


0

È possibile utilizzare childNodesinvece di children, childNodesè anche più affidabile considerando i problemi di compatibilità del browser, maggiori informazioni qui :

parent.childNodes.forEach(function (child) {
    console.log(child)
});

o usando l'operatore spread:

[...parent.children].forEach(function (child) {
    console.log(child)
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.