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.