Pertanyaan Untuk masing-masing lebih dari satu array dalam JavaScript?


Bagaimana saya bisa melewati semua entri dalam larik menggunakan JavaScript?

Saya pikir itu adalah sesuatu seperti ini:

forEach(instance in theArray)

Dimana theArray adalah array saya, tetapi ini tampaknya tidak benar.


3782
2018-02-17 13:51


asal


Jawaban:


TL; DR

  • Jangan gunakan for-in kecuali jika Anda menggunakannya dengan pengaman atau setidaknya menyadari mengapa itu mungkin menggigit Anda.
  • Taruhan terbaik Anda biasanya

    • Sebuah for-of loop (ES2015 + saja),
    • Array#forEach (spec | MDN) (atau kerabatnya some dan semacamnya) (ES5 + saja),
    • sederhana kuno for lingkaran,
    • atau for-in dengan perlindungan.

Tetapi ada banyak lebih banyak untuk dijelajahi, baca terus ...


JavaScript memiliki semantik kuat untuk perulangan melalui array dan objek seperti array. Saya telah membagi jawaban menjadi dua bagian: Pilihan untuk array asli, dan opsi untuk hal-hal yang hanya array-seperti, seperti arguments objek, objek iterable lain (ES2015 +), koleksi DOM, dan sebagainya.

Saya akan segera mencatat bahwa Anda dapat menggunakan opsi ES2015 sekarang, bahkan pada mesin ES5, oleh transpiling ES2015 ke ES5. Cari "ES2015 transpiling" / "ES6 transpiling" untuk lebih lanjut ...

Oke, mari kita lihat opsi kami:

Untuk Array Aktual

Anda memiliki tiga opsi ECMAScript 5 ("ES5"), versi yang paling banyak didukung saat ini, dan dua lainnya ditambahkan ECMAScript 2015 ("ES2015", "ES6"):

  1. Menggunakan forEach dan terkait (ES5 +)
  2. Gunakan yang sederhana for lingkaran
  3. Menggunakan for-in  benar
  4. Menggunakan for-of (gunakan iterator secara implisit) (ES2015 +)
  5. Gunakan iterator secara eksplisit (ES2015 +)

Detail:

1. Gunakan forEach dan terkait

Dalam lingkungan yang serba-modern (jadi, bukan IE8) di mana Anda memiliki akses ke Array fitur yang ditambahkan oleh ES5 (langsung atau menggunakan polyfills), dapat Anda gunakan forEach (spec | MDN):

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

forEach menerima fungsi panggilan balik dan, secara opsional, nilai untuk digunakan sebagai this saat memanggil callback itu (tidak digunakan di atas). Callback dipanggil untuk setiap entri dalam larik, dalam rangka, melewati entri yang tidak ada dalam larik yang jarang. Meskipun saya hanya menggunakan satu argumen di atas, callback dipanggil dengan tiga: Nilai setiap entri, indeks entri itu, dan referensi ke array yang Anda iterasi ulang (jika fungsi Anda belum memilikinya berguna ).

Kecuali Anda mendukung browser usang seperti IE8 (yang NetApps tunjukkan di lebih dari 4% pangsa pasar pada tulisan ini pada bulan September 2016), Anda dapat dengan senang hati menggunakan forEach di halaman web tujuan umum tanpa shim. Jika Anda memang perlu mendukung browser usang, shimming / polyfilling forEach mudah dilakukan (cari "es5 shim" untuk beberapa opsi).

forEach memiliki manfaat bahwa Anda tidak perlu mendeklarasikan pengindeksan dan variabel nilai dalam ruang lingkup yang mengandung, karena mereka disediakan sebagai argumen untuk fungsi iterasi, dan begitu baik scoped hanya untuk iterasi itu.

Jika Anda khawatir tentang biaya waktu proses pembuatan panggilan fungsi untuk setiap entri larik, jangan; rincian.

Selain itu, forEach adalah fungsi "loop through them all", tetapi ES5 mendefinisikan beberapa fungsi "work your way through the way and do things" yang berguna lainnya, termasuk:

  • every (berhenti mengulang saat pertama kali callback kembali false atau sesuatu yang falsey)
  • some (berhenti mengulang saat pertama kali callback kembali true atau sesuatu yang benar)
  • filter (membuat array baru termasuk elemen di mana fungsi filter kembali true dan menghilangkan yang mengembalikannya false)
  • map (membuat larik baru dari nilai yang dikembalikan oleh callback)
  • reduce (membangun nilai dengan berulang kali memanggil callback, meneruskan nilai-nilai sebelumnya; lihat spesifikasi untuk detail; berguna untuk menjumlahkan isi dari array dan banyak hal lainnya)
  • reduceRight (seperti reduce, tetapi bekerja dalam urutan menurun dan bukan naik)

2. Gunakan yang sederhana for lingkaran

Terkadang cara lama adalah yang terbaik:

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

Jika panjang array tidak akan berubah selama loop, dan itu dalam kode kinerja-sensitif (tidak mungkin), versi sedikit lebih rumit meraih panjang depan mungkin mungil sedikit lebih cepat:

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

Dan / atau menghitung mundur:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --index) {
    console.log(a[index]);
}

Tetapi dengan mesin JavaScript modern, sangat jarang Anda perlu menambah sedikit jus terakhir.

Di ES2015 dan lebih tinggi, Anda dapat membuat indeks dan variabel nilai lokal ke for lingkaran:

let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
}
//console.log(index); // Would cause "ReferenceError: index is not defined"
//console.log(value); // Would cause "ReferenceError: value is not defined"

Dan ketika Anda melakukan itu, bukan hanya value tetapi juga index dibuat ulang untuk setiap iterasi loop, yang berarti penutupan yang dibuat dalam badan loop menyimpan referensi ke index (dan value) dibuat untuk iterasi spesifik:

let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        alert("Index is: " + index);
    });
}

Jika Anda memiliki lima div, Anda akan mendapatkan "Index is: 0" jika Anda mengklik yang pertama dan "Index is: 4" jika Anda mengklik yang terakhir. Ini benar tidak bekerja jika Anda menggunakan var dari pada let.

3. Gunakan for-in  benar

Anda akan membuat orang-orang menyuruh Anda menggunakannya for-in, tapi bukan itu for-in adalah untuk. for-in loop melalui sifat benda yang bisa dihitung, bukan indeks array. Pesanan tidak dijamin, bahkan di ES2015 (ES6). ES2015 tidak mendefinisikan suatu perintah ke objek properti (via [[OwnPropertyKeys]], [[Enumerate]], dan hal-hal yang menggunakannya Object.getOwnPropertyKeys), tetapi tidak mendefinisikan itu for-in akan mengikuti perintah itu. (Detail dalam jawaban yang lain ini.)

Tetap saja bisa berguna, khususnya untuk jarang array, jika Anda menggunakan perlindungan yang tepat:

// `a` is a sparse array
var key;
var a = [];
a[0] = "a";
a[10] = "b";
a[10000] = "c";
for (key in a) {
    if (a.hasOwnProperty(key)  &&        // These are explained
        /^0$|^[1-9]\d*$/.test(key) &&    // and then hidden
        key <= 4294967294                // away below
        ) {
        console.log(a[key]);
    }
}

Perhatikan dua pemeriksaan:

  1. Bahwa objek itu ada sendiri properti dengan nama itu (bukan yang diwarisi dari prototipe), dan

  2. Bahwa kuncinya adalah string numerik basis-10 dalam bentuk string normal dan nilainya adalah <= 2 ^ 32 - 2 (yang adalah 4,294,967,294). Dari mana angka itu berasal? Ini bagian dari definisi indeks array dalam spesifikasi. Nomor lain (non-bilangan bulat, bilangan negatif, angka lebih besar dari 2 ^ 32 - 2) bukan indeks larik. Alasannya 2 ^ 32 - 2 adalah yang membuat nilai indeks terbesar lebih rendah dari 2 ^ 32 - 1, yang merupakan nilai maksimum sebuah array length bisa memperoleh. (Misalnya, panjang larik cocok dalam bilangan bulat unsigned 32-bit.) (Props untuk RobG untuk menunjukkan komentar di posting blog saya bahwa tes saya sebelumnya tidak benar.)

Itu sedikit tambahan biaya per iterasi perulangan pada sebagian besar array, tetapi jika Anda memiliki jarang Array, ini bisa menjadi cara yang lebih efisien untuk loop karena hanya loop untuk entri yang benar-benar ada. Misalnya, untuk susunan di atas, kami mengulang total tiga kali (untuk kunci "0", "10", dan "10000"- Ingat, mereka string), bukan 10,001 kali.

Sekarang, Anda tidak akan ingin menulis itu setiap waktu, jadi Anda dapat memasukkan ini ke dalam toolkit Anda:

function arrayHasOwnIndex(array, prop) {
    return array.hasOwnProperty(prop) && /^0$|^[1-9]\d*$/.test(prop) && prop <= 4294967294; // 2^32 - 2
}

Dan kemudian kami akan menggunakannya seperti ini:

for (key in a) {
    if (arrayHasOwnIndex(a, key)) {
        console.log(a[key]);
    }
}

Atau jika Anda tertarik hanya pada "ujian yang cukup baik untuk sebagian besar kasus", Anda dapat menggunakan ini, tetapi ketika sudah dekat, itu tidak benar:

for (key in a) {
    // "Good enough" for most cases
    if (String(parseInt(key, 10)) === key && a.hasOwnProperty(key)) {
        console.log(a[key]);
    }
}

4. Gunakan for-of (gunakan iterator secara implisit) (ES2015 +)

ES2015 menambahkan iterator ke JavaScript. Cara termudah untuk menggunakan iterator adalah yang baru for-of pernyataan. Terlihat seperti ini:

var val;
var a = ["a", "b", "c"];
for (val of a) {
    console.log(val);
}

Keluaran:

Sebuah
b
c

Di bawah selimut, yang mendapat iterator dari array dan loop melalui itu, mendapatkan nilai dari itu. Ini tidak memiliki masalah yang digunakan for-in memiliki, karena menggunakan iterator yang didefinisikan oleh objek (array), dan array mendefinisikan iterator mereka iterate melalui entri (bukan properti mereka). Tidak seperti for-in di ES5, urutan di mana entri yang dikunjungi adalah urutan numerik indeks mereka.

5. Gunakan iterator secara eksplisit (ES2015 +)

Terkadang, Anda mungkin ingin menggunakan iterator secara eksplisit. Anda juga bisa melakukan itu, meskipun jauh lebih buruk daripada for-of. Terlihat seperti ini:

var a = ["a", "b", "c"];
var it = a.values();
var entry;
while (!(entry = it.next()).done) {
    console.log(entry.value);
}

Iterator adalah obyek yang cocok dengan definisi Iterator dalam spesifikasi. Nya next metode mengembalikan yang baru objek hasil setiap kali Anda menyebutnya. Objek hasil memiliki properti, done, memberi tahu kami apakah sudah selesai, dan properti value dengan nilai untuk iterasi itu. (done adalah opsional jika itu akan terjadi false, value adalah opsional jika itu akan terjadi undefined.)

Arti dari value bervariasi tergantung pada iterator; dukungan array (setidaknya) tiga fungsi yang mengembalikan iterator:

  • values(): Ini yang saya gunakan di atas. Ia mengembalikan iterator di mana masing-masing value adalah entri larik untuk iterasi itu ("a", "b", dan "c" dalam contoh sebelumnya).
  • keys(): Mengembalikan iterator di mana masing-masing value adalah kunci untuk iterasi itu (jadi untuk kami a di atas, itulah yang akan terjadi "0", kemudian "1", kemudian "2").
  • entries(): Mengembalikan iterator di mana masing-masing value adalah array dalam bentuk [key, value] untuk iterasi itu.

Untuk Array-Like Objects

Selain dari array yang sebenarnya, ada juga array-like benda yang memiliki length properti dan properti dengan nama numerik: NodeList contoh, yang arguments objek, dll. Bagaimana kita mengulang isi mereka?

Gunakan salah satu opsi di atas untuk array

Setidaknya beberapa, dan mungkin sebagian besar atau bahkan semua, dari pendekatan array di atas sering berlaku juga untuk objek seperti-array:

  1. Menggunakan forEach dan terkait (ES5 +)

    Berbagai fungsi di Array.prototype adalah "sengaja generik" dan biasanya dapat digunakan pada objek seperti larik melalui Function#call atau Function#apply. (Lihat Peringatan untuk objek yang disediakan host di akhir jawaban ini, tapi ini masalah langka.)

    Misalkan Anda ingin menggunakannya forEach pada suatu Node's childNodes milik. Anda akan melakukan ini:

    Array.prototype.forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    

    Jika Anda akan melakukan itu banyak, Anda mungkin ingin mengambil salinan referensi fungsi menjadi variabel untuk digunakan kembali, misalnya:

    // (This is all presumably in some scoping function)
    var forEach = Array.prototype.forEach;
    
    // Then later...
    forEach.call(node.childNodes, function(child) {
        // Do something with `child`
    });
    
  2. Gunakan yang sederhana for lingkaran

    Tentunya, yang sederhana for loop berlaku untuk objek seperti larik.

  3. Menggunakan for-in  benar

    for-in dengan pengaman yang sama seperti array harus bekerja dengan objek seperti array juga; peringatan untuk benda-benda yang disediakan oleh tuan rumah pada # 1 di atas mungkin berlaku.

  4. Menggunakan for-of (gunakan iterator secara implisit) (ES2015 +)

    for-of akan menggunakan iterator yang disediakan oleh objek (jika ada); kita harus melihat bagaimana ini bermain dengan berbagai objek seperti array, terutama yang disediakan host. Misalnya, spesifikasi untuk NodeList dari querySelectorAll telah diperbarui untuk mendukung iterasi. Spesifikasi untuk HTMLCollection dari getElementsByTagName tidak.

  5. Gunakan iterator secara eksplisit (ES2015 +)

    Lihat # 4, kita harus melihat bagaimana iterator bermain.

Buat array yang benar

Di lain waktu, Anda mungkin ingin mengonversi objek seperti larik ke dalam larik yang benar. Melakukan hal itu ternyata mudah:

  1. Menggunakan slice metode array

    Kami bisa menggunakan slice metode array, yang seperti metode lain yang disebutkan di atas adalah "sengaja generik" dan dapat digunakan dengan objek seperti larik, seperti ini:

    var trueArray = Array.prototype.slice.call(arrayLikeObject);
    

    Jadi misalnya, jika kita ingin mengonversi NodeList menjadi array yang benar, kita bisa melakukan ini:

    var divs = Array.prototype.slice.call(document.querySelectorAll("div"));
    

    Lihat Peringatan untuk objek yang disediakan host di bawah. Secara khusus, perhatikan bahwa ini akan gagal di IE8 dan sebelumnya, yang tidak membiarkan Anda menggunakan objek yang disediakan host sebagai this seperti itu.

  2. Menggunakan spread syntax (...)

    Juga dimungkinkan untuk menggunakan ES2015 sebarkan sintaksis dengan mesin JavaScript yang mendukung fitur ini:

    var trueArray = [...iterableObject];
    

    Jadi misalnya, jika kita ingin mengonversi NodeList ke dalam array yang benar, dengan menyebar sintaks ini menjadi sangat ringkas:

    var divs = [...document.querySelectorAll("div")];
    
  3. Menggunakan Array.from  (spesifikasi) | (MDN)

    Array.from (ES2015 +, tetapi mudah polyfilled) menciptakan sebuah array dari objek seperti array, opsional melewati entri melalui fungsi pemetaan pertama. Begitu:

    var divs = Array.from(document.querySelectorAll("div"));
    

    Atau jika Anda ingin mendapatkan larik nama-nama tag dari elemen-elemen dengan kelas tertentu, Anda akan menggunakan fungsi pemetaan:

    // Arrow function (ES2015):
    var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName);
    
    // Standard function (since `Array.from` can be shimmed):
    var divs = Array.from(document.querySelectorAll(".some-class"), function(element) {
        return element.tagName;
    });
    

Peringatan untuk objek yang disediakan host

Jika Anda menggunakan Array.prototype berfungsi dengan disediakan host objek seperti array (daftar DOM dan hal-hal lain yang disediakan oleh browser daripada mesin JavaScript), Anda harus memastikan untuk menguji di lingkungan target Anda untuk memastikan objek yang disediakan host berperilaku dengan benar. Sebagian besar berperilaku dengan benar (sekarang), tetapi ini penting untuk diuji. Alasannya adalah sebagian besar Array.prototype metode yang cenderung ingin Anda gunakan bergantung pada objek yang disediakan host memberikan jawaban jujur ​​terhadap abstrak [[HasProperty]] operasi. Pada tulisan ini, browser melakukan pekerjaan yang sangat baik ini, tetapi spesifikasi 5.1 memang memungkinkan untuk kemungkinan objek yang disediakan host mungkin tidak jujur. Ini masuk §8.6.2, beberapa paragraf di bawah meja besar dekat awal bagian itu), di mana dikatakan:

Objek host dapat menerapkan metode internal ini dengan cara apa pun kecuali ditentukan lain; misalnya, satu kemungkinan adalah itu [[Get]] dan [[Put]] untuk objek host tertentu memang mengambil dan menyimpan nilai properti tetapi [[HasProperty]] selalu menghasilkan Salah.

(Saya tidak dapat menemukan kata kerja yang sepadan dalam spesifikasi ES2015, tetapi masih terikat pada kasus ini.) Sekali lagi, sejak artikel ini menulis objek-objek seperti-array yang disediakan oleh host umum di browser modern [NodeList contoh, misalnya] melakukan menangani [[HasProperty]] benar, tetapi penting untuk menguji.)


5976
2018-02-17 13:53



Edit: Jawaban ini benar-benar ketinggalan zaman. Untuk pendekatan yang lebih modern, lihatlah metode yang tersedia di array. Metode minat mungkin:

  • untuk setiap
  • peta
  • menyaring
  • zip
  • mengurangi
  • setiap
  • beberapa

Cara standar untuk mengulang array dalam JavaScript adalah vanila for-apa:

var length = arr.length,
    element = null;
for (var i = 0; i < length; i++) {
  element = arr[i];
  // Do something with element i.
}

Perhatikan, bagaimanapun, bahwa pendekatan ini hanya baik jika Anda memiliki larik yang padat, dan setiap indeks ditempati oleh elemen. Jika array jarang, maka Anda dapat mengalami masalah kinerja dengan pendekatan ini, karena Anda akan mengiterasi lebih banyak indeks yang tidak sangat ada dalam larik. Dalam hal ini, a for .. in-mungkin menjadi ide yang lebih baik. Namun, Anda harus menggunakan pengamanan yang tepat untuk memastikan bahwa hanya properti yang diinginkan dari larik (yaitu elemen larik) yang ditindaklanjuti, karena for..in-buka juga akan disebutkan di browser lawas, atau jika properti tambahan didefinisikan sebagai enumerable.

Di ECMAScript 5 akan ada metode forEach pada prototipe larik, tetapi tidak didukung di peramban lama. Jadi untuk dapat menggunakannya secara konsisten, Anda harus memiliki lingkungan yang mendukungnya (misalnya, Node.js untuk JavaScript sisi server), atau gunakan "Polyfill". Akan tetapi, Polyfill untuk fungsi ini sepele dan karena itu membuat kode lebih mudah dibaca, ini adalah polyfill yang bagus untuk disertakan.


451
2018-02-17 13:55



Jika Anda menggunakan jQuery perpustakaan, dapat Anda gunakan jQuery.each:

$.each(yourArray, function(index, value) {
  // do your stuff here
});

EDIT: 

Sebagai pertanyaan, pengguna ingin kode di javascript, bukan jquery sehingga pengeditannya

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

205
2018-02-17 14:01



Loop mundur

saya pikir membalikkan untuk loop layak disebutkan di sini:

for (var i = array.length; i--; ) {
     // process array[i]
}

Keuntungan:

  • Anda tidak perlu menyatakan sementara len variabel, atau dibandingkan dengan array.length pada setiap iterasi, yang mungkin menjadi pengoptimalan menit.
  • Menghapus saudara kandung dari DOM dalam urutan terbalik biasanya lebih efisien. (Browser perlu melakukan sedikit pergeseran elemen dalam susunan internal.)
  • Jika kamu memodifikasi larik while looping, at atau after index saya (misalnya Anda menghapus atau memasukkan item di array[i]), maka loop maju akan melewatkan item yang bergeser ke kiri ke posisi saya, atau proses ulang sayaitem yang digeser ke kanan. Dalam lingkaran tradisional, Anda bisa memperbarui saya untuk menunjuk ke item berikutnya yang perlu diproses - 1, tetapi hanya membalik arah iterasi sering kali a lebih sederhana dan solusi yang lebih elegan.
  • Begitu pula saat memodifikasi atau melepas bersarang Elemen DOM, diproses secara terbalik menghindari kesalahan. Misalnya, pertimbangkan memodifikasi innerHTML node induk sebelum menangani anak-anaknya. Pada saat simpul anak mencapai itu akan terlepas dari DOM, telah digantikan oleh anak yang baru dibuat ketika innerHTML orangtua ditulis.
  • ini singkat untuk mengetik, dan Baca baca, dari beberapa opsi lain yang tersedia. Meskipun kalah forEach() dan ke ES6 for ... of.

Kekurangan:

  • Ini memproses barang dalam urutan terbalik. Jika Anda sedang membangun array baru dari hasil, atau mencetak hal-hal di layar, secara alami output akan dibalik sehubungan dengan pesanan asli.
  • Berulang kali memasukkan saudara kandung ke dalam DOM sebagai anak pertama untuk mempertahankan pesanan mereka kurang efisien. (Browser akan terus menggeser hal-hal yang benar.) Untuk membuat simpul DOM secara efisien dan teratur, cukup loop ke depan dan tambahkan seperti biasa (dan juga gunakan "fragmen dokumen").
  • Lingkaran terbaliknya membingungkan untuk pengembang junior. (Anda dapat mempertimbangkan bahwa suatu keuntungan, tergantung pada pandangan Anda.)

Haruskah saya selalu menggunakannya?

Beberapa pengembang menggunakan reverse for loop secara default, kecuali ada alasan kuat untuk melakukan loop ke depan.

Meskipun perolehan kinerja biasanya tidak signifikan, itu semacam jeritan:

"Lakukan saja pada semua item dalam daftar, aku tidak peduli dengan pesanan!"

Namun dalam prakteknya itu tidak sebenarnya merupakan indikasi niat yang dapat diandalkan, karena itu tidak dapat dibedakan dari saat-saat itu ketika Anda melakukan peduli dengan pesanan, dan benar-benar perlu mengulang secara terbalik. Jadi, sebenarnya, konstruk lain diperlukan untuk secara akurat mengekspresikan maksud "tidak peduli", sesuatu yang saat ini tidak tersedia di sebagian besar bahasa, termasuk ECMAScript, tetapi yang bisa disebut, misalnya, forEachUnordered().

Jika pesanan tidak penting, dan efisiensi adalah kekhawatiran (dalam putaran paling dalam dari mesin game atau animasi), maka mungkin dapat diterima untuk menggunakan reverse for loop sebagai pola go-to Anda. Ingatlah bahwa melihat reverse for loop dalam kode yang ada tidak selalu berarti bahwa urutannya tidak relevan!

Lebih baik menggunakan forEach ()

Secara umum untuk kode tingkat yang lebih tinggi di mana kejelasan dan keamanan adalah kekhawatiran yang lebih besar, saya akan merekomendasikan penggunaan Array::forEach sebagai pola default Anda:

  • Sangat jelas untuk dibaca.
  • Itu menunjukkan itu saya tidak akan digeser dalam blok (yang selalu merupakan kemungkinan kejutan yang bersembunyi dalam waktu lama for dan while loop.)
  • Ini memberi Anda ruang lingkup gratis untuk penutupan.
  • Ini mengurangi kebocoran variabel lokal dan tabrakan tidak disengaja dengan (dan mutasi) variabel luar.

Kemudian ketika Anda melihat reverse for loop dalam kode Anda, itu adalah petunjuk bahwa itu dibalik untuk alasan yang baik (mungkin salah satu alasan yang dijelaskan di atas). Dan melihat forward for loop tradisional dapat menunjukkan bahwa pergeseran dapat terjadi.

(Jika diskusi tentang niat tidak masuk akal bagi Anda, maka Anda dan kode Anda dapat mengambil manfaat dari menonton kuliah Crockford Gaya Pemrograman & Otak Anda.)


Bagaimana cara kerjanya?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

Anda akan melihat itu i-- adalah klausa tengah (di mana kita biasanya melihat perbandingan) dan klausa terakhir kosong (biasanya kita lihat i++). Itu artinya itu i-- juga digunakan sebagai kondisi untuk kelanjutannya. Krusial, itu dieksekusi dan diperiksa sebelum setiap iterasi.

  • Bagaimana itu bisa dimulai array.length tanpa meledak?

    Karena i-- berjalan sebelum setiap iterasi, pada iterasi pertama kita akan benar-benar mengakses item di array.length - 1 yang menghindari masalah apa pun Array-out-of-batas  undefined item.

  • Mengapa tidak berhenti iterasi sebelum indeks 0?

    Loop akan berhenti iterasi ketika kondisi i-- mengevaluasi ke nilai falsey (ketika menghasilkan 0).

    Triknya tidak seperti itu --i, trailing i-- pengurangan operator i tapi menghasilkan nilainya sebelum penurunan. Konsol Anda dapat menunjukkan ini:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Jadi pada iterasi terakhir, saya sebelumnya 1 dan i-- ekspresi mengubahnya menjadi 0 tetapi sebenarnya menghasilkan 1 (Benar), dan begitu kondisi berlalu. Pada iterasi selanjutnya i-- perubahan saya untuk -1 tapi menghasilkan 0 (falsey), menyebabkan eksekusi untuk segera keluar dari bagian bawah loop.

    Di depan tradisional untuk loop, i++ dan ++i dapat dipertukarkan (seperti yang ditunjukkan oleh Douglas Crockford). Namun dalam reverse for loop, karena penurunan kita juga merupakan ekspresi kondisi kita, kita harus tetap dengan i-- jika kita ingin memproses item pada indeks 0.


Trivia

Beberapa orang suka menggambar panah kecil di bagian belakang for loop, dan diakhiri dengan kedipan:

for (var i = array.length; i --> 0 ;) {

Kredit pergi ke WYL untuk menunjukkan saya manfaat dan kengerian sebaliknya untuk loop.


88
2018-05-02 14:21



Beberapa Cbahasa-gaya digunakan foreach untuk mengulang melalui enumerasi. Di JavaScript ini dilakukan dengan for..in struktur lingkaran:

var index,
    value;
for (index in obj) {
    value = obj[index];
}

Ada tangkapan. for..in akan mengulang melalui masing-masing anggota enumerable objek, dan anggota pada prototipe. Untuk menghindari membaca nilai-nilai yang diwariskan melalui prototipe objek, cukup periksa apakah properti milik objek:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Selain itu, ECMAScript 5 telah menambahkan forEach metode untuk Array.prototypeyang dapat digunakan untuk menghitung lebih dari satu array menggunakan calback (polyfill ada dalam dokumen sehingga Anda masih dapat menggunakannya untuk browser yang lebih tua):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

Penting untuk dicatat itu Array.prototype.forEach tidak pecah saat panggilan balik kembali false. jQuery dan Underscore.js berikan variasi mereka sendiri each untuk menyediakan loop yang dapat dihubung-singkat.


71
2018-02-17 14:00



Jika Anda ingin mengulang array, gunakan tiga bagian standar for lingkaran.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

Anda bisa mendapatkan beberapa optimalisasi kinerja dengan caching myArray.length atau mengulanginya mundur.


30
2018-02-17 13:55



SEBUAH untuk setiap implementasi (lihat di jsFiddle):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

25
2018-04-10 00:26



Jika Anda tidak keberatan mengosongkan array:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

x akan berisi nilai terakhir y dan itu akan dihapus dari array. Anda juga bisa menggunakan shift() yang akan memberi dan menghapus item pertama dari y.


25
2018-03-10 02:37



Saya tahu ini adalah posting lama, dan ada begitu banyak jawaban yang bagus. Untuk sedikit lebih lengkap, saya pikir saya akan menggunakan satu lagi AngularJS. Tentu saja, ini hanya berlaku jika Anda menggunakan Angular, tentu saja, meskipun demikian saya ingin tetap menggunakannya.

angular.forEach mengambil 2 argumen dan argumen ketiga opsional. Argumen pertama adalah objek (array) untuk iterasi atas, argumen kedua adalah fungsi iterator, dan argumen ketiga opsional adalah konteks objek (pada dasarnya disebut di dalam loop sebagai 'ini'.

Ada berbagai cara untuk menggunakan loop forEach dari sudut. Yang paling sederhana dan mungkin paling banyak digunakan adalah

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Cara lain yang berguna untuk menyalin item dari satu array ke yang lain adalah

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Meskipun, Anda tidak perlu melakukan itu, Anda dapat melakukan hal berikut dan itu setara dengan contoh sebelumnya:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Sekarang ada pro dan kontra menggunakan angular.forEach berfungsi sebagai lawan yang dibangun di vanilla-flavored for lingkaran.

Pro

  • Mudah dibaca
  • Kemampuan menulis mudah
  • Jika tersedia, angular.forEach akan menggunakan ES5 forEach loop. Sekarang, saya akan mendapatkan efisien di bagian kontra, karena forEach loops banyak lebih lambat daripada untuk loop. Saya menyebutkan ini sebagai pro karena bagus untuk konsisten dan standar.

Pertimbangkan 2 loop bersarang berikut ini, yang melakukan hal yang sama persis. Katakanlah kita memiliki 2 larik objek dan setiap objek berisi larik hasil, yang masing-masing memiliki properti Nilai yang berupa string (atau apa pun). Dan katakanlah kita perlu mengulangi setiap hasil dan jika mereka sama kemudian melakukan beberapa tindakan:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

Diberikan ini adalah contoh hipotetis yang sangat sederhana, tetapi saya telah menulis triple embedded for loop menggunakan pendekatan kedua dan itu sangat sulit untuk dibaca, dan menulis dalam hal ini.

Cons

  • Efisiensi. angular.forEach, dan pribumi forEach, dalam hal ini, keduanya banyak lebih lambat dari biasanya for lingkaran .... tentang 90% lebih lambat. Jadi untuk set data besar, lebih baik untuk menempel pada penduduk asli for lingkaran.
  • Tidak ada istirahat, melanjutkan, atau mengembalikan dukungan. continue sebenarnya didukung oleh "kecelakaan", untuk melanjutkan dalam angular.forEach Anda menempatkan sederhana a return; pernyataan dalam fungsi seperti angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); yang akan menyebabkannya terus keluar dari fungsi untuk iterasi itu. Ini juga karena fakta bahwa penduduk asli forEach tidak mendukung istirahat atau melanjutkan.

Saya yakin ada banyak pro dan kontra lainnya, dan jangan ragu untuk menambahkan apa pun yang Anda inginkan. Saya merasakan hal itu, intinya, jika Anda membutuhkan efisiensi, tetaplah dengan penduduk asli for loop untuk kebutuhan perulangan Anda. Tapi, jika dataset Anda lebih kecil dan beberapa efisiensi tidak apa-apa menyerah dalam pertukaran untuk keterbacaan dan writability, maka dengan segala cara melempar angular.forEach pada bocah nakal itu.


25
2018-06-20 22:56