forEach ist kein Funktionsfehler mit einem JavaScript-Array

145

Ich versuche eine einfache Schleife zu machen:

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

Aber ich bekomme folgenden Fehler:

VM384: 53 Nicht erfasster TypeError: parent.children.forEach ist keine Funktion

Obwohl parent.childrenProtokolle:

Geben Sie hier die Bildbeschreibung ein

Was könnte das Problem sein?

Hinweis: Hier ist eine JSFiddle .

alexchenco
quelle
Das gleiche Problem tritt bei element.s Geschwistern auf
Daut
@Daut ja, weil element.s Geschwister eine HTMLCollection zurückgibt und HTMLCollections nicht die forEach () -Methode haben
Freddo
1
Hey du, Google Searcher! Wenn Sie diese doppelte Lektüre lesen, überprüfen Sie, ob es für jedes mit einem Großbuchstaben E anstelle von foreach ist ....
Robert Sinclair

Antworten:

127

Erste Option: ForEach indirekt aufrufen

Das parent.childrenist ein Array-ähnliches Objekt. Verwenden Sie die folgende Lösung:

const parent = this.el.parentElement;

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

Das parent.childrenheißt NodeListTyp, der ein Array wie Objekt ist , weil:

  • Es enthält die lengthEigenschaft, die die Anzahl der Knoten angibt
  • Jeder Knoten ist ein Eigenschaftswert mit einem numerischen Namen, der bei 0 beginnt: {0: NodeObject, 1: NodeObject, length: 2, ...}

Weitere Details finden Sie in diesem Artikel .


Zweite Option: Verwenden Sie das iterierbare Protokoll

parent.childrenist ein HTMLCollection: das das iterierbare Protokoll implementiert . In einer ES2015-Umgebung können Sie die HTMLCollectionmit jeder Konstruktion verwenden, die iterables akzeptiert.

Verwendung HTMLCollectionmit dem Spread-Operator:

const parent = this.el.parentElement;

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

Oder mit dem for..ofZyklus (was meine bevorzugte Option ist):

const parent = this.el.parentElement;

for (const child of parent.children) {
  console.log(child);
}
Dmitri Pavlutin
quelle
Wenn ich Ihre Lösung verwende, habe ich keine Probleme mehr, aber der Code in der anonymisierten Funktion wird nicht ausgeführt. .so ..
Jérémy
Welchen Browser Sie verwenden, damit parent.children Ihnen mitteilt, dass es sich um eine Knotenliste handelt. In Firefox heißt es, dass es sich um eine HTMLCollection handelt. Wenn es eine Knotenliste wäre, würde .forEach () funktionieren
Freddo
104

parent.childrenist kein Array. Es ist HTMLCollection und es gibt keine forEachMethode. Sie können es zuerst in das Array konvertieren. Zum Beispiel in ES6:

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

oder mit dem Spread-Operator:

[...parent.children].forEach(function (child) {
    console.log(child)
});
madox2
quelle
9
Ich bevorzuge diese Lösung viel mehr als das Herumspielen mit dem Array-Prototyp.
Daut
Und diese Antwort ist (eine von) der richtigen Antwort auf die Frage des OP. parent.children ist eine HTMLCollection, die keine .forEach-Methode hat
Freddo
18

parent.childrengibt eine Knotenlistenliste zurück , technisch gesehen eine HTML-Sammlung . Das ist ein Array-ähnliches Objekt, aber kein Array. Sie können also keine Array-Funktionen direkt darüber aufrufen. In diesem Kontext können Sie dies Array.from()in ein reales Array konvertieren.

Array.from(parent.children).forEach(child => {
  console.log(child)
})
Rajaprabhu Aravindasamy
quelle
Nein, parent.children gibt keine nodeList zurück, sondern eine HTML-Sammlung. Nicht dasselbe. Wenn es eine Knotenliste wäre, würde .forEach funktionieren
Freddo
12

Eine naivere Version, zumindest sind Sie sicher, dass sie auf allen Geräten ohne Konvertierung und ES6 funktioniert:

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

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

Jean
quelle
2
Upvoted, weil all diese neuen ES6-Funktionen genau das Gleiche tun, was verfügbar war, aber auf unordentliche Weise, wie immer bei JS
Freddo
8

parent.childrenist ein HTMLCollectionArray-ähnliches Objekt. Zuerst müssen Sie es in eine reale konvertieren Array, um Array.prototypeMethoden zu verwenden .

const parent = this.el.parentElement
console.log(parent.children)
[].slice.call(parent.children).forEach(child => {
  console.log(child)
})
Dmitriy
quelle
2
Oder konvertieren Sie es nicht, sondern verwenden Sie .call () für .forEach ()?
nnnnnn
@nnnnnn Siehe meine Antwort unten.
Dmitri Pavlutin
Es gibt viele Möglichkeiten, ein Array-ähnliches Objekt in ein Array umzuwandeln :) Dies ist eine davon
Dmitriy
@DmitriyLoskutov Sie müssen es nicht konvertieren - JavaScript ist eine Sprache für die Eingabe von Enten. Verwenden Sie einfach diese Funktion.
Dmitri Pavlutin
5

Das ist , weil parent.childrenein NodeList , und es nicht die unterstützt .forEachMethode (wie ein Array NodeList artige Struktur ist , aber kein Array), so versuchen , es zu nennen , indem sie zuerst auf Array - Umwandlung unter Verwendung von

var children = [].slice.call(parent.children);
children.forEach(yourFunc);
Ammar Hasan
quelle
Nein, es ist keine NodeList, es ist eine HTML-Sammlung
Freddo
5

Es ist nicht erforderlichforEach , Sie können nur mit dem fromzweiten Parameter des ' iterieren , wie folgt :

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

Armfuß
quelle
Die traurige Nachricht ist, dass parent.children keine nodeList ist ... .from () funktioniert nicht.
Freddo
@Cedric Wenn Ihr Objekt keine NodeList ist, sollten Sie eine neue Frage speziell für die Adressierung stellen. Hier wird Downvoting verwendet, wenn die Antwort an sich falsch oder schädlich ist und, wie Sie anhand des Code-Snippets sehen können, alle Elemente des Objekts iteriert und gedruckt werden, was das Ziel der OP-Frage war.
Armfoot
Ja, das Problem ist, dass sich die Frage des OP auf eine HTML-Sammlung bezieht, nicht auf eine Knotenliste ... Die Antwort war also einfach nicht die Beantwortung der Frage
Freddo
@Cedric Diese Antwort wird auch über eine HTML-Sammlung iteriert, da Array.fromdas im ersten Parameter angegebene Objekt in ein Array konvertiert wird. Das Ergebnis ist das gleiche wie in der Antwort von madox2, ohne dass eine zusätzliche forEachSchleife ( Array.fromMDN- Dokumente) erforderlich ist .
Armfoot
4

Wenn Sie versuchen, eine Schleife NodeListwie folgt zu erstellen :

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

Ich kann Loop so empfehlen:

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

Persönlich habe ich verschiedene Möglichkeiten ausprobiert, aber die meisten haben nicht funktioniert, da ich eine Schleife durchlaufen wollte NodeList, aber diese funktioniert wie ein Zauber, probieren Sie es aus!

Das NodeListist kein Array, aber wir behandeln es als Array. Verwenden Sie Array.also. Sie müssen wissen, dass es in älteren Browsern nicht unterstützt wird!

Benötigen Sie weitere Informationen über NodeList? Bitte lesen Sie die Dokumentation zu MDN .

Elharony
quelle
1
Diese Antwort funktioniert offensichtlich auf nodeList. Das Problem ist parent.children gibt eine HTML-Sammlung zurück, die keine NodeList ist ...
Freddo
3

Da Sie Funktionen von ES6 ( Pfeilfunktionen ) verwenden, können Sie auch einfach eine for-Schleife wie die folgende verwenden:

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

Armfuß
quelle
Upvoted. Was für eine Verzerrung, die ES6-Syntax ... Bringt mich zum Weinen und ich komme aus einem C ++ - Hintergrund ...
Freddo
1

Sie können überprüfen, ob Sie forEach richtig eingegeben haben. Wenn Sie foreach wie in anderen Programmiersprachen eingegeben haben, funktioniert dies nicht.

Abdelsalam Megahed
quelle
0

Sie können childNodesanstelle von verwenden children, childNodesist auch zuverlässiger unter Berücksichtigung von Browserkompatibilitätsproblemen, weitere Informationen hier :

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

oder mit dem Spread-Operator:

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