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 .


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

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

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

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/


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

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

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


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 .


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


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.


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)
});
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.