forEach nie jest błędem funkcji z tablicą JavaScript


145

Próbuję zrobić prostą pętlę:

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

Ale pojawia się następujący błąd:

VM384: 53 Uncaught TypeError: parent.children.forEach nie jest funkcją

Mimo że parent.childrendzienniki:

wprowadź opis obrazu tutaj

Jaki może być problem?

Uwaga: oto JSFiddle .


Ten sam problem występuje z elementem.siblings
Daut

@Daut tak, ponieważ element.siblings zwraca HTMLCollection, a HTMLCollections nie ma metody forEach ()
Freddo

1
hej ty, wyszukiwarce Google! jeśli czytasz to podwójnie, sprawdź, czy jest to forEach z wielką literą E zamiast foreach ....
Robert Sinclair

Odpowiedzi:


127

Pierwsza opcja: wywołaj forEach pośrednio

parent.childrenJest tablicą jak przedmiot. Skorzystaj z następującego rozwiązania:

const parent = this.el.parentElement;

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

Typ parent.childrenis NodeList, który jest obiektem typu Array, ponieważ:

  • Zawiera lengthwłaściwość, która wskazuje liczbę węzłów
  • Każdy węzeł jest wartością właściwości o nazwie numerycznej, zaczynając od 0: {0: NodeObject, 1: NodeObject, length: 2, ...}

Zobacz więcej szczegółów w tym artykule .


Druga opcja: użyj iterowalnego protokołu

parent.childrenjest HTMLCollection: który implementuje iterowalny protokół . W środowisku ES2015 można używać HTMLCollectionz dowolną konstrukcją, która akceptuje elementy iteracyjne.

Użyj HTMLCollectionz operatorem rozprzestrzeniania:

const parent = this.el.parentElement;

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

Lub z for..ofcyklem (który jest moją preferowaną opcją):

const parent = this.el.parentElement;

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

Kiedy używam twojego rozwiązania, nie mam więcej problemów, ale kod wewnątrz funkcji anonimowej nie jest wykonywany. .so ..
Jérémy

Z jakiej przeglądarki korzystasz, aby parent.children poinformował Cię, że jest to lista węzłów. W przeglądarce Firefox informuje mnie, że jest to HTMLCollection. Gdyby to była lista węzłów, .forEach () działałaby
Freddo

104

parent.childrennie jest tablicą. To jest HTMLCollection i nie ma forEachmetody. Możesz najpierw przekonwertować go na tablicę. Na przykład w ES6:

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

lub używając operatora rozprzestrzeniania:

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

9
Wolę to rozwiązanie znacznie bardziej niż majstrowanie przy prototypie Array.
Daut

A ta odpowiedź jest (jedną z) poprawnych odpowiedzi na pytanie PO. parent.children jest HTMLCollection które nie posiadają metodę .forEach
freddo

18

parent.childrenzwróci listę listy węzłów , technicznie rzecz biorąc, kolekcję html . Jest to obiekt podobny do tablicy, ale nie tablica, więc nie można bezpośrednio wywoływać funkcji tablicowych. W tym kontekście możesz użyć Array.from()do przekonwertowania tego na prawdziwą tablicę,

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

Nie, parent.children nie zwraca nodeList, ale kolekcję HTML. To nie to samo. Gdyby to była lista węzłów, .forEach działałoby
Freddo

12

Bardziej naiwna wersja, przynajmniej masz pewność, że będzie działać na wszystkich urządzeniach, bez konwersji i ES6:

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

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


2
Głos za pozytywnymi, ponieważ wszystkie te nowe funkcje ES6 robią dokładnie to samo, stare dobre rzeczy, które były dostępne, ale w niechlujny sposób, jak zawsze w JS
Freddo

8

parent.childrenjest HTMLCollectionobiektem podobnym do tablicy. Najpierw musisz przekonwertować to na rzeczywiste, Arrayaby użyć Array.prototypemetod.

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

2
Lub nie konwertuj go, ale użyj .call () na .forEach ()?
nnnnnn

@nnnnnn Zobacz moją odpowiedź poniżej.
Dmitri Pavlutin

Istnieje wiele sposobów na przekonwertowanie obiektu przypominającego tablicę na tablicę :) Oto jeden z nich
Dmitriy

@DmitriyLoskutov Nie musisz go konwertować - JavaScript jest językiem pisania typu kaczka. Po prostu użyj tej funkcji.
Dmitri Pavlutin

5

Dzieje się tak , ponieważ parent.childrenjest to lista NodeList i nie obsługuje .forEachmetody (ponieważ NodeList jest strukturą podobną do tablicy, ale nie tablicą), więc spróbuj ją wywołać, najpierw przekonwertując ją na tablicę za pomocą

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

Nie, to nie jest NodeList, to zbiór HTML
Freddo

5

Nie ma potrzebyforEach , możesz iterować używając tylko fromdrugiego parametru, na przykład:

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


Smutną wiadomością jest to, że parent.children nie jest nodeList ... .from () nie będzie działać.
Freddo

@Cedric, jeśli twój obiekt nie jest NodeList, powinieneś zadać nowe pytanie, dotyczące jego rozwiązania. W tym przypadku głosowanie w dół jest używane, gdy odpowiedź jest z natury błędna lub szkodliwa i, jak widać po fragmencie kodu, wszystkie elementy obiektu są iterowane i drukowane, co było celem pytania OP.
Armfoot

Tak, problem polega na tym, że pytanie OP dotyczyło kolekcji HTML, a nie nodeList ... Więc odpowiedź po prostu nie była odpowiedzią na pytanie
Freddo

@Cedric ta odpowiedź będzie również iterować po kolekcji HTML, ponieważ Array.fromkonwertuje obiekt podany w pierwszym parametrze na tablicę. Wynik jest taki sam, jak w odpowiedzi madox2 bez potrzeby dodatkowej forEachpętli ( dokumentacja Array.fromMDN ).
Armfoot

4

Jeśli próbujesz zapętlić coś NodeListtakiego:

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

Gorąco polecam zapętlić to w ten sposób:

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

Osobiście wypróbowałem kilka sposobów, ale większość z nich nie działała, ponieważ chciałem zapętlić nad a NodeList, ale ten działa jak urok, spróbuj!

To NodeListnie jest tablica, ale traktujemy ją jako tablicę, używając Array.Więc musisz wiedzieć, że nie jest obsługiwana w starszych przeglądarkach!

Potrzebujesz więcej informacji NodeList? Przeczytaj jego dokumentację na MDN .


1
Ta odpowiedź oczywiście działa na nodeList. Kłopot polega parent.children Zwraca Collection HTML, który nie jest NodeList ...
Freddo

3

Ponieważ używasz funkcji ES6 ( funkcji strzałkowych ), możesz po prostu użyć pętli for w następujący sposób:

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


Głosowano za. Co za skrzywienie, chociaż składnia ES6 ... Sprawia, że ​​chcę płakać, a wychodzę z tła C ++ ...
Freddo

1

Możesz sprawdzić, czy wpisałeś forEach poprawnie, jeśli wpisałeś foreach jak w innych językach programowania, to nie zadziała.


0

Możesz użyć childNodeszamiast children, childNodesjest również bardziej niezawodny, biorąc pod uwagę problemy ze zgodnością przeglądarki, więcej informacji tutaj :

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

lub używając operatora rozprzestrzeniania:

[...parent.children].forEach(function (child) {
    console.log(child)
});
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.