forEach bukan kesalahan fungsi dengan array JavaScript

145

Saya mencoba membuat loop sederhana:

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

Tapi saya mendapatkan kesalahan berikut:

VM384: 53 UnEught TypeError: parent.children.forEach bukan sebuah fungsi

Meskipun parent.childrenlog:

masukkan deskripsi gambar di sini

Apa yang bisa menjadi masalah?

Catatan: Ini JSFiddle .

alexchenco
sumber
Masalah yang sama terjadi dengan element.siblings
Daut
@Lakukan ya karena elemen.siblings mengembalikan HTMLCollection dan HTMLCollections tidak memiliki metode forEach ()
Freddo
1
hai kamu, pencari google! jika Anda membaca cek ganda ini bahwa masing-masing memiliki modal E dan bukannya foreach ....
Robert Sinclair

Jawaban:

127

Opsi pertama: aktifkan forEach secara tidak langsung

Ini parent.childrenadalah objek seperti Array. Gunakan solusi berikut:

const parent = this.el.parentElement;

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

The parent.childrenyaitu NodeListjenis, yang merupakan Array seperti objek karena:

  • Ini berisi lengthproperti, yang menunjukkan jumlah node
  • Setiap node adalah nilai properti dengan nama numerik, mulai dari 0: {0: NodeObject, 1: NodeObject, length: 2, ...}

Lihat lebih detail di artikel ini .


Opsi kedua: gunakan protokol iterable

parent.childrenadalah HTMLCollection: yang mengimplementasikan protokol iterable . Dalam lingkungan ES2015, Anda dapat menggunakan HTMLCollectiondengan konstruksi apa pun yang menerima iterables.

Gunakan HTMLCollectiondengan spread operator:

const parent = this.el.parentElement;

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

Atau dengan for..ofsiklus (yang merupakan pilihan pilihan saya):

const parent = this.el.parentElement;

for (const child of parent.children) {
  console.log(child);
}
Dmitri Pavlutin
sumber
Ketika saya menggunakan solusi Anda, saya tidak memiliki masalah lagi, tetapi kode di dalam fungsi anonim tidak dieksekusi. .so ..
Jérémy
Browser mana yang Anda gunakan sehingga parent.children memberi tahu Anda bahwa itu adalah nodeList. Di Firefox, itu memberitahu saya adalah HTMLCollection. Jika itu adalah nodeList, .forEach () akan bekerja
Freddo
104

parent.childrenbukan sebuah array. Ini HTMLCollection dan tidak memiliki forEachmetode. Anda dapat mengonversikannya ke array terlebih dahulu. Misalnya dalam ES6:

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

atau menggunakan operator spread:

[...parent.children].forEach(function (child) {
    console.log(child)
});
madox2
sumber
9
Saya lebih suka solusi ini lebih dari mengacaukan prototipe Array.
Daut
Dan jawaban ini adalah (salah satu) jawaban yang benar untuk pertanyaan OP. parent.children adalah HTMLCollection yang tidak memiliki metode .forEach
Freddo
18

parent.childrenakan mengembalikan daftar daftar simpul , secara teknis Koleksi html . Itu adalah array seperti objek, tetapi bukan array, jadi Anda tidak bisa memanggil fungsi array secara langsung. Pada konteks ini Anda dapat menggunakan Array.from()untuk mengubahnya menjadi array nyata,

Array.from(parent.children).forEach(child => {
  console.log(child)
})
Rajaprabhu Aravindasamy
sumber
Tidak, parent.children tidak mengembalikan nodeList tetapi Koleksi HTML. Bukan hal yang sama. Jika itu adalah nodeList, .forEach akan bekerja
Freddo
12

Versi yang lebih naif , setidaknya Anda yakin itu akan berfungsi pada semua perangkat, tanpa konversi dan ES6:

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

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

Jean
sumber
2
Terpilih karena semua fungsi ES6 baru ini melakukan hal baik yang sama persis yang tersedia, tetapi dengan cara yang berantakan, seperti biasa dengan JS
Freddo
8

parent.childrenadalah HTMLCollectionobjek yang mirip array. Pertama, Anda harus mengubahnya menjadi metode nyata Arrayuntuk digunakan Array.prototype.

const parent = this.el.parentElement
console.log(parent.children)
[].slice.call(parent.children).forEach(child => {
  console.log(child)
})
Dmitriy
sumber
2
Atau jangan mengonversinya, tetapi gunakan .call () pada .forEach ()?
nnnnnn
@nnnnnn Lihat jawaban saya di bawah ini.
Dmitri Pavlutin
Ada banyak cara untuk mengonversi objek mirip array ke Array :) Ini salah satunya
Dmitriy
@DmitriyLoskutov Anda tidak perlu mengubahnya - JavaScript adalah bahasa pengetik bebek. Cukup gunakan fitur ini.
Dmitri Pavlutin
5

Itu karena parent.childrenadalah NodeList , dan itu tidak mendukung .forEachmetode (karena NodeList adalah array seperti struktur tetapi bukan array), jadi cobalah untuk menyebutnya dengan terlebih dahulu mengubahnya ke array menggunakan

var children = [].slice.call(parent.children);
children.forEach(yourFunc);
Ammar Hasan
sumber
Tidak, ini bukan NodeList, ini adalah Koleksi HTML
Freddo
5

Tidak perlu untuk ituforEach , Anda dapat beralih menggunakan hanya fromparameter kedua, seperti:

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

Lengan
sumber
Berita sedihnya adalah parent.children bukan nodeList ... .dari () tidak akan berfungsi.
Freddo
@Cedric jika objek Anda bukan NodeList, maka Anda harus mengajukan pertanyaan baru khusus untuk mengatasinya. Di sini, downvoting digunakan ketika jawabannya secara intrinsik salah atau berbahaya dan, seperti yang Anda lihat pada cuplikan kode, semua elemen objek diulang dan dicetak, yang merupakan tujuan dari pertanyaan OP.
Armfoot
Yap, masalahnya adalah bahwa pertanyaan OP terkait dengan Koleksi HTML, bukan nodeList ... Jadi jawabannya sama sekali tidak menjawab pertanyaan
Freddo
@Cedric jawaban ini juga akan beralih di atas Koleksi HTML karena Array.frommengubah objek yang diberikan dalam parameter pertama menjadi array. Hasilnya sama dengan jawaban madox2 tanpa perlu forEachloop tambahan ( Array.fromMDN docs).
Armfoot
4

Jika Anda mencoba untuk mengulang NodeListseperti ini:

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

Saya sangat merekomendasikan untuk melakukannya:

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

Secara pribadi, saya sudah mencoba beberapa cara tetapi kebanyakan dari mereka tidak bekerja karena saya ingin mengulang NodeList, tetapi yang ini berfungsi seperti pesona, cobalah!

Ini NodeListbukan Array, tapi kami memperlakukannya sebagai Array, menggunakan Array.Jadi, Anda perlu tahu bahwa itu tidak didukung di browser lama!

Perlu informasi lebih lanjut tentang NodeList? Silakan baca dokumentasinya di MDN .

Elharony
sumber
1
Jawaban ini jelas bekerja pada nodeList. Masalahnya adalah parent.children mengembalikan Koleksi HTML, yang bukan nodeList ...
Freddo
3

Karena Anda menggunakan fitur ES6 ( fungsi panah ), Anda juga dapat menggunakan loop for seperti ini:

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

Lengan
sumber
Terpilih. Betapa berbelit-belitnya, sintaks ES6, meskipun ... Membuat saya ingin menangis, dan saya berasal dari latar belakang C ++ ...
Freddo
1

Anda dapat memeriksa apakah Anda mengetik untukEach dengan benar, jika Anda mengetik foreach seperti dalam bahasa pemrograman lain itu tidak akan berfungsi.

Abdelsalam Megahed
sumber
0

Anda bisa menggunakan childNodesalih-alih children, childNodesjuga lebih andal mengingat masalah kompatibilitas browser, info lebih lanjut di sini :

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

atau menggunakan operator spread:

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