Saya memang mencarinya, tetapi saya mencarinya forEach dan bukan hanya for. seperti yang dinyatakan, dalam c # itu sedikit berbeda, dan itu membingungkan saya :)
Dante1986
6
ECMAScript & nbsp; 6 mungkin akan mengandung konstruk "for ... of". Lihat ... dari (MDN) untuk informasi lebih lanjut. Anda sudah dapat mencobanya dengan versi Firefox terbaru.
Sebaliknya, di Python itu lebih efisien untuk menggunakan fungsi daripada penggunaan tradisional untuk loop. (Pertimbangkan itu i < lendan i++dapat dilakukan oleh mesin, bukan oleh penerjemah.)
joeytwiddle
Jawaban:
7022
TL; DR
Jangan gunakan for-inkecuali Anda menggunakannya dengan perlindungan atau setidaknya menyadari mengapa itu bisa menggigit Anda.
Tetapi ada banyak lagi untuk dijelajahi, baca terus ...
JavaScript memiliki semantik yang kuat untuk perulangan melalui array dan objek seperti array. Saya telah membagi jawaban menjadi dua bagian: Opsi untuk array asli, dan opsi untuk hal-hal yang hanya seperti array , seperti argumentsobjek, objek iterable lainnya (ES2015 +), koleksi DOM, dan sebagainya.
Aku akan segera dicatat bahwa Anda dapat menggunakan ES2015 pilihan sekarang , bahkan pada mesin ES5, oleh transpiling ES2015 untuk ES5. Cari "ES2015 transpiling" / "ES6 transpiling" untuk lebih ...
Oke, mari kita lihat opsi kami:
Untuk Array Aktual
Anda memiliki tiga opsi dalam ECMAScript 5 ("ES5"), versi yang paling banyak didukung saat ini, dan dua lagi ditambahkan dalam ECMAScript 2015 ("ES2015", "ES6"):
Gunakan forEachdan terkait (ES5 +)
Gunakan forloop sederhana
Gunakan for-indengan benar
Gunakan for-of(gunakan iterator secara implisit) (ES2015 +)
Gunakan iterator secara eksplisit (ES2015 +)
Detail:
1. Gunakan forEachdan terkait
Di lingkungan samar-samar modern (jadi, bukan IE8) di mana Anda memiliki akses ke Arrayfitur yang ditambahkan oleh ES5 (langsung atau menggunakan polyfill), Anda dapat menggunakan forEach( spec| MDN):
var a =["a","b","c"];
a.forEach(function(entry){
console.log(entry);});
forEachmenerima fungsi panggilan balik dan, secara opsional, nilai yang digunakan seperti thissaat memanggil panggilan balik itu (tidak digunakan di atas). Callback dipanggil untuk setiap entri dalam array, secara berurutan, melewatkan entri yang tidak ada dalam array 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 (jika fungsi Anda belum membuatnya berguna) ).
Kecuali jika Anda mendukung peramban usang seperti IE8 (yang NetApps tunjukkan di lebih dari 4% pangsa pasar pada tulisan ini pada September 2016), Anda dapat dengan senang hati menggunakan forEachlaman web tujuan umum tanpa shim. Jika Anda perlu mendukung browser yang usang, shimming / polyfilling forEachmudah dilakukan (cari "es5 shim" untuk beberapa opsi).
forEach memiliki manfaat bahwa Anda tidak harus mendeklarasikan pengindeksan dan nilai variabel dalam lingkup yang berisi, karena mereka disediakan sebagai argumen untuk fungsi iterasi, dan sangat baik hanya untuk iterasi itu.
Jika Anda khawatir tentang biaya runtime untuk membuat panggilan fungsi untuk setiap entri array, jangan; detail .
Selain itu, forEachadalah fungsi "loop through them all", tetapi ES5 mendefinisikan beberapa fungsi lain yang bermanfaat "bekerja dengan cara Anda melalui array dan melakukan sesuatu" fungsi, termasuk:
every(berhenti mengulang-ulang saat panggilan balik kembali falseatau sesuatu yang palsu)
some(berhenti mengulang-ulang saat panggilan balik kembali trueatau sesuatu yang benar)
filter(membuat array baru termasuk elemen tempat fungsi filter kembali truedan menghilangkan yang mengembalikannya false)
map (membuat array baru dari nilai yang dikembalikan oleh callback)
reduce (membangun nilai dengan berulang kali memanggil callback, meneruskan nilai sebelumnya; lihat spesifikasi untuk detail; berguna untuk menjumlahkan isi array dan banyak hal lainnya)
reduceRight(seperti reduce, tetapi bekerja dalam urutan menurun daripada urutan naik)
2. Gunakan forloop sederhana
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 (mungkin), versi yang sedikit lebih rumit meraih panjang depan mungkin kecil sedikit lebih cepat:
var index, len;var a =["a","b","c"];for(index =0, len = a.length; index < len;++index){
console.log(a[index]);}
Tetapi dengan mesin JavaScript modern, jarang Anda perlu menambah sedikit jus terakhir.
Di ES2015 dan lebih tinggi, Anda bisa membuat indeks dan variabel nilai lokal ke forloop:
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}//console.log(index); // would cause "ReferenceError: index is not defined"//console.log(value); // would cause "ReferenceError: value is not defined"
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}try{
console.log(index);}catch(e){
console.error(e);// "ReferenceError: index is not defined"}try{
console.log(value);}catch(e){
console.error(e);// "ReferenceError: value is not defined"}
Dan ketika Anda melakukan itu, bukan hanya valuetetapi juga indexdiciptakan kembali untuk setiap iterasi loop, artinya penutupan yang dibuat dalam tubuh loop tetap mengacu pada index(dan value) yang dibuat untuk iterasi spesifik:
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
Jika Anda memiliki lima div, Anda akan mendapatkan "Indeks adalah: 0" jika Anda mengklik yang pertama dan "Indeks adalah: 4" jika Anda mengklik yang terakhir. Ini tidak berfungsi jika Anda menggunakannya varsebagai gantinya let.
3. Gunakan for-indengan benar
Anda akan mendapatkan orang memberitahu Anda untuk menggunakan for-in, tapi bukan itu yang for-inbagi . for-inloop melalui properti enumerable suatu objek , bukan indeks array. Pesanan tidak dijamin , bahkan dalam ES2015 (ES6). ES2015 + tidak menentukan untuk properti obyek (melalui [[OwnPropertyKeys]], [[Enumerate]]dan hal-hal yang menggunakannya seperti Object.getOwnPropertyKeys), tapi itu tidak menentukan bahwa for-inakan mengikuti perintah itu; ES2020 melakukannya. (Detail dalam jawaban lain ini .)
Satu-satunya kasus penggunaan nyata untuk for-inpada array adalah:
Ini array jarang dengan celah besar di dalamnya, atau
Anda menggunakan properti non-elemen dan Anda ingin memasukkannya dalam loop
Melihat hanya pada contoh pertama itu: Anda dapat menggunakan for-inuntuk mengunjungi elemen array yang jarang itu jika Anda menggunakan pengamanan yang sesuai:
// `a` is a sparse arrayvar key;var a =[];
a[0]="a";
a[10]="b";
a[10000]="c";for(key in a){if(a.hasOwnProperty(key)&&// These checks are/^0$|^[1-9]\d*$/.test(key)&&// explained
key <=4294967294// below){
console.log(a[key]);}}
Bahwa objek memiliki properti sendiri dengan nama itu (bukan yang diwarisi dari prototipe), dan
Bahwa kuncinya adalah semua digit desimal (misalnya, bentuk string normal, bukan notasi ilmiah), dan
Bahwa nilai kunci ketika dipaksa ke suatu angka adalah <= 2 ^ 32 - 2 (yaitu 4.294.967.294). Dari mana angka itu berasal? Itu bagian dari definisi indeks array dalam spesifikasi . Angka lain (bukan bilangan bulat, angka negatif, angka lebih besar dari 2 ^ 32 - 2) bukan indeks array. Alasannya adalah 2 ^ 32 - 2 adalah yang membuat nilai indeks terbesar lebih rendah dari 2 ^ 32 - 1 , yang merupakan nilai maksimum yang dimiliki sebuah array length. (Misalnya, panjang array cocok dengan bilangan bulat 32-bit unsigned.) (Props untuk RobG untuk menunjukkan dalam komentar di posting blog saya bahwa tes saya sebelumnya tidak benar.)
Anda tidak akan melakukannya dalam kode inline, tentu saja. Anda akan menulis fungsi utilitas. Mungkin:
// Utility function for antiquated environments without `forEach`var hasOwn =Object.prototype.hasOwnProperty;var rexNum =/^0$|^[1-9]\d*$/;function sparseEach(array, callback, thisArg){var index;for(var key in array){
index =+key;if(hasOwn.call(a, key)&&
rexNum.test(key)&&
index <=4294967294){
callback.call(thisArg, array[key], index, array);}}}var a =[];
a[5]="five";
a[10]="ten";
a[100000]="one hundred thousand";
a.b ="bee";
sparseEach(a,function(value, index){
console.log("Value at "+ index +" is "+ value);});
Di bawah selimut, yang mendapatkan iterator dari array dan loop melalui itu, mendapatkan nilai dari itu. Ini tidak memiliki masalah yang menggunakan for-intelah, karena menggunakan iterator yang ditentukan oleh objek (array), dan array menentukan bahwa iterator mereka mengulangi melalui entri mereka (bukan properti mereka). Tidak seperti for-inES5, urutan entri yang dikunjungi adalah urutan numerik indeks mereka.
5. Gunakan iterator secara eksplisit (ES2015 +)
Terkadang, Anda mungkin ingin menggunakan iterator secara eksplisit . Anda dapat melakukannya juga, meskipun jauh lebih clunkier daripada for-of. Ini terlihat seperti ini:
const a =["a","b","c"];const it = a.values();let entry;while(!(entry = it.next()).done){
console.log(entry.value);}
Iterator adalah objek yang cocok dengan definisi Iterator dalam spesifikasi. Its nextmetode mengembalikan baru hasil objek setiap kali Anda menyebutnya. Objek hasil memiliki properti, donememberi tahu kami apakah itu dilakukan, dan properti valuedengan nilai untuk iterasi itu. ( doneadalah opsional jika itu akan false, valueadalah opsional jika itu akan terjadi undefined.)
Arti valuebervariasi tergantung pada iterator; dukungan array (setidaknya) tiga fungsi yang mengembalikan iterator:
values(): Ini yang saya gunakan di atas. Ini mengembalikan sebuah iterator di mana setiap valueadalah entri array untuk iterasi yang ( "a", "b", dan "c"dalam contoh sebelumnya).
keys(): Mengembalikan iterator di mana masing value- masing adalah kunci untuk iterasi itu (jadi untuk di aatas kita , itu akan menjadi "0", lalu "1", lalu "2").
entries(): Mengembalikan iterator di mana masing value- masing adalah array dalam bentuk [key, value]untuk iterasi itu.
Untuk Objek Seperti Array
Selain dari array yang benar, ada juga objek seperti array yang memiliki lengthproperti dan properti dengan nama numerik: NodeListinstance, argumentsobjek, dll. Bagaimana cara kita menelusuri isinya?
Gunakan salah satu opsi di atas untuk array
Setidaknya beberapa, dan mungkin sebagian besar atau bahkan semua, pendekatan array di atas sering berlaku sama baiknya untuk objek seperti array:
Gunakan forEachdan terkait (ES5 +)
Berbagai fungsi pada Array.prototype"sengaja generik" dan biasanya dapat digunakan pada objek mirip array melalui Function#callatau Function#apply. (Lihat Peringatan untuk objek yang disediakan oleh tuan rumah di akhir jawaban ini, tetapi ini adalah masalah yang jarang terjadi.)
Misalkan Anda ingin menggunakan forEachpada Node's childNodesproperti. Anda akan melakukan ini:
Array.prototype.forEach.call(node.childNodes,function(child){// Do something with `child`});
Jika Anda akan sering melakukannya, Anda mungkin ingin mengambil salinan referensi fungsi ke dalam 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`});
Gunakan forloop sederhana
Jelas, forloop sederhana berlaku untuk objek mirip array.
Gunakan for-indengan benar
for-indengan perlindungan yang sama dengan array harus bekerja dengan objek seperti array juga; peringatan untuk objek yang disediakan oleh host pada # 1 di atas mungkin berlaku.
Gunakan for-of(gunakan iterator secara implisit) (ES2015 +)
for-ofmenggunakan iterator yang disediakan oleh objek (jika ada). Itu termasuk objek yang disediakan host. Misalnya, spesifikasi untuk NodeListdari querySelectorAlltelah diperbarui untuk mendukung iterasi. Spesifikasi untuk HTMLCollectiondari getElementsByTagNametidak.
Gunakan iterator secara eksplisit (ES2015 +)
Lihat # 4.
Buat array yang benar
Di lain waktu, Anda mungkin ingin mengubah objek mirip array menjadi array yang benar. Melakukan hal itu sangat mudah:
Gunakan slicemetode array
Kita dapat menggunakan slicemetode array, yang seperti metode lain yang disebutkan di atas adalah "sengaja generik" dan dapat digunakan dengan objek seperti array, seperti ini:
var trueArray =Array.prototype.slice.call(arrayLikeObject);
Jadi misalnya, jika kita ingin mengkonversi NodeListmenjadi array yang benar, kita bisa melakukan ini:
var divs =Array.prototype.slice.call(document.querySelectorAll("div"));
Lihat Peringatan untuk objek yang disediakan oleh host di bawah ini. Secara khusus, perhatikan bahwa ini akan gagal di IE8 dan sebelumnya, yang tidak memungkinkan Anda menggunakan objek yang disediakan host thisseperti itu.
Gunakan sintaksis sebar ( ...)
Dimungkinkan juga untuk menggunakan sintaksis penyebaran ES2015 dengan mesin JavaScript yang mendukung fitur ini. Seperti for-of, ini menggunakan iterator yang disediakan oleh objek (lihat # 4 di bagian sebelumnya):
var trueArray =[...iterableObject];
Jadi misalnya, jika kita ingin mengkonversi NodeListmenjadi array yang benar, dengan menyebar sintaks ini menjadi sangat ringkas:
var divs =[...document.querySelectorAll("div")];
Menggunakan Array.from
Array.from(spec) | (MDN) (ES2015 +, tetapi mudah di-polyfilled) membuat array dari objek mirip array, secara opsional meneruskan entri melalui fungsi pemetaan terlebih dahulu. Begitu:
var divs =Array.from(document.querySelectorAll("div"));
Atau jika Anda ingin mendapatkan array nama tag elemen dengan kelas yang diberikan, 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 oleh host
Jika Anda menggunakan Array.prototypefungsi dengan objek mirip array yang disediakan host (daftar DOM dan hal-hal lain yang disediakan oleh browser daripada mesin JavaScript), Anda perlu memastikan untuk menguji di lingkungan target Anda untuk memastikan objek yang disediakan host bertindak dengan benar . Sebagian besar berperilaku baik (sekarang), tetapi penting untuk menguji. Alasannya adalah bahwa sebagian besar Array.prototypemetode yang Anda ingin gunakan bergantung pada objek yang disediakan host memberikan jawaban jujur untuk [[HasProperty]]operasi abstrak . 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. Ada dalam §8.6.2 , beberapa paragraf di bawah tabel besar di 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 bahwa [[Get]]dan [[Put]]untuk objek host tertentu memang mengambil dan menyimpan nilai properti tetapi [[HasProperty]]selalu menghasilkan false .
(Saya tidak bisa menemukan setara verbiage di ES2015 spec, tapi itu pasti masih menjadi kasus.) Sekali lagi, seperti tulisan ini umum host-disediakan array seperti objek dalam browser modern [ NodeListcontoh, misalnya] lakukan pegangan [[HasProperty]]dengan benar, tetapi penting untuk menguji.)
Saya juga ingin menambahkan bahwa .forEachtidak dapat rusak secara efisien. Anda harus melempar pengecualian untuk melakukan break.
Pijusn
82
@Pius: Jika Anda ingin memutus perulangan, Anda dapat menggunakan some. (Saya lebih suka membiarkan istirahat forEachjuga, tetapi mereka, um, tidak bertanya kepada saya. ;-))
TJ Crowder
6
@TJCrowder Benar, meskipun itu lebih seperti solusi karena ini bukan tujuan utamanya.
Pijusn
8
@ user889030: Anda perlu ,after k=0, bukan a ;. Ingat, pemrograman adalah banyak hal, salah satunya adalah perhatian terhadap detail ... :-)
TJ Crowder
5
@ JimB: Itu dibahas di atas (dan lengthbukan metode). :-)
TJ Crowder
513
Catatan : Jawaban ini sudah ketinggalan zaman. Untuk pendekatan yang lebih modern, lihat metode yang tersedia di array . Metode yang menarik mungkin:
untuk setiap
peta
Saring
zip
mengurangi
setiap
beberapa
Cara standar untuk mengulangi array dalam JavaScript adalah vanilla for-loop:
var length = arr.length,
element =null;for(var i =0; i < length; i++){
element = arr[i];// Do something with element}
Perhatikan, bagaimanapun, bahwa pendekatan ini hanya baik jika Anda memiliki array yang padat, dan setiap indeks ditempati oleh suatu elemen. Jika array jarang, maka Anda dapat mengalami masalah kinerja dengan pendekatan ini, karena Anda akan mengulangi banyak indeks yang tidak benar - benar ada dalam array. Dalam hal ini, for .. in-loop mungkin ide yang lebih baik. Namun , Anda harus menggunakan perlindungan yang sesuai untuk memastikan bahwa hanya properti array yang diinginkan (yaitu, elemen array) yang ditindaklanjuti, karena for..in-loop juga akan disebutkan dalam browser lama, atau jika properti tambahan didefinisikan sebagai enumerable.
Dalam ECMAScript 5 akan ada metode forEach pada prototipe array, tetapi tidak didukung di browser lawas. Jadi untuk dapat menggunakannya secara konsisten, Anda harus memiliki lingkungan yang mendukungnya (misalnya, Node.js untuk JavaScript sisi server), atau menggunakan "Polyfill". Namun, Polyfill untuk fungsi ini sepele dan karena membuat kode lebih mudah dibaca, itu adalah polyfill yang baik untuk dimasukkan.
mengapa for(instance in objArray) penggunaannya tidak benar? itu terlihat lebih sederhana bagi saya, tetapi saya mendengar Anda berbicara tentang itu bukan cara yang benar untuk digunakan?
Dante1986
21
Anda dapat menggunakan caching panjang sebaris: untuk (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann
3
Apakah koma pada akhir baris pertama disengaja, atau apakah itu salah ketik (bisa titik koma)?
Mohd Abdul Mujib
6
@ wardha-Web Ini disengaja. Ini memungkinkan kita untuk mendeklarasikan banyak variabel dengan satu kata kunci var. Jika kita menggunakan titik koma, maka elementakan dinyatakan dalam lingkup global (atau, lebih tepatnya, JSHint akan meneriaki kita sebelum mencapai produksi).
PatrikAkerstrand
239
Jika Anda menggunakan perpustakaan jQuery , Anda dapat menggunakan jQuery.each :
$.each(yourArray,function(index, value){// do your stuff here});
EDIT:
Sesuai pertanyaan, pengguna menginginkan kode dalam javascript alih-alih jquery sehingga hasil editnya
var length = yourArray.length;for(var i =0; i < length; i++){// Do something with yourArray[i].}
Saya mungkin akan menggunakan jawaban ini paling sering. Ini bukan jawaban terbaik untuk pertanyaan, tetapi dalam praktiknya akan menjadi yang paling sederhana dan paling berlaku bagi kita yang menggunakan jQuery. Saya pikir kita semua harus belajar cara vanila juga. Tidak ada salahnya untuk memperluas pemahaman Anda.
mopsyd
47
Hanya demi itu: masing-masing jQuery jauh lebih lambat daripada solusi asli. Disarankan oleh jQuery untuk menggunakan JavaScript asli alih-alih jQuery jika memungkinkan. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss
8
Jangan menggunakan jQuery saat Anda dapat menggunakan vanilla js
Noe
2
Tetap berpegang pada JS standar, jauhkan perpustakaan pihak ke-3 dari jawabannya kecuali jika tidak ada solusi bahasa asli
scubasteve
116
Loop ke belakang
Saya pikir sebaliknya untuk loop layak disebutkan di sini:
for(var i = array.length; i--;){// process array[i]}
Keuntungan:
Anda tidak perlu mendeklarasikan lenvariabel sementara , atau membandingkannya array.lengthpada setiap iterasi, yang keduanya mungkin merupakan pengoptimalan menit.
Menghapus saudara kandung dari DOM dalam urutan terbalik biasanya lebih efisien . (Peramban perlu mengurangi pergeseran elemen dalam susunan internalnya.)
Jika Anda memodifikasi array saat pengulangan, pada atau setelah indeks i (misalnya Anda menghapus atau menyisipkan item di array[i]), maka pengulangan akan melewatkan item yang bergeser ke kiri ke posisi i , atau memproses ulang item ke- i yang sebelumnya bergeser ke kanan. Dalam perulangan tradisional, Anda dapat memperbarui saya untuk menunjuk ke item berikutnya yang perlu diproses - 1, tetapi hanya membalikkan arah iterasi seringkali merupakan solusi yang lebih sederhana dan lebih elegan .
Demikian pula, ketika memodifikasi atau menghapus elemen DOM bersarang , pemrosesan secara terbalik dapat menghindari kesalahan . Misalnya, pertimbangkan untuk memodifikasi innerHTML dari simpul induk sebelum menangani anak-anaknya. Pada saat simpul anak tercapai, simpul itu akan terlepas dari DOM, yang telah digantikan oleh anak yang baru dibuat ketika innerHTML induknya ditulis.
Ini lebih pendek untuk mengetik, dan membaca , daripada beberapa opsi lain yang tersedia. Meskipun kalah dari forEach()dan ke ES6 for ... of.
Kekurangan:
Ini memproses item dalam urutan terbalik. Jika Anda sedang membangun array baru dari hasil, atau mencetak hal-hal di layar, tentu saja hasilnya akan terbalik sehubungan dengan pesanan asli.
Berulang kali memasukkan saudara kandung ke dalam DOM sebagai anak pertama untuk mempertahankan pesanan mereka kurang efisien . (Peramban akan tetap harus mengubah hal-hal dengan benar.) Untuk membuat simpul DOM secara efisien dan berurutan, hanya loop ke depan dan tambahkan seperti biasa (dan juga menggunakan "fragmen dokumen").
Loop terbalik membingungkan bagi pengembang junior. (Anda dapat menganggap itu suatu keuntungan, tergantung pada pandangan Anda.)
Haruskah saya selalu menggunakannya?
Beberapa pengembang menggunakan reverse for loop secara default , kecuali ada alasan bagus untuk loop ke depan.
Meskipun keuntungan kinerja biasanya tidak signifikan, itu semacam jeritan:
"Lakukan saja ini untuk setiap item dalam daftar, aku tidak peduli dengan pesanannya!"
Namun dalam praktiknya itu sebenarnya bukan indikasi niat yang dapat diandalkan, karena itu tidak dapat dibedakan dari saat-saat ketika Anda benar-benar peduli dengan pesanan, dan benar-benar perlu mengulang secara terbalik. Jadi sebenarnya diperlukan konstruksi lain untuk secara akurat mengekspresikan maksud "tidak peduli", sesuatu yang saat ini tidak tersedia di sebagian besar bahasa, termasuk ECMAScript, tetapi yang dapat disebut, misalnya forEachUnordered(),.
Jika pesanan tidak masalah, dan efisiensi adalah masalah (di loop paling dalam dari game atau mesin animasi), maka mungkin dapat diterima untuk menggunakan reverse untuk loop sebagai pola masuk Anda. Ingatlah bahwa melihat pembalikan untuk loop dalam kode yang ada tidak selalu berarti bahwa urutannya tidak relevan!
Lebih baik menggunakan forEach ()
Secara umum untuk kode level yang lebih tinggi di mana kejelasan dan keamanan merupakan masalah yang lebih besar, saya sebelumnya merekomendasikan penggunaan Array::forEachsebagai pola default Anda untuk perulangan (meskipun hari ini saya lebih suka menggunakan for..of). Alasan untuk memilih forEachlebih dari loop terbalik adalah:
Lebih jelas untuk membaca.
Ini menunjukkan bahwa saya tidak akan bergeser di dalam blok (yang selalu merupakan kejutan yang mungkin bersembunyi lama fordan whileloop).
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 pembalikan untuk loop dalam kode Anda, itu adalah petunjuk bahwa itu terbalik karena alasan yang baik (mungkin salah satu alasan yang dijelaskan di atas). Dan melihat ke depan tradisional untuk loop dapat menunjukkan bahwa pergeseran dapat terjadi.
(Jika pembahasan niat tidak masuk akal bagi Anda, maka Anda dan kode Anda mungkin mendapat manfaat dari menonton ceramah Crockford tentang Gaya Pemrograman & Otak Anda .)
Sekarang bahkan lebih baik untuk digunakan untuk ... dari!
Ada perdebatan tentang apakah for..ofatau forEach()lebih disukai:
Untuk dukungan peramban yang maksimal, for..ofdiperlukan polyfill untuk iterator, membuat aplikasi Anda sedikit lebih lambat untuk dieksekusi dan sedikit lebih besar untuk diunduh.
Karena alasan itu (dan untuk mendorong penggunaan mapdan filter), beberapa panduan gaya front-end dilarang for..ofsepenuhnya!
Tetapi masalah di atas tidak berlaku untuk aplikasi Node.js, di mana for..ofsekarang didukung dengan baik.
Secara pribadi, saya cenderung menggunakan apa pun yang terlihat paling mudah dibaca, kecuali kinerja atau minifikasi telah menjadi perhatian utama. Jadi hari ini saya lebih memilih untuk menggunakan for..ofbukan forEach(), tapi saya akan selalu menggunakan mapatau filteratau findatau someketika berlaku. (Demi kolega saya, saya jarang menggunakan reduce.)
Bagaimana cara kerjanya?
for(var i =0; i < array.length; i++){...}// Forwardsfor(var i = array.length; i--;){...}// Reverse
Anda akan melihat bahwa itu i--adalah klausa tengah (di mana kita biasanya melihat perbandingan) dan klausa terakhir kosong (di mana kita biasanya melihat i++). Itu berarti yang i--juga digunakan sebagai syarat untuk kelanjutan. Yang terpenting, ini dieksekusi dan diperiksa sebelum setiap iterasi.
Bagaimana ini bisa dimulai array.lengthtanpa meledak?
Karena i--berjalan sebelum setiap iterasi, pada iterasi pertama kita akan benar-benar mengakses item array.length - 1yang menghindari masalah dengan item Array-out-of-boundsundefined .
Mengapa tidak berhenti iterasi sebelum indeks 0?
Loop akan berhenti iterasi ketika kondisi i--mengevaluasi ke nilai falsey (ketika menghasilkan 0).
Kuncinya adalah bahwa tidak seperti --i, i--operator tambahan menurun itetapi menghasilkan nilai sebelum pengurangan. 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 dengan demikian kondisinya lewat. Pada iterasi berikutnya i--perubahan i menjadi -1 tetapi menghasilkan 0 (falsey), menyebabkan eksekusi segera keluar dari bagian bawah loop.
Dalam ke depan tradisional untuk loop, i++dan ++idapat dipertukarkan (seperti yang ditunjukkan Douglas Crockford). Namun dalam reverse for loop, karena penurunan kami juga merupakan ekspresi kondisi kami, kami harus tetap dengan i--jika kami ingin memproses item di indeks 0.
Hal sepele
Beberapa orang suka menggambar panah kecil di forloop terbalik , dan diakhiri dengan mengedipkan mata:
for(var i = array.length; i -->0;){
Kredit pergi ke WYL untuk menunjukkan kepada saya manfaat dan kengerian dari pembalikan untuk loop.
Saya lupa menambahkan tolok ukur . Saya juga lupa menyebutkan bagaimana reverse looping adalah optimasi yang signifikan pada prosesor 8-bit seperti 6502, di mana Anda benar-benar mendapatkan perbandingan secara gratis!
joeytwiddle
Jawaban yang sama diberikan jauh lebih ringkas di sini (pada pertanyaan yang berbeda).
joeytwiddle
84
Beberapa bahasa gaya- C digunakan foreachuntuk mengulang enumerasi. Dalam JavaScript ini dilakukan dengan for..instruktur loop :
var index,
value;for(index in obj){
value = obj[index];}
Ada tangkapan. for..inakan loop melalui masing-masing anggota objek enumerable, dan anggota pada prototipe-nya. Untuk menghindari membaca nilai yang diwariskan melalui prototipe objek, cukup periksa apakah properti itu milik objek:
for(i in obj){if(obj.hasOwnProperty(i)){//do stuff}}
Selain itu, ECMAScript 5 telah menambahkan forEachmetode 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 lama):
Penting untuk dicatat bahwa Array.prototype.forEachtidak terputus ketika callback kembali false. jQuery dan Underscore.js menyediakan variasi sendiri eachuntuk menyediakan loop yang dapat dihubung pendek.
Jadi bagaimana seseorang keluar dari loop foreach ECMAScript5 seperti yang kita lakukan untuk loop normal atau loop foreach seperti yang ditemukan dalam bahasa C-style?
Ciaran Gallagher
5
@CiaranG, dalam JavaScript adalah hal biasa untuk melihat eachmetode yang memungkinkan return falsedigunakan untuk keluar dari loop, tetapi dengan forEachini bukanlah suatu pilihan. Bendera eksternal dapat digunakan (yaitu if (flag) return;, tetapi itu hanya akan mencegah sisa dari fungsi tubuh dari mengeksekusi, forEachmasih akan melanjutkan iterasi di seluruh koleksi.
zzzzBov
43
Jika Anda ingin mengulang array, gunakan forloop tiga bagian standar .
for(var i =0; i < myArray.length; i++){var arrayItem = myArray[i];}
Anda bisa mendapatkan beberapa optimasi kinerja dengan melakukan caching myArray.lengthatau mengulanginya.
untuk (var i = 0, length = myArray.length; i <length; i ++) harus melakukannya
Edson Medina
5
@ EdsonMedina Itu juga akan membuat variabel global baru yang disebut length. ;)
joeytwiddle
4
@ joeytwiddle Ya, tapi itu di luar cakupan posting ini. Anda tetap akan membuat variabel global.
Edson Medina
6
@ EdsonMedina Permintaan maaf saya, saya salah besar. Menggunakan ,setelah penugasan tidak memperkenalkan global baru, jadi saran Anda baik - baik saja ! Saya membingungkan ini untuk masalah yang berbeda: Menggunakan =setelah tugas tidak membuat global baru.
joeytwiddle
Waspadai variabel saya bukan lokal untuk loop. JavaScript tidak memiliki ruang lingkup blokir. Mungkin lebih baik untuk mendeklarasikan var i, length, arrayItem;sebelum loop untuk menghindari kesalahpahaman ini.
James
35
Saya tahu ini adalah pos lama, dan sudah ada begitu banyak jawaban. Untuk sedikit lebih lengkap saya pikir saya akan melempar yang lain menggunakan AngularJS . Tentu saja, ini hanya berlaku jika Anda menggunakan Angular, jelas, toh saya tetap ingin mengatakannya.
angular.forEachmengambil 2 argumen dan argumen ketiga opsional. Argumen pertama adalah objek (array) untuk beralih, 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 forEach loop of angular. 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 array lainnya 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 harus melakukan itu, Anda cukup melakukan hal berikut dan itu setara dengan contoh sebelumnya:
Sekarang ada pro dan kontra dari menggunakan angular.forEachfungsi yang bertentangan dengan forloop bawaan rasa vanilla .
Pro
Mudah dibaca
Mudah ditulisi
Jika tersedia, angular.forEachakan menggunakan loop ES5 forEach. Sekarang, saya akan sampai pada efisiensi di bagian kontra, karena forEach loop jauh lebih lambat daripada for loop. Saya menyebut ini sebagai pro karena senang konsisten dan standar.
Pertimbangkan 2 loop bersarang berikut, yang melakukan hal yang persis sama. Katakanlah kita memiliki 2 array objek dan setiap objek berisi array hasil, yang masing-masing memiliki properti Nilai yang berupa string (atau apa pun). Dan katakanlah kita perlu mengulangi setiap hasil dan jika hasilnya sama maka lakukan 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 loopfor(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}}}
Memang ini adalah contoh hipotetis yang sangat sederhana, tetapi saya telah menulis triple tertanam untuk loop menggunakan pendekatan kedua dan itu sangat sulit dibaca, dan menulis dalam hal ini.
Cons
Efisiensi. angular.forEach, dan asli forEach, dalam hal ini, keduanya jauh lebih lambat daripada forloop normal .... sekitar 90% lebih lambat . Jadi untuk set data besar, lebih baik tetap pada forloop asli .
Tanpa istirahat, melanjutkan, atau mengembalikan dukungan. continuesebenarnya didukung oleh " kecelakaan ", untuk melanjutkan angular.forEachAnda meletakkan 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 disebabkan oleh fakta bahwa penduduk asli forEachtidak mendukung istirahat atau melanjutkan.
Saya yakin ada berbagai pro dan kontra lainnya, dan jangan ragu untuk menambahkan yang Anda inginkan. Saya rasa, intinya, jika Anda membutuhkan efisiensi, tetaplah dengan hanya forloop asli untuk kebutuhan looping Anda. Tetapi, jika set data Anda lebih kecil dan sedikit efisiensi tidak apa-apa untuk menyerah dalam pertukaran untuk keterbacaan dan kemampuan menulis, maka dengan cara apa pun melemparkan angular.forEachanak nakal itu.
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});
Mungkin for(i = 0; i < array.length; i++)loop bukan pilihan terbaik. Mengapa? Jika Anda memiliki ini:
var array =newArray();
array[1]="Hello";
array[7]="World";
array[11]="!";
Metode akan memanggil dari array[0]ke array[2]. Pertama, ini pertama akan variabel referensi Anda bahkan tidak memiliki, kedua Anda tidak akan memiliki variabel dalam array, dan ketiga ini akan membuat kode lebih tebal. Lihat di sini, itulah yang saya gunakan:
for(var i in array){var el = array[i];//If you want 'i' to be INT just put parseInt(i)//Do something with el}
Dan jika Anda ingin itu berfungsi, Anda bisa melakukan ini:
function foreach(array, call){for(var i in array){
call(array[i]);}}
Jika Anda ingin istirahat, sedikit lebih banyak logika:
function foreach(array, call){for(var i in array){if(call(array[i])==false){break;}}}
Ada tiga implementasi foreachdi jQuery sebagai berikut.
var a =[3,2];
$(a).each(function(){console.log(this.valueOf())});//Method 1
$.each(a,function(){console.log(this.valueOf())});//Method 2
$.each($(a),function(){console.log(this.valueOf())});//Method 3
Di mana ofmenghindari keanehan yang terkait dengan indan membuatnya bekerja seperti forloop dari bahasa lain, dan letmengikat idalam loop sebagai lawan dalam fungsi.
Kawat gigi ( {}) dapat dihilangkan ketika hanya ada satu perintah (misalnya dalam contoh di atas).
Solusi mudah sekarang adalah dengan menggunakan perpustakaan underscore.js . Ini menyediakan banyak alat yang bermanfaat, seperti eachdan akan secara otomatis mendelegasikan pekerjaan kepada penduduk asli forEachjika tersedia.
Tidak ada for eachloop dalam JavaScript asli . Anda dapat menggunakan pustaka untuk mendapatkan fungsi ini (saya sarankan Underscore.js ), gunakan forloop sederhana .
Ini adalah iterator untuk daftar NON-jarang di mana indeks dimulai pada 0, yang merupakan skenario khas ketika berhadapan dengan document.getElementsByTagName atau document.querySelectorAll)
function each( fn, data ){if(typeof fn =='string')eval('fn = function(data, i){'+ fn +'}');for(var i=0, L=this.length; i < L; i++)
fn.call(this[i], data, i );returnthis;}Array.prototype.each = each;
Contoh penggunaan:
Contoh 1
var arr =[];[1,2,3].each(function(a){ a.push(this*this}, arr);
arr =[1,4,9]
each.call(document.getElementsByTagName('p'),"if( i % 2 == 0) this.className = data;",'red');
Setiap tag p lainnya mendapat class="red">
Contoh # 4
each.call(document.querySelectorAll('p.blue'),function(newClass, i){if( i <20)this.className = newClass;},'green');
Dan akhirnya 20 tag p biru pertama diubah menjadi hijau
Perhatian saat menggunakan string sebagai fungsi: fungsi ini dibuat di luar konteks dan harus digunakan hanya jika Anda yakin akan pelingkupan variabel. Jika tidak, lebih baik melewati fungsi di mana pelingkupan lebih intuitif.
Ada beberapa cara untuk mengulang-ulang array dalam JavaScript, seperti di bawah ini:
untuk - itu yang paling umum . Blok penuh kode untuk perulangan
var languages =["Java","JavaScript","C#","Python"];var i, len, text;for(i =0, len = languages.length, text =""; i < len; i++){
text += languages[i]+"<br>";}
document.getElementById("example").innerHTML = text;
Loop fungsional - forEach, map, filter, juga reduce(lingkaran mereka melalui fungsi, tetapi mereka digunakan jika Anda perlu untuk melakukan sesuatu dengan array, dll
// For example, in this case we loop through the number and double them up using the map functionvar numbers =[65,44,12,4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num *2});
Koreksi kecil: forEachbukan loop "fungsional" karena tidak mengembalikan yang baru Array(sebenarnya itu tidak mengembalikan apa pun), itu hanya berulang.
nicholaswmin
19
ECMAScript 5 (versi JavaScript) untuk bekerja dengan Array:
forEach - Memisahkan setiap item dalam array dan melakukan apa pun yang Anda butuhkan dengan setiap item.
['C','D','E'].forEach(function(element, index){
console.log(element +" is #"+(index+1)+" in the musical scale");});// Output// C is the #1 in musical scale// D is the #2 in musical scale// E is the #3 in musical scale
Dalam hal ini, lebih tertarik pada operasi pada array menggunakan beberapa fitur bawaan.
map - Ini menciptakan array baru dengan hasil dari fungsi callback. Metode ini baik untuk digunakan ketika Anda perlu memformat elemen array Anda.
// Let's upper case the items in the array['bob','joe','jen'].map(function(elem){return elem.toUpperCase();});// Output: ['BOB', 'JOE', 'JEN']
mengurangi - Seperti namanya, itu mengurangi array ke nilai tunggal dengan memanggil fungsi yang diberikan lewat elemen saat ini dan hasil dari eksekusi sebelumnya.
Tidak ada kemampuan bawaan untuk masuk forEach. Untuk menghentikan eksekusi, gunakan Array#someseperti di bawah ini:
[1,2,3].some(function(number){return number ===1;});
Ini berfungsi karena somemengembalikan true segera setelah salah satu dari callback, dieksekusi dalam urutan array, mengembalikan true, hubungan pendek eksekusi sisanya.
Jawaban Asli,
lihat prototipe array untuk beberapa
Saya juga ingin menambahkan ini sebagai komposisi loop terbalik dan jawaban di atas untuk seseorang yang ingin sintaks ini juga.
var foo =[object,object,object];for(var i = foo.length, item; item = foo[--i];){
console.log(item);}
Pro:
Manfaat untuk ini: Anda sudah memiliki referensi di pertama seperti itu tidak perlu dinyatakan kemudian dengan baris lain. Ini berguna saat perulangan melalui array objek.
Cons:
Ini akan rusak setiap kali referensi salah - falsey (tidak ditentukan, dll.). Ini bisa digunakan sebagai keuntungan. Namun, itu akan membuatnya sedikit lebih sulit untuk dibaca. Dan juga tergantung pada browser itu bisa "tidak" dioptimalkan untuk bekerja lebih cepat daripada yang asli.
Destrukturisasi dan penggunaan operator penyebaran telah terbukti cukup berguna bagi pendatang baru ke ECMAScript 6 sebagai lebih dapat dibaca / estetika manusia, meskipun beberapa veteran JavaScript mungkin menganggapnya berantakan. Junior atau orang lain mungkin merasa berguna.
Contoh-contoh berikut akan menggunakan for...ofpernyataan dan .forEachmetode.
Contoh 6, 7, dan 8 dapat digunakan dengan loop fungsional seperti .map, .filter, .reduce, .sort, .every, .some. Untuk informasi lebih lanjut tentang metode ini, periksa Array Object .
Contoh 1: Normal for...ofloop - tidak ada trik di sini.
let arrSimple =['a','b','c'];for(let letter of arrSimple){
console.log(letter);}
let arrFruits =['apple','orange','banana'];for(let[firstLetter,...restOfTheWord]of arrFruits){// Create a shallow copy using the spread operatorlet[lastLetter]=[...restOfTheWord].reverse();
console.log(firstLetter, lastLetter, restOfTheWord);}
// let arrSimple = ['a', 'b', 'c'];// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`// this example will use a multi-dimensional array of the following format type:// `arrWithIndex: [number, string][]`let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Same thing can be achieved using `.map` method// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);// Same thing can be achieved using `Object.entries`// NOTE: `Object.entries` method doesn't work on Internet Explorer unless it's polyfilled// let arrWithIndex = Object.entries(arrSimple);for(let[key, value]of arrWithIndex){
console.log(key, value);}
Contoh 6: Apakah Contoh 3 digunakan dengan.forEach
let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Not to be confused here, `forEachIndex` is the real index// `mappedIndex` was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex)=>{
console.log(forEachIndex, mappedIndex, item);});
Contoh 7: Apakah Contoh 4 digunakan dengan.forEach
let arrWithObjects =[{
name:'Jon',
age:32},{
name:'Elise',
age:33}];// NOTE: Destructuring objects while using shorthand functions// are required to be surrounded by parentheses
arrWithObjects.forEach(({ name, age: aliasForAge })=>{
console.log(name, aliasForAge)});
Cara terdekat dengan ide Anda adalah dengan menggunakan Array.forEach()yang menerima fungsi penutupan yang akan dieksekusi untuk setiap elemen array.
myArray.forEach((item)=>{// Do something
console.log(item);});
Cara lain yang layak adalah menggunakan Array.map()yang berfungsi dengan cara yang sama, tetapi juga mengambil semua nilai yang Anda kembalikan dan mengembalikannya dalam array baru (pada dasarnya memetakan setiap elemen ke yang baru), seperti ini:
Ini salah, maptidak mengubah elemen array, karena mengembalikan array baru, dengan item yang baru menjadi hasil penerapan fungsi ke item array lama.
Jesús Franco
Saya tidak pernah mengatakan itu tidak mengembalikan array baru, saya merujuk pada perubahan yang diterapkan oleh fungsi. Tapi di sini saya akan mengubahnya dalam jawabannya.
Ante Jablan Adamović
lagi salah, peta tidak mengubah atau bermutasi di semua item dalam array asli, saya telah mengusulkan dan mengedit jawaban yang menekankan peta bekerja dengan salinan item asli, meninggalkan array asli tidak tersentuh sama sekali
Jesús Franco
7
Anda dapat menghubungi forEach seperti ini:
forEachakan beralih di atas array yang Anda berikan dan untuk setiap iterasi akan memiliki elementyang memegang nilai iterasi itu. Jika Anda membutuhkan indeks, Anda bisa mendapatkan indeks saat ini dengan melewatkan isebagai parameter kedua dalam fungsi panggilan balik untuk forEach.
Foreach pada dasarnya adalah Fungsi Tingkat Tinggi, yang mengambil fungsi lain sebagai parameternya.
let theArray=[1,3,2];
theArray.forEach((element)=>{// Use the element of the array
console.log(element)}
Keluaran:
132
Anda juga dapat beralih ke array seperti ini:
for(let i=0; i<theArray.length; i++){
console.log(i);// i will have the value of each index}
Jika Anda ingin mengulang melalui array objek dengan fungsi panah:
let arr =[{name:'john', age:50},{name:'clark', age:19},{name:'mohan', age:26}];
arr.forEach((person)=>{
console.log('I am '+ person.name +' and I am '+ person.age +' old');})
Sintaks lambda biasanya tidak berfungsi di Internet Explorer 10 atau di bawah.
Saya biasanya menggunakan
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Jika Anda adalah penggemar jQuery dan sudah menjalankan file jQuery, Anda harus membalik posisi indeks dan parameter nilai
$("#ul>li").each(function(**index, value**){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Jika Anda memiliki array besar yang harus Anda gunakan iteratorsuntuk mendapatkan efisiensi. Iterator adalah properti dari koleksi JavaScript tertentu (sepertiMap , Set, String, Array). Bahkan, for..ofmenggunakan iteratorunder-the-hood.
Iterator meningkatkan efisiensi dengan membiarkan Anda mengonsumsi item dalam daftar satu per satu seolah-olah itu adalah stream. Apa yang membuat iterator spesial adalah bagaimana ia melintasi koleksi. Loop lain perlu memuat seluruh koleksi di depan untuk beralih di atasnya, sedangkan iterator hanya perlu mengetahui posisi saat ini dalam koleksi.
Anda mengakses item saat ini dengan memanggil metode iterator next. Metode selanjutnya akan mengembalikan valueitem saat ini dan booleanuntuk menunjukkan kapan Anda telah mencapai akhir koleksi. Berikut ini adalah contoh membuat iterator dari array.
Ubah array reguler Anda menjadi iterator menggunakan values() metode seperti ini:
const myArr =[2,3,4]let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Hari ini (2019-12-18) saya melakukan pengujian pada macOS v10.13.6 (High Sierra), di Chrome v 79.0, Safari v13.0.4 dan Firefox v71.0 (64 bit) - kesimpulan tentang pengoptimalan (dan pengoptimalan mikro yang biasanya tidak layak untuk memperkenalkannya ke kode karena manfaatnya kecil, tetapi kompleksitas kode tumbuh).
Sepertinya tradisional for i( Aa ) adalah pilihan yang baik untuk menulis kode cepat di semua browser.
Solusi lain, seperti for-of( Iklan ), semua dalam grup C. ... biasanya 2 - 10 (dan lebih) kali lebih lambat dari Aa , tetapi untuk array kecil tidak apa-apa untuk menggunakannya - demi meningkatkan kejelasan kode.
Loop dengan panjang array yang di-cache dalam n( Ab, Bb, Be ) terkadang lebih cepat, kadang tidak. Mungkin kompiler secara otomatis mendeteksi situasi ini dan memperkenalkan caching. Perbedaan kecepatan antara versi yang di-cache dan yang tidak di-cache ( Aa, Ba, Bd ) sekitar ~ 1%, jadi sepertinya introduksi nadalah optimasi mikro .
The i--seperti solusi mana loop dimulai dari elemen array terakhir ( Ac, Bc ) biasanya ~ 30% lebih lambat dari solusi ke depan - mungkin alasannya adalah cara memory CPU Cache kerja - maju memori membaca lebih optimal untuk CPU caching). Dianjurkan untuk TIDAK MENGGUNAKAN solusi tersebut.
Detail
Dalam pengujian kami menghitung jumlah elemen array. Saya melakukan tes untuk array kecil (10 elemen) dan array besar (elemen 1M) dan membaginya menjadi tiga kelompok:
Ketika beralih ke array, kita sering ingin mencapai salah satu dari tujuan berikut:
Kami ingin beralih di atas array dan membuat array baru:
Array.prototype.map
Kami ingin mengulangi array dan tidak membuat array baru:
Array.prototype.forEach
for..oflingkaran
Dalam JavaScript, ada banyak cara untuk mencapai kedua tujuan ini. Namun, beberapa lebih nyaman daripada yang lain. Di bawah ini Anda dapat menemukan beberapa metode yang umum digunakan (IMO paling nyaman) untuk menyelesaikan iterasi array dalam JavaScript.
Membuat array baru: Map
map()adalah fungsi yang terletak di Array.prototypemana dapat mengubah setiap elemen array dan kemudian mengembalikan array baru . map()mengambil sebagai argumen fungsi panggilan balik dan bekerja dengan cara berikut:
let arr =[1,2,3,4,5];let newArr = arr.map((element, index, array)=>{return element *2;})
console.log(arr);
console.log(newArr);
Callback yang kami sampaikan map()sebagai argumen dieksekusi untuk setiap elemen. Kemudian sebuah array dikembalikan yang memiliki panjang yang sama dengan array asli. Dalam elemen array baru ini ditransformasikan oleh fungsi callback yang diteruskan sebagai argumen map().
Perbedaan yang berbeda antara mapdan mekanisme loop lain seperti forEachdan for..ofloop adalah yang mapmengembalikan array baru dan membiarkan array lama tetap utuh (kecuali jika Anda secara eksplisit memanipulasi dengan berpikir seperti splice).
Juga, perhatikan bahwa mapfungsi callback memberikan nomor indeks dari iterasi saat ini sebagai argumen kedua. Selanjutnya, apakah argumen ketiga menyediakan array yang mapdipanggil? Terkadang sifat ini bisa sangat berguna.
Loop menggunakan forEach
forEachadalah fungsi yang terletak di Array.prototypemana mengambil fungsi callback sebagai argumen. Itu kemudian mengeksekusi fungsi callback ini untuk setiap elemen dalam array. Berbeda dengan map()fungsi, fungsi forEach mengembalikan apa-apa ( undefined). Sebagai contoh:
let arr =[1,2,3,4,5];
arr.forEach((element, index, array)=>{
console.log(element *2);if(index ===4){
console.log(array)}// index, and oldArray are provided as 2nd and 3th argument by the callback})
console.log(arr);
Sama seperti mapfungsi, forEachpanggilan balik memberikan nomor indeks dari iterasi saat ini sebagai argumen kedua. Juga, apakah argumen ketiga menyediakan array yang forEachdipanggil?
Loop melalui elemen menggunakan for..of
The for..ofLoop loop melalui setiap elemen array (atau benda iterable lainnya). Ini bekerja dengan cara berikut:
let arr =[1,2,3,4,5];for(let element of arr){
console.log(element *2);}
Dalam contoh di atas, elementsingkatan dari elemen array dan arrmerupakan array yang ingin kita loop. Perhatikan bahwa nama elementtersebut arbitrer, dan kami dapat memilih nama lain seperti 'el' atau sesuatu yang lebih deklaratif saat ini berlaku.
Jangan bingung antara for..inloop dengan for..ofloop. for..inakan mengulang semua properti enumerable dari array sedangkan for..ofloop hanya akan mengulang melalui elemen array. Sebagai contoh:
let arr =[1,2,3,4,5];
arr.foo ='foo';for(let element of arr){
console.log(element);}for(let element in arr){
console.log(element);}
forEach
dan bukan hanyafor
. seperti yang dinyatakan, dalam c # itu sedikit berbeda, dan itu membingungkan saya :)i < len
dani++
dapat dilakukan oleh mesin, bukan oleh penerjemah.)Jawaban:
TL; DR
for-in
kecuali Anda menggunakannya dengan perlindungan atau setidaknya menyadari mengapa itu bisa menggigit Anda.Taruhan terbaik Anda biasanya
for-of
loop (ES2015 + saja),Array#forEach
(spec
|MDN
) (atau saudarasome
dan sejenisnya) (hanya ES5 +),for
loop kuno sederhana ,for-in
dengan perlindungan.Tetapi ada banyak lagi untuk dijelajahi, baca terus ...
JavaScript memiliki semantik yang kuat untuk perulangan melalui array dan objek seperti array. Saya telah membagi jawaban menjadi dua bagian: Opsi untuk array asli, dan opsi untuk hal-hal yang hanya seperti array , seperti
arguments
objek, objek iterable lainnya (ES2015 +), koleksi DOM, dan sebagainya.Aku akan segera dicatat bahwa Anda dapat menggunakan ES2015 pilihan sekarang , bahkan pada mesin ES5, oleh transpiling ES2015 untuk ES5. Cari "ES2015 transpiling" / "ES6 transpiling" untuk lebih ...
Oke, mari kita lihat opsi kami:
Untuk Array Aktual
Anda memiliki tiga opsi dalam ECMAScript 5 ("ES5"), versi yang paling banyak didukung saat ini, dan dua lagi ditambahkan dalam ECMAScript 2015 ("ES2015", "ES6"):
forEach
dan terkait (ES5 +)for
loop sederhanafor-in
dengan benarfor-of
(gunakan iterator secara implisit) (ES2015 +)Detail:
1. Gunakan
forEach
dan terkaitDi lingkungan samar-samar modern (jadi, bukan IE8) di mana Anda memiliki akses ke
Array
fitur yang ditambahkan oleh ES5 (langsung atau menggunakan polyfill), Anda dapat menggunakanforEach
(spec
|MDN
):forEach
menerima fungsi panggilan balik dan, secara opsional, nilai yang digunakan sepertithis
saat memanggil panggilan balik itu (tidak digunakan di atas). Callback dipanggil untuk setiap entri dalam array, secara berurutan, melewatkan entri yang tidak ada dalam array 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 (jika fungsi Anda belum membuatnya berguna) ).Kecuali jika Anda mendukung peramban usang seperti IE8 (yang NetApps tunjukkan di lebih dari 4% pangsa pasar pada tulisan ini pada September 2016), Anda dapat dengan senang hati menggunakan
forEach
laman web tujuan umum tanpa shim. Jika Anda perlu mendukung browser yang usang, shimming / polyfillingforEach
mudah dilakukan (cari "es5 shim" untuk beberapa opsi).forEach
memiliki manfaat bahwa Anda tidak harus mendeklarasikan pengindeksan dan nilai variabel dalam lingkup yang berisi, karena mereka disediakan sebagai argumen untuk fungsi iterasi, dan sangat baik hanya untuk iterasi itu.Jika Anda khawatir tentang biaya runtime untuk membuat panggilan fungsi untuk setiap entri array, jangan; detail .
Selain itu,
forEach
adalah fungsi "loop through them all", tetapi ES5 mendefinisikan beberapa fungsi lain yang bermanfaat "bekerja dengan cara Anda melalui array dan melakukan sesuatu" fungsi, termasuk:every
(berhenti mengulang-ulang saat panggilan balik kembalifalse
atau sesuatu yang palsu)some
(berhenti mengulang-ulang saat panggilan balik kembalitrue
atau sesuatu yang benar)filter
(membuat array baru termasuk elemen tempat fungsi filter kembalitrue
dan menghilangkan yang mengembalikannyafalse
)map
(membuat array baru dari nilai yang dikembalikan oleh callback)reduce
(membangun nilai dengan berulang kali memanggil callback, meneruskan nilai sebelumnya; lihat spesifikasi untuk detail; berguna untuk menjumlahkan isi array dan banyak hal lainnya)reduceRight
(sepertireduce
, tetapi bekerja dalam urutan menurun daripada urutan naik)2. Gunakan
for
loop sederhanaTerkadang cara lama adalah yang terbaik:
Jika panjang array tidak akan berubah selama loop, dan itu dalam kode kinerja sensitif (mungkin), versi yang sedikit lebih rumit meraih panjang depan mungkin kecil sedikit lebih cepat:
Dan / atau menghitung mundur:
Tetapi dengan mesin JavaScript modern, jarang Anda perlu menambah sedikit jus terakhir.
Di ES2015 dan lebih tinggi, Anda bisa membuat indeks dan variabel nilai lokal ke
for
loop:Tampilkan cuplikan kode
Dan ketika Anda melakukan itu, bukan hanya
value
tetapi jugaindex
diciptakan kembali untuk setiap iterasi loop, artinya penutupan yang dibuat dalam tubuh loop tetap mengacu padaindex
(danvalue
) yang dibuat untuk iterasi spesifik:Tampilkan cuplikan kode
Jika Anda memiliki lima div, Anda akan mendapatkan "Indeks adalah: 0" jika Anda mengklik yang pertama dan "Indeks adalah: 4" jika Anda mengklik yang terakhir. Ini tidak berfungsi jika Anda menggunakannya
var
sebagai gantinyalet
.3. Gunakan
for-in
dengan benarAnda akan mendapatkan orang memberitahu Anda untuk menggunakan
for-in
, tapi bukan itu yangfor-in
bagi .for-in
loop melalui properti enumerable suatu objek , bukan indeks array. Pesanan tidak dijamin , bahkan dalam ES2015 (ES6). ES2015 + tidak menentukan untuk properti obyek (melalui[[OwnPropertyKeys]]
,[[Enumerate]]
dan hal-hal yang menggunakannya sepertiObject.getOwnPropertyKeys
), tapi itu tidak menentukan bahwafor-in
akan mengikuti perintah itu; ES2020 melakukannya. (Detail dalam jawaban lain ini .)Satu-satunya kasus penggunaan nyata untuk
for-in
pada array adalah:Melihat hanya pada contoh pertama itu: Anda dapat menggunakan
for-in
untuk mengunjungi elemen array yang jarang itu jika Anda menggunakan pengamanan yang sesuai:Perhatikan tiga cek:
Bahwa objek memiliki properti sendiri dengan nama itu (bukan yang diwarisi dari prototipe), dan
Bahwa kuncinya adalah semua digit desimal (misalnya, bentuk string normal, bukan notasi ilmiah), dan
Bahwa nilai kunci ketika dipaksa ke suatu angka adalah <= 2 ^ 32 - 2 (yaitu 4.294.967.294). Dari mana angka itu berasal? Itu bagian dari definisi indeks array dalam spesifikasi . Angka lain (bukan bilangan bulat, angka negatif, angka lebih besar dari 2 ^ 32 - 2) bukan indeks array. Alasannya adalah 2 ^ 32 - 2 adalah yang membuat nilai indeks terbesar lebih rendah dari 2 ^ 32 - 1 , yang merupakan nilai maksimum yang dimiliki sebuah array
length
. (Misalnya, panjang array cocok dengan bilangan bulat 32-bit unsigned.) (Props untuk RobG untuk menunjukkan dalam komentar di posting blog saya bahwa tes saya sebelumnya tidak benar.)Anda tidak akan melakukannya dalam kode inline, tentu saja. Anda akan menulis fungsi utilitas. Mungkin:
Tampilkan cuplikan kode
4. Gunakan
for-of
(gunakan iterator secara implisit) (ES2015 +)ES2015 menambahkan iterators ke JavaScript. Cara termudah untuk menggunakan iterator adalah
for-of
pernyataan baru . Ini terlihat seperti ini:Di bawah selimut, yang mendapatkan iterator dari array dan loop melalui itu, mendapatkan nilai dari itu. Ini tidak memiliki masalah yang menggunakan
for-in
telah, karena menggunakan iterator yang ditentukan oleh objek (array), dan array menentukan bahwa iterator mereka mengulangi melalui entri mereka (bukan properti mereka). Tidak sepertifor-in
ES5, urutan entri yang dikunjungi adalah urutan numerik indeks mereka.5. Gunakan iterator secara eksplisit (ES2015 +)
Terkadang, Anda mungkin ingin menggunakan iterator secara eksplisit . Anda dapat melakukannya juga, meskipun jauh lebih clunkier daripada
for-of
. Ini terlihat seperti ini:Iterator adalah objek yang cocok dengan definisi Iterator dalam spesifikasi. Its
next
metode mengembalikan baru hasil objek setiap kali Anda menyebutnya. Objek hasil memiliki properti,done
memberi tahu kami apakah itu dilakukan, dan propertivalue
dengan nilai untuk iterasi itu. (done
adalah opsional jika itu akanfalse
,value
adalah opsional jika itu akan terjadiundefined
.)Arti
value
bervariasi tergantung pada iterator; dukungan array (setidaknya) tiga fungsi yang mengembalikan iterator:values()
: Ini yang saya gunakan di atas. Ini mengembalikan sebuah iterator di mana setiapvalue
adalah entri array untuk iterasi yang ("a"
,"b"
, dan"c"
dalam contoh sebelumnya).keys()
: Mengembalikan iterator di mana masingvalue
- masing adalah kunci untuk iterasi itu (jadi untuk dia
atas kita , itu akan menjadi"0"
, lalu"1"
, lalu"2"
).entries()
: Mengembalikan iterator di mana masingvalue
- masing adalah array dalam bentuk[key, value]
untuk iterasi itu.Untuk Objek Seperti Array
Selain dari array yang benar, ada juga objek seperti array yang memiliki
length
properti dan properti dengan nama numerik:NodeList
instance,arguments
objek, dll. Bagaimana cara kita menelusuri isinya?Gunakan salah satu opsi di atas untuk array
Setidaknya beberapa, dan mungkin sebagian besar atau bahkan semua, pendekatan array di atas sering berlaku sama baiknya untuk objek seperti array:
Gunakan
forEach
dan terkait (ES5 +)Berbagai fungsi pada
Array.prototype
"sengaja generik" dan biasanya dapat digunakan pada objek mirip array melaluiFunction#call
atauFunction#apply
. (Lihat Peringatan untuk objek yang disediakan oleh tuan rumah di akhir jawaban ini, tetapi ini adalah masalah yang jarang terjadi.)Misalkan Anda ingin menggunakan
forEach
padaNode
'schildNodes
properti. Anda akan melakukan ini:Jika Anda akan sering melakukannya, Anda mungkin ingin mengambil salinan referensi fungsi ke dalam variabel untuk digunakan kembali, misalnya:
Gunakan
for
loop sederhanaJelas,
for
loop sederhana berlaku untuk objek mirip array.Gunakan
for-in
dengan benarfor-in
dengan perlindungan yang sama dengan array harus bekerja dengan objek seperti array juga; peringatan untuk objek yang disediakan oleh host pada # 1 di atas mungkin berlaku.Gunakan
for-of
(gunakan iterator secara implisit) (ES2015 +)for-of
menggunakan iterator yang disediakan oleh objek (jika ada). Itu termasuk objek yang disediakan host. Misalnya, spesifikasi untukNodeList
dariquerySelectorAll
telah diperbarui untuk mendukung iterasi. Spesifikasi untukHTMLCollection
darigetElementsByTagName
tidak.Gunakan iterator secara eksplisit (ES2015 +)
Lihat # 4.
Buat array yang benar
Di lain waktu, Anda mungkin ingin mengubah objek mirip array menjadi array yang benar. Melakukan hal itu sangat mudah:
Gunakan
slice
metode arrayKita dapat menggunakan
slice
metode array, yang seperti metode lain yang disebutkan di atas adalah "sengaja generik" dan dapat digunakan dengan objek seperti array, seperti ini:Jadi misalnya, jika kita ingin mengkonversi
NodeList
menjadi array yang benar, kita bisa melakukan ini:Lihat Peringatan untuk objek yang disediakan oleh host di bawah ini. Secara khusus, perhatikan bahwa ini akan gagal di IE8 dan sebelumnya, yang tidak memungkinkan Anda menggunakan objek yang disediakan host
this
seperti itu.Gunakan sintaksis sebar (
...
)Dimungkinkan juga untuk menggunakan sintaksis penyebaran ES2015 dengan mesin JavaScript yang mendukung fitur ini. Seperti
for-of
, ini menggunakan iterator yang disediakan oleh objek (lihat # 4 di bagian sebelumnya):Jadi misalnya, jika kita ingin mengkonversi
NodeList
menjadi array yang benar, dengan menyebar sintaks ini menjadi sangat ringkas:Menggunakan
Array.from
Array.from
(spec) | (MDN) (ES2015 +, tetapi mudah di-polyfilled) membuat array dari objek mirip array, secara opsional meneruskan entri melalui fungsi pemetaan terlebih dahulu. Begitu:Atau jika Anda ingin mendapatkan array nama tag elemen dengan kelas yang diberikan, Anda akan menggunakan fungsi pemetaan:
Peringatan untuk objek yang disediakan oleh host
Jika Anda menggunakan
Array.prototype
fungsi dengan objek mirip array yang disediakan host (daftar DOM dan hal-hal lain yang disediakan oleh browser daripada mesin JavaScript), Anda perlu memastikan untuk menguji di lingkungan target Anda untuk memastikan objek yang disediakan host bertindak dengan benar . Sebagian besar berperilaku baik (sekarang), tetapi penting untuk menguji. Alasannya adalah bahwa sebagian besarArray.prototype
metode yang Anda ingin gunakan bergantung pada objek yang disediakan host memberikan jawaban jujur untuk[[HasProperty]]
operasi abstrak . 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. Ada dalam §8.6.2 , beberapa paragraf di bawah tabel besar di dekat awal bagian itu), di mana dikatakan:(Saya tidak bisa menemukan setara verbiage di ES2015 spec, tapi itu pasti masih menjadi kasus.) Sekali lagi, seperti tulisan ini umum host-disediakan array seperti objek dalam browser modern [
NodeList
contoh, misalnya] lakukan pegangan[[HasProperty]]
dengan benar, tetapi penting untuk menguji.)sumber
.forEach
tidak dapat rusak secara efisien. Anda harus melempar pengecualian untuk melakukan break.some
. (Saya lebih suka membiarkan istirahatforEach
juga, tetapi mereka, um, tidak bertanya kepada saya. ;-)),
afterk=0
, bukan a;
. Ingat, pemrograman adalah banyak hal, salah satunya adalah perhatian terhadap detail ... :-)length
bukan metode). :-)Catatan : Jawaban ini sudah ketinggalan zaman. Untuk pendekatan yang lebih modern, lihat metode yang tersedia di array . Metode yang menarik mungkin:
Cara standar untuk mengulangi array dalam JavaScript adalah vanilla
for
-loop:Perhatikan, bagaimanapun, bahwa pendekatan ini hanya baik jika Anda memiliki array yang padat, dan setiap indeks ditempati oleh suatu elemen. Jika array jarang, maka Anda dapat mengalami masalah kinerja dengan pendekatan ini, karena Anda akan mengulangi banyak indeks yang tidak benar - benar ada dalam array. Dalam hal ini,
for .. in
-loop mungkin ide yang lebih baik. Namun , Anda harus menggunakan perlindungan yang sesuai untuk memastikan bahwa hanya properti array yang diinginkan (yaitu, elemen array) yang ditindaklanjuti, karenafor..in
-loop juga akan disebutkan dalam browser lama, atau jika properti tambahan didefinisikan sebagaienumerable
.Dalam ECMAScript 5 akan ada metode forEach pada prototipe array, tetapi tidak didukung di browser lawas. Jadi untuk dapat menggunakannya secara konsisten, Anda harus memiliki lingkungan yang mendukungnya (misalnya, Node.js untuk JavaScript sisi server), atau menggunakan "Polyfill". Namun, Polyfill untuk fungsi ini sepele dan karena membuat kode lebih mudah dibaca, itu adalah polyfill yang baik untuk dimasukkan.
sumber
for(instance in objArray)
penggunaannya tidak benar? itu terlihat lebih sederhana bagi saya, tetapi saya mendengar Anda berbicara tentang itu bukan cara yang benar untuk digunakan?var
. Jika kita menggunakan titik koma, makaelement
akan dinyatakan dalam lingkup global (atau, lebih tepatnya, JSHint akan meneriaki kita sebelum mencapai produksi).Jika Anda menggunakan perpustakaan jQuery , Anda dapat menggunakan jQuery.each :
EDIT:
Sesuai pertanyaan, pengguna menginginkan kode dalam javascript alih-alih jquery sehingga hasil editnya
sumber
Loop ke belakang
Saya pikir sebaliknya untuk loop layak disebutkan di sini:
Keuntungan:
len
variabel sementara , atau membandingkannyaarray.length
pada setiap iterasi, yang keduanya mungkin merupakan pengoptimalan menit.array[i]
), maka pengulangan akan melewatkan item yang bergeser ke kiri ke posisi i , atau memproses ulang item ke- i yang sebelumnya bergeser ke kanan. Dalam perulangan tradisional, Anda dapat memperbarui saya untuk menunjuk ke item berikutnya yang perlu diproses - 1, tetapi hanya membalikkan arah iterasi seringkali merupakan solusi yang lebih sederhana dan lebih elegan .forEach()
dan ke ES6for ... of
.Kekurangan:
Haruskah saya selalu menggunakannya?
Beberapa pengembang menggunakan reverse for loop secara default , kecuali ada alasan bagus untuk loop ke depan.
Meskipun keuntungan kinerja biasanya tidak signifikan, itu semacam jeritan:
Namun dalam praktiknya itu sebenarnya bukan indikasi niat yang dapat diandalkan, karena itu tidak dapat dibedakan dari saat-saat ketika Anda benar-benar peduli dengan pesanan, dan benar-benar perlu mengulang secara terbalik. Jadi sebenarnya diperlukan konstruksi lain untuk secara akurat mengekspresikan maksud "tidak peduli", sesuatu yang saat ini tidak tersedia di sebagian besar bahasa, termasuk ECMAScript, tetapi yang dapat disebut, misalnya
forEachUnordered()
,.Jika pesanan tidak masalah, dan efisiensi adalah masalah (di loop paling dalam dari game atau mesin animasi), maka mungkin dapat diterima untuk menggunakan reverse untuk loop sebagai pola masuk Anda. Ingatlah bahwa melihat pembalikan untuk loop dalam kode yang ada tidak selalu berarti bahwa urutannya tidak relevan!
Lebih baik menggunakan forEach ()
Secara umum untuk kode level yang lebih tinggi di mana kejelasan dan keamanan merupakan masalah yang lebih besar, saya sebelumnya merekomendasikan penggunaan
Array::forEach
sebagai pola default Anda untuk perulangan (meskipun hari ini saya lebih suka menggunakanfor..of
). Alasan untuk memilihforEach
lebih dari loop terbalik adalah:for
danwhile
loop).Kemudian ketika Anda melihat pembalikan untuk loop dalam kode Anda, itu adalah petunjuk bahwa itu terbalik karena alasan yang baik (mungkin salah satu alasan yang dijelaskan di atas). Dan melihat ke depan tradisional untuk loop dapat menunjukkan bahwa pergeseran dapat terjadi.
(Jika pembahasan niat tidak masuk akal bagi Anda, maka Anda dan kode Anda mungkin mendapat manfaat dari menonton ceramah Crockford tentang Gaya Pemrograman & Otak Anda .)
Sekarang bahkan lebih baik untuk digunakan untuk ... dari!
Ada perdebatan tentang apakah
for..of
atauforEach()
lebih disukai:Untuk dukungan peramban yang maksimal,
for..of
diperlukan polyfill untuk iterator, membuat aplikasi Anda sedikit lebih lambat untuk dieksekusi dan sedikit lebih besar untuk diunduh.Karena alasan itu (dan untuk mendorong penggunaan
map
danfilter
), beberapa panduan gaya front-end dilarangfor..of
sepenuhnya!Tetapi masalah di atas tidak berlaku untuk aplikasi Node.js, di mana
for..of
sekarang didukung dengan baik.Dan selanjutnya
await
tidak bekerja di dalamforEach()
. Penggunaanfor..of
adalah pola paling jelas dalam kasus ini.Secara pribadi, saya cenderung menggunakan apa pun yang terlihat paling mudah dibaca, kecuali kinerja atau minifikasi telah menjadi perhatian utama. Jadi hari ini saya lebih memilih untuk menggunakan
for..of
bukanforEach()
, tapi saya akan selalu menggunakanmap
ataufilter
ataufind
atausome
ketika berlaku. (Demi kolega saya, saya jarang menggunakanreduce
.)Bagaimana cara kerjanya?
Anda akan melihat bahwa itu
i--
adalah klausa tengah (di mana kita biasanya melihat perbandingan) dan klausa terakhir kosong (di mana kita biasanya melihati++
). Itu berarti yangi--
juga digunakan sebagai syarat untuk kelanjutan. Yang terpenting, ini dieksekusi dan diperiksa sebelum setiap iterasi.Bagaimana ini bisa dimulai
array.length
tanpa meledak?Karena
i--
berjalan sebelum setiap iterasi, pada iterasi pertama kita akan benar-benar mengakses itemarray.length - 1
yang menghindari masalah dengan itemArray-out-of-boundsundefined
.Mengapa tidak berhenti iterasi sebelum indeks 0?
Loop akan berhenti iterasi ketika kondisi
i--
mengevaluasi ke nilai falsey (ketika menghasilkan 0).Kuncinya adalah bahwa tidak seperti
--i
,i--
operator tambahan menuruni
tetapi menghasilkan nilai sebelum pengurangan. 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 dengan demikian kondisinya lewat. Pada iterasi berikutnyai--
perubahan i menjadi -1 tetapi menghasilkan 0 (falsey), menyebabkan eksekusi segera keluar dari bagian bawah loop.Dalam ke depan tradisional untuk loop,
i++
dan++i
dapat dipertukarkan (seperti yang ditunjukkan Douglas Crockford). Namun dalam reverse for loop, karena penurunan kami juga merupakan ekspresi kondisi kami, kami harus tetap dengani--
jika kami ingin memproses item di indeks 0.Hal sepele
Beberapa orang suka menggambar panah kecil di
for
loop terbalik , dan diakhiri dengan mengedipkan mata:Kredit pergi ke WYL untuk menunjukkan kepada saya manfaat dan kengerian dari pembalikan untuk loop.
sumber
Beberapa bahasa gaya- C digunakan
foreach
untuk mengulang enumerasi. Dalam JavaScript ini dilakukan denganfor..in
struktur loop :Ada tangkapan.
for..in
akan loop melalui masing-masing anggota objek enumerable, dan anggota pada prototipe-nya. Untuk menghindari membaca nilai yang diwariskan melalui prototipe objek, cukup periksa apakah properti itu milik objek:Selain itu, ECMAScript 5 telah menambahkan
forEach
metodeArray.prototype
yang dapat digunakan untuk menghitung lebih dari satu array menggunakan calback (polyfill ada dalam dokumen sehingga Anda masih dapat menggunakannya untuk browser yang lebih lama):Penting untuk dicatat bahwa
Array.prototype.forEach
tidak terputus ketika callback kembalifalse
. jQuery dan Underscore.js menyediakan variasi sendirieach
untuk menyediakan loop yang dapat dihubung pendek.sumber
each
metode yang memungkinkanreturn false
digunakan untuk keluar dari loop, tetapi denganforEach
ini bukanlah suatu pilihan. Bendera eksternal dapat digunakan (yaituif (flag) return;
, tetapi itu hanya akan mencegah sisa dari fungsi tubuh dari mengeksekusi,forEach
masih akan melanjutkan iterasi di seluruh koleksi.Jika Anda ingin mengulang array, gunakan
for
loop tiga bagian standar .Anda bisa mendapatkan beberapa optimasi kinerja dengan melakukan caching
myArray.length
atau mengulanginya.sumber
length
. ;),
setelah penugasan tidak memperkenalkan global baru, jadi saran Anda baik - baik saja ! Saya membingungkan ini untuk masalah yang berbeda: Menggunakan=
setelah tugas tidak membuat global baru.var i, length, arrayItem;
sebelum loop untuk menghindari kesalahpahaman ini.Saya tahu ini adalah pos lama, dan sudah ada begitu banyak jawaban. Untuk sedikit lebih lengkap saya pikir saya akan melempar yang lain menggunakan AngularJS . Tentu saja, ini hanya berlaku jika Anda menggunakan Angular, jelas, toh saya tetap ingin mengatakannya.
angular.forEach
mengambil 2 argumen dan argumen ketiga opsional. Argumen pertama adalah objek (array) untuk beralih, 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 forEach loop of angular. Yang paling sederhana dan mungkin paling banyak digunakan adalah
Cara lain yang berguna untuk menyalin item dari satu array ke array lainnya adalah
Meskipun, Anda tidak harus melakukan itu, Anda cukup melakukan hal berikut dan itu setara dengan contoh sebelumnya:
Sekarang ada pro dan kontra dari menggunakan
angular.forEach
fungsi yang bertentangan denganfor
loop bawaan rasa vanilla .Pro
angular.forEach
akan menggunakan loop ES5 forEach. Sekarang, saya akan sampai pada efisiensi di bagian kontra, karena forEach loop jauh lebih lambat daripada for loop. Saya menyebut ini sebagai pro karena senang konsisten dan standar.Pertimbangkan 2 loop bersarang berikut, yang melakukan hal yang persis sama. Katakanlah kita memiliki 2 array objek dan setiap objek berisi array hasil, yang masing-masing memiliki properti Nilai yang berupa string (atau apa pun). Dan katakanlah kita perlu mengulangi setiap hasil dan jika hasilnya sama maka lakukan beberapa tindakan:
Memang ini adalah contoh hipotetis yang sangat sederhana, tetapi saya telah menulis triple tertanam untuk loop menggunakan pendekatan kedua dan itu sangat sulit dibaca, dan menulis dalam hal ini.
Cons
angular.forEach
, dan asliforEach
, dalam hal ini, keduanya jauh lebih lambat daripadafor
loop normal .... sekitar 90% lebih lambat . Jadi untuk set data besar, lebih baik tetap padafor
loop asli .continue
sebenarnya didukung oleh " kecelakaan ", untuk melanjutkanangular.forEach
Anda meletakkanreturn;
pernyataan dalam fungsi sepertiangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
yang akan menyebabkannya terus keluar dari fungsi untuk iterasi itu. Ini juga disebabkan oleh fakta bahwa penduduk asliforEach
tidak mendukung istirahat atau melanjutkan.Saya yakin ada berbagai pro dan kontra lainnya, dan jangan ragu untuk menambahkan yang Anda inginkan. Saya rasa, intinya, jika Anda membutuhkan efisiensi, tetaplah dengan hanya
for
loop asli untuk kebutuhan looping Anda. Tetapi, jika set data Anda lebih kecil dan sedikit efisiensi tidak apa-apa untuk menyerah dalam pertukaran untuk keterbacaan dan kemampuan menulis, maka dengan cara apa pun melemparkanangular.forEach
anak nakal itu.sumber
Jika Anda tidak keberatan mengosongkan array:
x
akan berisi nilai terakhiry
dan akan dihapus dari array. Anda juga dapat menggunakanshift()
yang akan memberi dan menghapus item pertama dariy
.sumber
[1, 2, undefined, 3]
.[1, 2, 0, 3]
atau[true, true, false, true]
Sebuah forEach pelaksanaan ( lihat di jsFiddle ):
sumber
Mungkin
for(i = 0; i < array.length; i++)
loop bukan pilihan terbaik. Mengapa? Jika Anda memiliki ini:Metode akan memanggil dari
array[0]
kearray[2]
. Pertama, ini pertama akan variabel referensi Anda bahkan tidak memiliki, kedua Anda tidak akan memiliki variabel dalam array, dan ketiga ini akan membuat kode lebih tebal. Lihat di sini, itulah yang saya gunakan:Dan jika Anda ingin itu berfungsi, Anda bisa melakukan ini:
Jika Anda ingin istirahat, sedikit lebih banyak logika:
Contoh:
Ia mengembalikan:
sumber
Ada tiga implementasi
foreach
di jQuery sebagai berikut.sumber
Pada ECMAScript 6:
Di mana
of
menghindari keanehan yang terkait denganin
dan membuatnya bekerja sepertifor
loop dari bahasa lain, danlet
mengikati
dalam loop sebagai lawan dalam fungsi.Kawat gigi (
{}
) dapat dihilangkan ketika hanya ada satu perintah (misalnya dalam contoh di atas).sumber
Solusi mudah sekarang adalah dengan menggunakan perpustakaan underscore.js . Ini menyediakan banyak alat yang bermanfaat, seperti
each
dan akan secara otomatis mendelegasikan pekerjaan kepada penduduk asliforEach
jika tersedia.Contoh CodePen tentang cara kerjanya adalah:
Lihat juga
Array.prototype.forEach()
.for each (variable in object)
tidak digunakan lagi sebagai bagian dari standar ECMA-357 ( EAX ).for (variable of object)
sebagai bagian dari proposal Harmony (ECMAScript 6).sumber
Tidak ada
for each
loop dalam JavaScript asli . Anda dapat menggunakan pustaka untuk mendapatkan fungsi ini (saya sarankan Underscore.js ), gunakanfor
loop sederhana .Namun, perhatikan bahwa mungkin ada alasan untuk menggunakan
for
loop yang lebih sederhana (lihat pertanyaan Stack Overflow Mengapa menggunakan "untuk ... dalam" dengan iterasi array, ide yang buruk? )sumber
Ini adalah iterator untuk daftar NON-jarang di mana indeks dimulai pada 0, yang merupakan skenario khas ketika berhadapan dengan document.getElementsByTagName atau document.querySelectorAll)
Contoh penggunaan:
Contoh 1
Contoh # 2
Setiap tag p mendapat
class="blue"
Contoh # 3
Setiap tag p lainnya mendapat
class="red"
>Contoh # 4
Dan akhirnya 20 tag p biru pertama diubah menjadi hijau
Perhatian saat menggunakan string sebagai fungsi: fungsi ini dibuat di luar konteks dan harus digunakan hanya jika Anda yakin akan pelingkupan variabel. Jika tidak, lebih baik melewati fungsi di mana pelingkupan lebih intuitif.
sumber
Ada beberapa cara untuk mengulang-ulang array dalam JavaScript, seperti di bawah ini:
untuk - itu yang paling umum . Blok penuh kode untuk perulangan
while - loop saat suatu kondisi sedang lewat. Tampaknya menjadi loop tercepat
do / while - juga loop melalui blok kode sementara kondisinya benar, akan berjalan setidaknya satu kali
Loop fungsional -
forEach
,map
,filter
, jugareduce
(lingkaran mereka melalui fungsi, tetapi mereka digunakan jika Anda perlu untuk melakukan sesuatu dengan array, dllUntuk informasi lebih lanjut dan contoh tentang pemrograman fungsional pada array, lihat posting blog Pemrograman fungsional dalam JavaScript: peta, filter dan kurangi .
sumber
forEach
bukan loop "fungsional" karena tidak mengembalikan yang baruArray
(sebenarnya itu tidak mengembalikan apa pun), itu hanya berulang.ECMAScript 5 (versi JavaScript) untuk bekerja dengan Array:
forEach - Memisahkan setiap item dalam array dan melakukan apa pun yang Anda butuhkan dengan setiap item.
Dalam hal ini, lebih tertarik pada operasi pada array menggunakan beberapa fitur bawaan.
map - Ini menciptakan array baru dengan hasil dari fungsi callback. Metode ini baik untuk digunakan ketika Anda perlu memformat elemen array Anda.
mengurangi - Seperti namanya, itu mengurangi array ke nilai tunggal dengan memanggil fungsi yang diberikan lewat elemen saat ini dan hasil dari eksekusi sebelumnya.
every - Mengembalikan nilai true atau false jika semua elemen dalam array lulus tes dalam fungsi callback.
filter - Sangat mirip dengan setiap kecuali filter mengembalikan array dengan elemen yang mengembalikan true ke fungsi yang diberikan.
sumber
Tidak ada kemampuan bawaan untuk masuk
forEach
. Untuk menghentikan eksekusi, gunakanArray#some
seperti di bawah ini:Ini berfungsi karena
some
mengembalikan true segera setelah salah satu dari callback, dieksekusi dalam urutan array, mengembalikan true, hubungan pendek eksekusi sisanya. Jawaban Asli, lihat prototipe array untuk beberapasumber
Saya juga ingin menambahkan ini sebagai komposisi loop terbalik dan jawaban di atas untuk seseorang yang ingin sintaks ini juga.
Pro:
Manfaat untuk ini: Anda sudah memiliki referensi di pertama seperti itu tidak perlu dinyatakan kemudian dengan baris lain. Ini berguna saat perulangan melalui array objek.
Cons:
Ini akan rusak setiap kali referensi salah - falsey (tidak ditentukan, dll.). Ini bisa digunakan sebagai keuntungan. Namun, itu akan membuatnya sedikit lebih sulit untuk dibaca. Dan juga tergantung pada browser itu bisa "tidak" dioptimalkan untuk bekerja lebih cepat daripada yang asli.
sumber
Cara jQuery menggunakan
$.map
:sumber
[undefined, 2, undefined, 4, undefined, 6, undefined]
.Menggunakan loop dengan destruksi ECMAScript 6 dan operator spread
Destrukturisasi dan penggunaan operator penyebaran telah terbukti cukup berguna bagi pendatang baru ke ECMAScript 6 sebagai lebih dapat dibaca / estetika manusia, meskipun beberapa veteran JavaScript mungkin menganggapnya berantakan. Junior atau orang lain mungkin merasa berguna.
Contoh 1: Normal
for...of
loop - tidak ada trik di sini.Contoh 2: Pisahkan kata menjadi karakter
Contoh 3: Looping dengan a
key
danvalue
Contoh 4: Dapatkan properti objek inline
Contoh 5: Dapatkan properti objek mendalam dari apa yang Anda butuhkan
Contoh 6: Apakah Contoh 3 digunakan dengan
.forEach
Contoh 7: Apakah Contoh 4 digunakan dengan
.forEach
Contoh 8: Apakah Contoh 5 digunakan dengan
.forEach
sumber
Cara terdekat dengan ide Anda adalah dengan menggunakan
Array.forEach()
yang menerima fungsi penutupan yang akan dieksekusi untuk setiap elemen array.Cara lain yang layak adalah menggunakan
Array.map()
yang berfungsi dengan cara yang sama, tetapi juga mengambil semua nilai yang Anda kembalikan dan mengembalikannya dalam array baru (pada dasarnya memetakan setiap elemen ke yang baru), seperti ini:sumber
map
tidak mengubah elemen array, karena mengembalikan array baru, dengan item yang baru menjadi hasil penerapan fungsi ke item array lama.Anda dapat menghubungi forEach seperti ini:
forEach
akan beralih di atas array yang Anda berikan dan untuk setiap iterasi akan memilikielement
yang memegang nilai iterasi itu. Jika Anda membutuhkan indeks, Anda bisa mendapatkan indeks saat ini dengan melewatkani
sebagai parameter kedua dalam fungsi panggilan balik untuk forEach.Foreach pada dasarnya adalah Fungsi Tingkat Tinggi, yang mengambil fungsi lain sebagai parameternya.
Keluaran:
Anda juga dapat beralih ke array seperti ini:
sumber
Jika Anda ingin mengulang melalui array objek dengan fungsi panah:
sumber
Sintaks lambda biasanya tidak berfungsi di Internet Explorer 10 atau di bawah.
Saya biasanya menggunakan
Jika Anda adalah penggemar jQuery dan sudah menjalankan file jQuery, Anda harus membalik posisi indeks dan parameter nilai
sumber
Jika Anda memiliki array besar yang harus Anda gunakan
iterators
untuk mendapatkan efisiensi. Iterator adalah properti dari koleksi JavaScript tertentu (sepertiMap
,Set
,String
,Array
). Bahkan,for..of
menggunakaniterator
under-the-hood.Iterator meningkatkan efisiensi dengan membiarkan Anda mengonsumsi item dalam daftar satu per satu seolah-olah itu adalah stream. Apa yang membuat iterator spesial adalah bagaimana ia melintasi koleksi. Loop lain perlu memuat seluruh koleksi di depan untuk beralih di atasnya, sedangkan iterator hanya perlu mengetahui posisi saat ini dalam koleksi.
Anda mengakses item saat ini dengan memanggil metode iterator
next
. Metode selanjutnya akan mengembalikanvalue
item saat ini danboolean
untuk menunjukkan kapan Anda telah mencapai akhir koleksi. Berikut ini adalah contoh membuat iterator dari array.Ubah array reguler Anda menjadi iterator menggunakan
values()
metode seperti ini:Anda juga dapat mengubah array reguler Anda ke iterator menggunakan
Symbol.iterator
seperti ini:Anda juga dapat mengubah reguler Anda
array
menjadiiterator
seperti ini:CATATAN :
iterable
secara default. Menggunakanfor..in
dalam kasus itu karena alih-alih nilai-nilai itu bekerja dengan kunci.Anda dapat membaca lebih lanjut tentang di
iteration protocol
sini .sumber
Jika Anda ingin menggunakannya
forEach()
, akan terlihat seperti -Jika Anda ingin menggunakannya
for()
, akan terlihat seperti -sumber
Sesuai dengan fitur baru yang diperbarui ECMAScript 6 (ES6) dan ECMAScript 2015, Anda dapat menggunakan opsi berikut dengan loop:
sumber
Performa
Hari ini (2019-12-18) saya melakukan pengujian pada macOS v10.13.6 (High Sierra), di Chrome v 79.0, Safari v13.0.4 dan Firefox v71.0 (64 bit) - kesimpulan tentang pengoptimalan (dan pengoptimalan mikro yang biasanya tidak layak untuk memperkenalkannya ke kode karena manfaatnya kecil, tetapi kompleksitas kode tumbuh).
Sepertinya tradisional
for i
( Aa ) adalah pilihan yang baik untuk menulis kode cepat di semua browser.Solusi lain, seperti
for-of
( Iklan ), semua dalam grup C. ... biasanya 2 - 10 (dan lebih) kali lebih lambat dari Aa , tetapi untuk array kecil tidak apa-apa untuk menggunakannya - demi meningkatkan kejelasan kode.Loop dengan panjang array yang di-cache dalam
n
( Ab, Bb, Be ) terkadang lebih cepat, kadang tidak. Mungkin kompiler secara otomatis mendeteksi situasi ini dan memperkenalkan caching. Perbedaan kecepatan antara versi yang di-cache dan yang tidak di-cache ( Aa, Ba, Bd ) sekitar ~ 1%, jadi sepertinya introduksin
adalah optimasi mikro .The
i--
seperti solusi mana loop dimulai dari elemen array terakhir ( Ac, Bc ) biasanya ~ 30% lebih lambat dari solusi ke depan - mungkin alasannya adalah cara memory CPU Cache kerja - maju memori membaca lebih optimal untuk CPU caching). Dianjurkan untuk TIDAK MENGGUNAKAN solusi tersebut.Detail
Dalam pengujian kami menghitung jumlah elemen array. Saya melakukan tes untuk array kecil (10 elemen) dan array besar (elemen 1M) dan membaginya menjadi tiga kelompok:
for
teswhile
tesTampilkan cuplikan kode
Lintas hasil browser
Hasil untuk semua browser yang diuji
browser **
Array dengan 10 elemen
Hasil untuk Chrome. Anda dapat melakukan tes pada mesin Anda di sini .
Array dengan 1.000.000 elemen
Hasil untuk Chrome. Anda dapat melakukan tes pada mesin Anda di sini
sumber
Ringkasan:
Ketika beralih ke array, kita sering ingin mencapai salah satu dari tujuan berikut:
Kami ingin beralih di atas array dan membuat array baru:
Array.prototype.map
Kami ingin mengulangi array dan tidak membuat array baru:
Array.prototype.forEach
for..of
lingkaranDalam JavaScript, ada banyak cara untuk mencapai kedua tujuan ini. Namun, beberapa lebih nyaman daripada yang lain. Di bawah ini Anda dapat menemukan beberapa metode yang umum digunakan (IMO paling nyaman) untuk menyelesaikan iterasi array dalam JavaScript.
Membuat array baru:
Map
map()
adalah fungsi yang terletak diArray.prototype
mana dapat mengubah setiap elemen array dan kemudian mengembalikan array baru .map()
mengambil sebagai argumen fungsi panggilan balik dan bekerja dengan cara berikut:Callback yang kami sampaikan
map()
sebagai argumen dieksekusi untuk setiap elemen. Kemudian sebuah array dikembalikan yang memiliki panjang yang sama dengan array asli. Dalam elemen array baru ini ditransformasikan oleh fungsi callback yang diteruskan sebagai argumenmap()
.Perbedaan yang berbeda antara
map
dan mekanisme loop lain sepertiforEach
danfor..of
loop adalah yangmap
mengembalikan array baru dan membiarkan array lama tetap utuh (kecuali jika Anda secara eksplisit memanipulasi dengan berpikir sepertisplice
).Juga, perhatikan bahwa
map
fungsi callback memberikan nomor indeks dari iterasi saat ini sebagai argumen kedua. Selanjutnya, apakah argumen ketiga menyediakan array yangmap
dipanggil? Terkadang sifat ini bisa sangat berguna.Loop menggunakan
forEach
forEach
adalah fungsi yang terletak diArray.prototype
mana mengambil fungsi callback sebagai argumen. Itu kemudian mengeksekusi fungsi callback ini untuk setiap elemen dalam array. Berbeda denganmap()
fungsi, fungsi forEach mengembalikan apa-apa (undefined
). Sebagai contoh:Sama seperti
map
fungsi,forEach
panggilan balik memberikan nomor indeks dari iterasi saat ini sebagai argumen kedua. Juga, apakah argumen ketiga menyediakan array yangforEach
dipanggil?Loop melalui elemen menggunakan
for..of
The
for..of
Loop loop melalui setiap elemen array (atau benda iterable lainnya). Ini bekerja dengan cara berikut:Dalam contoh di atas,
element
singkatan dari elemen array danarr
merupakan array yang ingin kita loop. Perhatikan bahwa namaelement
tersebut arbitrer, dan kami dapat memilih nama lain seperti 'el' atau sesuatu yang lebih deklaratif saat ini berlaku.Jangan bingung antara
for..in
loop denganfor..of
loop.for..in
akan mengulang semua properti enumerable dari array sedangkanfor..of
loop hanya akan mengulang melalui elemen array. Sebagai contoh:sumber