Javascript bagaimana untuk mendapatkan elemen induk. Teknik DOM: elemen ibu bapa, anak dan jiran. Mencegah Tindakan Lalai

The untuk setiap() kaedah melaksanakan fungsi yang disediakan sekali untuk setiap elemen tatasusunan.

Sumber untuk contoh interaktif ini disimpan dalam repositori GitHub. Jika anda ingin menyumbang kepada projek contoh interaktif, sila klon https://github.com/mdn/interactive-examples dan hantarkan permintaan tarik kepada kami.

Sintaks

arr .forEach(callback(currentValue [, indeks [, array]]) [, thisArg ])

Parameter

panggilan balik Fungsi untuk melaksanakan pada setiap elemen. Ia menerima antara satu dan tiga argumen: currentValue Elemen semasa sedang diproses dalam tatasusunan. indeks Pilihan Nilai semasa indeks dalam tatasusunan. array Pilihan Tatasusunan forEach() telah dipanggil. thisArg Nilai Pilihan untuk digunakan seperti ini semasa melaksanakan panggilan balik.

Nilai pulangan

Penerangan

forEach() memanggil fungsi panggil balik yang disediakan sekali untuk setiap elemen dalam tatasusunan dalam tertib menaik. Ia tidak digunakan untuk sifat indeks yang telah dipadamkan atau tidak dimulakan. (Untuk tatasusunan yang jarang, .)

panggilan balik dipanggil dengan tiga hujah:

  1. nilai unsur tersebut
  2. indeks unsur
  3. objek Array sedang dilalui

Jika parameter thisArg diberikan kepada forEach() , ia akan digunakan sebagai nilai panggil balik ini. Nilai thisArg akhirnya boleh diperhatikan oleh panggil balik ditentukan mengikut peraturan biasa untuk menentukan ini dilihat oleh fungsi .

Julat elemen yang diproses oleh forEach() ditetapkan sebelum panggilan balik pertama. Elemen yang dilampirkan pada tatasusunan selepas panggilan ke forEach() bermula tidak akan dilawati oleh panggilan balik . Jika unsur tatasusunan yang sedia ada diubah atau dipadamkan, nilainya yang dihantar ke panggil balik akan menjadi nilai pada masa forEach() melawatnya; elemen yang dipadam sebelum dilawati tidak dilawati. Jika elemen yang telah dilawati dialih keluar (mis. menggunakan shift()) semasa lelaran, elemen kemudian akan dilangkau. (Lihat contoh ini, di bawah.)

forEach() melaksanakan fungsi panggil balik sekali untuk setiap elemen tatasusunan; tidak seperti map() atau reduce() ia sentiasa mengembalikan nilai yang tidak ditentukan dan tidak boleh dirantai. Kes penggunaan biasa adalah untuk melaksanakan kesan sampingan pada penghujung rantai.

forEach() tidak mengubah tatasusunan yang mana ia dipanggil. (Walau bagaimanapun, panggilan balik boleh berbuat demikian)

Tiada cara untuk menghentikan atau memecahkan gelung forEach() selain dengan melemparkan pengecualian. Jika anda memerlukan tingkah laku sedemikian, kaedah forEach() adalah alat yang salah.

Penamatan awal boleh dicapai dengan:

Kaedah tatasusunan: every() , some() , find() , dan findIndex() menguji elemen tatasusunan dengan predikat yang mengembalikan nilai kebenaran untuk menentukan sama ada lelaran selanjutnya diperlukan.

Contoh

Tiada operasi untuk nilai yang tidak dimulakan (tatasusunan jarang)

const arraySparse = biarkan numCallbackRuns = 0 arraySparse.forEach(fungsi(elemen)( console.log(elemen) numCallbackRuns++ )) console.log("numCallbackRuns: ", numCallbackRuns) // 1 // 3 // 7 // numCallbackRuns: 3 // komen: kerana anda dapat melihat nilai yang hilang antara 3 dan 7 tidak menggunakan fungsi panggil balik.

Menukar gelung for kepada forEach

item const = ["item1", "item2", "item3"] const copy = // sebelum untuk (biar i = 0; i< items.length; i++) { copy.push(items[i]) } // after items.forEach(function(item){ copy.push(item) })

Mencetak kandungan tatasusunan

Catatan: Untuk memaparkan kandungan tatasusunan dalam konsol, anda boleh menggunakan console.table() , yang mencetak versi terformat tatasusunan.

Contoh berikut menggambarkan pendekatan alternatif, menggunakan forEach() .

Kod berikut mencatat baris untuk setiap elemen dalam tatasusunan:

Fungsi logArrayElements(elemen, indeks, tatasusunan) ( console.log("a[" + index + "] = " + element) ) // Perhatikan bahawa indeks 2 dilangkau, kerana tiada item di // kedudukan itu dalam tatasusunan... .forEach(logArrayElements) // log: // a = 2 // a = 5 // a = 9

Menggunakan thisArg

Contoh (yang dibuat) berikut mengemas kini sifat objek daripada setiap entri dalam tatasusunan:

Function Counter() ( this.sum = 0 this.count = 0 ) Counter.prototype.add = function(array) ( array.forEach(function(entry) ( this.sum += entry ++this.count ), ini ) // ^---- Nota ) const obj = new Counter() obj.add() obj.count // 3 obj.sum // 16

Memandangkan parameter thisArg (this) diberikan kepada forEach() , ia dihantar ke panggil balik setiap kali ia dipanggil. Panggilan balik menggunakannya sebagai nilai ini.

Fungsi salinan objek

Kod berikut mencipta salinan objek yang diberikan.

Terdapat pelbagai cara untuk membuat salinan objek. Yang berikut hanyalah satu cara dan dibentangkan untuk menerangkan cara Array.prototype.forEach() berfungsi dengan menggunakan ECMAScript 5 Object.* fungsi sifat meta.

Fungsi copy(obj) ( const copy = Object.create(Object.getPrototypeOf(obj)) const propNames = Object.getOwnPropertyNames(obj) propNames.forEach(function(nama) ( const desc = Object.getOwnPropertyDescriptor(obj, nama) Object .defineProperty(copy, name, desc) )) return copy ) const obj1 = ( a: 1, b: 2 ) const obj2 = copy(obj1) // obj2 kelihatan seperti obj1 sekarang

Jika tatasusunan diubah semasa lelaran, elemen lain mungkin dilangkau.

Contoh berikut mencatatkan "satu" , "dua" , "empat" .

Apabila entri yang mengandungi nilai "two" is reached, the first entry of the whole array is shifted off-resulting in all remaining entries moving up one position. Because element "four" is now at an earlier position in the array, "three" will be skipped.!}

forEach() tidak membuat salinan tatasusunan sebelum lelaran.

Biarkan perkataan = ["satu", "dua", "tiga", "empat"] perkataan.forEach(fungsi(perkataan) ( console.log(perkataan) jika (perkataan === "dua") ( words.shift( ) ) )) // satu // dua // empat

Ratakan tatasusunan

Contoh berikut hanya di sini untuk tujuan pembelajaran. Jika anda ingin meratakan tatasusunan menggunakan kaedah terbina dalam anda boleh menggunakan Array.prototype.flat() (yang dijangka menjadi sebahagian daripada ES2019, dan sudah dilaksanakan dalam sesetengah penyemak imbas).

/** * Meratakan tatasusunan yang diluluskan dalam tatasusunan satu dimensi * * @params (tatasusunan) arr * @mengembalikan (tatasusunan) */ fungsi mendatar(arr) ( hasil const = arr.forEach((i) => ( jika (Array. isArray(i)) ( result.push(...flatten(i)) ) else ( result.push(i) )) return result ) // Masalah const penggunaan = , 8, 9]] ratakan(masalah) / /

Nota tentang penggunaan Janji atau fungsi async

biarkan ratings = biarkan jumlah = 0 biarkan sumFunction = async function (a, b) ( return a + b ) ratings.forEach(async function(rating) ( sum = tunggu sumFunction(jumlah, rating) )) console.log(sum) // Output yang dijangka: 14 // Output sebenar: 0

Spesifikasi

Spesifikasi Status Komen
Draf Terkini ECMAScript (ECMA-262)
Draf
ECMAScript 2015 (Edisi ke-6, ECMA-262)
Takrifan "Array.prototype.forEach" dalam spesifikasi itu.
Standard
ECMAScript 5.1 (ECMA-262)
Takrifan "Array.prototype.forEach" dalam spesifikasi itu.
Standard Definisi awal. Dilaksanakan dalam JavaScript 1.6.

Keserasian pelayar

Jadual keserasian dalam halaman ini dijana daripada data berstruktur. Jika anda ingin menyumbang kepada data, sila semak https://github.com/mdn/browser-compat-data dan hantarkan permintaan tarik kepada kami.

Kemas kini data keserasian pada GitHub

DesktopMudah alihPelayan
ChromeHujungFirefoxinternet ExplorerOperaSafaripaparan web AndroidChrome untuk AndroidFirefox untuk AndroidOpera untuk AndroidSafari pada iOSInternet SamsungNode.js
untuk setiapSokongan penuh Chrome 1Sokongan penuh Edge 12Sokongan penuh Firefox 1.5IE Sokongan penuh 9Opera Sokongan penuh YaSafari Sokongan penuh 3WebView Android Sokongan penuh ≤37Chrome Android Sokongan penuh 18Firefox Android Sokongan penuh 4Opera Android Sokongan penuh YaSafari iOS Sokongan penuh 1Samsung Internet Android Sokongan penuh 1.0nodejs Sokongan penuh Ya
  • I. Mengulang ke atas tatasusunan sebenar
    1. untukSetiap kaedah dan kaedah yang berkaitan
    2. untuk gelung
    3. Penggunaan yang betul bagi gelung untuk...dalam
    4. for...of loop (penggunaan tersirat iterator)
    5. Penggunaan iterator secara eksplisit
  • II. Mengulangi objek seperti tatasusunan
    1. Menggunakan kaedah untuk mengulangi tatasusunan sebenar
    2. Tukar kepada tatasusunan sebenar
    3. Nota pada objek masa jalan

I. Mengulang ke atas tatasusunan sebenar

Pada masa ini, terdapat tiga cara untuk mengulangi elemen tatasusunan sebenar:

  1. kaedah Array.prototype.forEach ;
  2. klasik untuk gelung
  3. "betul" dibina untuk...dalam gelung.

Di samping itu, tidak lama lagi, dengan kemunculan standard ECMAScript 6 (ES 6) baharu, dua lagi kaedah dijangka:

  1. for...of loop (penggunaan tersirat iterator);
  2. penggunaan eksplisit iterator.

1. Kaedah untukSetiap dan kaedah yang berkaitan

Jika projek anda direka bentuk untuk menyokong ciri standard ECMAScript 5 (ES5), anda boleh menggunakan salah satu daripada inovasinya - kaedah forEach.

Contoh penggunaan:

Var a = ["a", "b", "c"]; a.forEach(function(entry) ( console.log(entry); ));

Secara umum, menggunakan forEach memerlukan penyambungan perpustakaan emulasi es5-shim untuk penyemak imbas yang tidak menyokong kaedah ini secara asli. Ini termasuk IE 8 dan lebih awal, yang masih digunakan di beberapa tempat.

Kelebihan forEach ialah tidak perlu mengisytiharkan pembolehubah tempatan untuk menyimpan indeks dan nilai elemen tatasusunan semasa, kerana ia secara automatik dihantar ke fungsi panggil balik sebagai argumen.

Jika anda bimbang tentang kemungkinan kos panggilan balik pada setiap elemen, jangan risau dan baca ini.

forEach direka bentuk untuk melelaran melalui semua elemen tatasusunan, tetapi selain itu, ES5 menawarkan beberapa kaedah yang lebih berguna untuk lelaran melalui semua atau beberapa elemen serta melakukan beberapa tindakan padanya:

  • setiap - mengembalikan benar jika untuk setiap elemen tatasusunan panggilan balik mengembalikan nilai yang boleh ditukar kepada benar.
  • sesetengah - mengembalikan benar jika untuk sekurang-kurangnya satu elemen tatasusunan panggilan balik mengembalikan nilai yang boleh ditukar kepada benar.
  • penapis - mencipta tatasusunan baharu yang merangkumi unsur tatasusunan asal yang mana panggilan balik itu kembali benar.
  • peta - mencipta tatasusunan baharu yang terdiri daripada nilai yang dikembalikan oleh panggilan balik.
  • mengurangkan - mengurangkan tatasusunan kepada nilai tunggal, menggunakan panggilan balik pada setiap elemen tatasusunan secara bergilir-gilir, bermula dengan yang pertama (boleh berguna untuk mengira jumlah elemen tatasusunan dan fungsi ringkasan lain).
  • reduceRight - berfungsi sama seperti mengurangkan, tetapi berulang melalui elemen dalam susunan terbalik.

2. Untuk gelung

Baik lama untuk peraturan:

Var a = ["a", "b", "c"]; indeks var; untuk (indeks = 0; indeks< a.length; ++index) { console.log(a); }

Jika panjang tatasusunan adalah malar sepanjang gelung, dan gelung itu sendiri tergolong dalam bahagian kod yang kritikal prestasi (yang tidak mungkin), maka anda boleh menggunakan versi "lebih optimum" untuk menyimpan panjang tatasusunan :

Var a = ["a", "b", "c"]; indeks var, len; untuk (indeks = 0, len = a.panjang; indeks< len; ++index) { console.log(a); }

Secara teorinya, kod ini sepatutnya berjalan sedikit lebih cepat daripada yang sebelumnya.

Jika susunan elemen tidak penting, maka anda boleh pergi lebih jauh dari segi pengoptimuman dan menyingkirkan pembolehubah untuk menyimpan panjang tatasusunan, menukar susunan carian ke sebaliknya:

Var a = ["a", "b", "c"]; indeks var; untuk (indeks = a.panjang - 1; indeks >= 0; --index) ( console.log(a); )

Walau bagaimanapun, dalam enjin JavaScript moden permainan pengoptimuman seperti itu biasanya tidak bermakna apa-apa.

3. Penggunaan yang betul bagi...dalam gelung

Jika anda dinasihatkan untuk menggunakan for...in loop, ingat bahawa lelaran ke atas tatasusunan bukanlah perkara yang dimaksudkan. Bertentangan dengan salah tanggapan biasa, gelung for...in tidak berulang ke atas indeks tatasusunan, sebaliknya melalui sifat terhitung objek.

Walau bagaimanapun, dalam beberapa kes, seperti mengulangi tatasusunan yang jarang, untuk...in boleh berguna, selagi anda mengambil langkah berjaga-jaga, seperti yang ditunjukkan dalam contoh di bawah:

// a - tatasusunan jarang var a = ; a = "a"; a = "b"; a = "c"; untuk (kunci var dalam a) ( jika (a.hasOwnProperty(key) && /^0$|^d*$/.test(key) && key<= 4294967294) { console.log(a); } }

Dalam contoh ini, dua semakan dilakukan pada setiap lelaran gelung:

  1. bahawa tatasusunan mempunyai sifatnya sendiri yang dipanggil kunci (tidak diwarisi daripada prototaipnya).
  2. kunci itu ialah rentetan yang mengandungi perwakilan perpuluhan bagi integer yang nilainya kurang daripada 4294967294 . Dari mana datangnya nombor terakhir? Daripada definisi indeks tatasusunan dalam ES5, yang menunjukkan bahawa indeks tertinggi yang boleh dimiliki oleh sesuatu elemen dalam tatasusunan ialah: (2^32 - 2) = 4294967294 .

Sudah tentu, semakan sedemikian akan mengambil masa yang tidak perlu apabila melaksanakan gelung. Tetapi dalam kes tatasusunan jarang, kaedah ini lebih cekap daripada gelung for, kerana dalam kes ini hanya elemen yang ditakrifkan secara eksplisit dalam tatasusunan akan diulang. Jadi, dalam contoh di atas, hanya 3 lelaran akan dilakukan (untuk indeks 0, 10 dan 10000) - berbanding 10001 dalam gelung for.

Untuk tidak menulis kod semak yang menyusahkan setiap kali anda perlu mengulangi tatasusunan, anda boleh menulisnya sebagai fungsi yang berasingan:

Fungsi arrayHasOwnIndex(array, key) ( return array.hasOwnProperty(key) && /^0$|^d*$/.test(key) && key<= 4294967294; }

Kemudian badan gelung dari contoh akan dikurangkan dengan ketara:

Untuk (masukkan a) ( jika (arrayHasOwnIndex(a, kunci)) ( console.log(a); ) )

Kod semak yang dibincangkan di atas adalah universal, sesuai untuk semua kes. Tetapi sebaliknya, anda boleh menggunakan versi yang lebih pendek, walaupun secara rasmi tidak betul sepenuhnya, tetapi sesuai untuk kebanyakan kes:

Untuk (masukkan a) ( jika (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) ( console.log(a); ) )

4. Untuk...gelung (penggunaan tersirat lelaran)

ES6, masih dalam status draf, harus memperkenalkan iterator kepada JavaScript.

Iterator ialah protokol yang dilaksanakan oleh objek yang mentakrifkan cara standard untuk mendapatkan urutan nilai (terhingga atau tidak terhingga).
Objek mempunyai iterator jika ia mentakrifkan kaedah next(), fungsi tanpa hujah yang mengembalikan objek dengan dua sifat:

  1. done (boolean) - benar jika iterator telah mencapai penghujung urutan boleh lelar. Jika tidak, nilainya adalah palsu.
  2. nilai - mentakrifkan nilai yang dikembalikan oleh iterator. Mungkin tidak ditentukan (hilang) jika harta yang dilakukan adalah benar.

Banyak objek terbina dalam, termasuk. tatasusunan sebenar mempunyai iterator secara lalai. Cara paling mudah untuk menggunakan iterator pada tatasusunan sebenar ialah menggunakan yang baharu untuk...daripada konstruk.

Contoh penggunaan untuk...daripada:

Varval; var a = ["a", "b", "c"]; untuk (val of a) ( console.log(val); )

Dalam contoh di atas, gelung for...of secara tersirat memanggil lelaran objek Array untuk mendapatkan setiap nilai tatasusunan.

5. Penggunaan iterator secara eksplisit

Iterator juga boleh digunakan secara eksplisit, walau bagaimanapun, dalam kes ini kod menjadi lebih rumit berbanding dengan gelung for...of. Ia kelihatan seperti ini:

Var a = ["a", "b", "c"]; entri var; manakala (!(entry = a.next()).done) ( console.log(entry.value); )

II. Mengulangi objek seperti tatasusunan

Sebagai tambahan kepada tatasusunan sebenar, dalam JavaScript terdapat juga objek seperti tatasusunan . Apa yang mereka ada persamaan dengan tatasusunan sebenar ialah mereka mempunyai sifat panjang dan sifat yang dinamakan sebagai nombor yang sepadan dengan unsur tatasusunan. Contohnya termasuk DOM koleksi NodeList dan argumen pseudo-array, tersedia dalam mana-mana fungsi/kaedah.

1. Menggunakan kaedah untuk lelaran ke atas tatasusunan sebenar

Sekurang-kurangnya, kebanyakan, jika tidak semua, kaedah lelaran ke atas tatasusunan sebenar boleh digunakan untuk lelaran ke atas objek seperti tatasusunan.

Konstruk untuk dan untuk...dalam boleh digunakan pada objek seperti tatasusunan dengan cara yang sama seperti ia digunakan pada tatasusunan sebenar.

forEach dan kaedah Array.prototype yang lain juga digunakan pada objek seperti tatasusunan. Untuk melakukan ini, anda perlu menggunakan Function.call atau Function.apply .

Sebagai contoh, jika anda ingin memohon untukEach kepada sifat childNodes bagi objek Node, anda akan melakukannya seperti ini:

Array.prototype.forEach.call(node.childNodes, function(child) ( // lakukan sesuatu dengan objek kanak-kanak));

Untuk menjadikan helah ini lebih mudah digunakan semula, anda boleh mengisytiharkan rujukan kepada kaedah Array.prototype.forEach dalam pembolehubah berasingan dan menggunakannya sebagai pintasan:

// (Dengan mengandaikan semua kod di bawah adalah dalam skop yang sama) var forEach = Array.prototype.forEach; // ... forEach.call(node.childNodes, function(child) ( // buat sesuatu dengan objek kanak-kanak));

Jika objek seperti tatasusunan mempunyai iterator, ia boleh digunakan secara eksplisit atau tersirat untuk lelaran ke atas objek dengan cara yang sama seperti tatasusunan sebenar.

2. Tukar kepada tatasusunan sebenar

Terdapat juga satu lagi cara yang sangat mudah untuk mengulangi objek seperti tatasusunan: menukarnya kepada tatasusunan sebenar dan gunakan mana-mana kaedah yang dibincangkan di atas untuk mengulangi tatasusunan sebenar. Untuk penukaran, anda boleh menggunakan kaedah Array.prototype.slice generik, yang boleh digunakan pada mana-mana objek seperti tatasusunan. Ini dilakukan dengan sangat mudah, seperti yang ditunjukkan dalam contoh di bawah:

Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);

Contohnya, jika anda ingin menukar koleksi NodeList kepada tatasusunan sebenar, anda memerlukan kod seperti ini:

Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);

3. Nota pada objek masa jalan

Jika anda menggunakan kaedah Array.prototype pada objek masa jalan (seperti koleksi DOM), maka anda harus sedar bahawa kaedah ini tidak dijamin berfungsi dengan betul dalam semua persekitaran masa jalan (termasuk penyemak imbas). Ini bergantung pada kelakuan objek tertentu dalam persekitaran pelaksanaan tertentu, atau lebih tepat lagi, tentang cara operasi abstrak HasProperty dilaksanakan dalam objek ini. Masalahnya ialah piawai ES5 itu sendiri membenarkan kemungkinan objek tidak berkelakuan berkenaan dengan operasi ini (lihat §8.6.2).

Oleh itu, adalah penting untuk menguji pengendalian kaedah Array.prototype dalam setiap persekitaran masa jalan (pelayar) di mana anda merancang untuk menggunakan aplikasi anda.