Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. JavaScript

Cara menggunakan Map, Filter, dan Reduce di JavaScript

by
Read Time:16 minsLanguages:

Indonesian (Bahasa Indonesia) translation by Andy Nur (you can also view the original English article)

Pemrograman fungsional telah membuat cukup banyak percikan di dunia pengembangan akhir-akhir ini. Dan untuk alasan yang baik: Teknik fungsional dapat membantumu menulis lebih banyak kode deklaratif yang lebih mudah dipahami sekilas, refaktor, dan tes.

Salah satu pilar pemrograman fungsional adalah penggunaan khusus daftar dan operasi daftar. Dan hal-hal itu persis seperti apa terdengarnya: array dari berbagai hal, dan hal-hal yang kamu lakukan kepadanya. Tetapi pola pikir fungsional memperlakukannya sedikit berbeda dari yang kamu duga.

Artikel ini akan melihat lebih dekat pada apa yang saya suka sebut operasi daftar "big three": map, filter, dan reduce. Membungkus kepalamu di sekitar ketiga fungsi ini merupakan langkah penting untuk dapat menulis kode fungsional yang bersih, dan membuka pintu bagi teknik pemrograman fungsional dan reaktif yang sangat kuat.

Ini juga berarti kamu tidak perlu menulis perulangan for lagi.

Ingin tahu? Mari kita selami.

Peta Dari Daftar ke Daftar

Seringkali, kita menemukan diri kita perlu mengambil array dan memodifikasi setiap elemen di dalamnya dengan cara yang persis sama. Contoh-contoh yang umum adalah mengkuadratkan setiap elemen dalam array angka, mengambil nama dari daftar pengguna, atau menjalankan regex pada suatu array string.

map adalah metode yang dibuat untuk melakukan hal itu. Ini didefinisikan pada Array.prototype, sehingga kamu dapat memanggilnya di array apa pun, dan ia menerima callback sebagai argumen pertamanya.

Ketika kamu memanggil map pada suatu array, ia akan menjalankan callback tersebut pada setiap elemen di dalamnya, mengembalikan sebuah array baru dengan semua nilai yang dikembalikan oleh callback.

Pada dasarnya, map meneruskan tiga argumen ke callback-mu:

  1. Item saat ini di dalam array
  2. Indeks array dari item saat ini
  3. Seluruh array yang kamu sebut map

Mari kita lihat beberapa kode.

map dalam Prakteknya

Misalkan kita memiliki aplikasi yang mengelola berbagai tugasmu untuk hari itu. Setiap task adalah objek, masing-masing dengan properti name dan duration:

Katakanlah kita ingin membuat array baru hanya dengan nama setiap tugas, sehingga kita dapat melihat semua yang telah kita selesaikan hari ini. Dengan menggunakan perulangan for, kita akan menulis sesuatu seperti ini:

JavaScript juga menawarkan perulangan forEach. Ini berfungsi seperti perulangan for, tetapi mengatur semua messiness memeriksa indeks perulangan kita terhadap panjang array untuk kita:

Dengan menggunakan map, kita bisa menulis:

Saya menyertakan parmeter index dan array untuk mengingatkanmu bahwa mereka ada di sana jika kamu membutuhkannya. Karena saya tidak menggunakannya di sini, kamu bisa meninggalkannya, dan kode itu akan berjalan dengan baik.

Ada beberapa perbedaan penting antara dua pendekatan tersebut:

  1. Dengan menggunakan map, kamu tidak perlu mengelola keadaan perulangan for mu sendiri.
  2. Kamu dapat mengoperasikan elemen secara langsung, daripada harus mengindeks ke dalam array.
  3. Kamu tidak perlu membuat array baru dan melakukan push padanya. map mengembalikan semua produk jadi sekaligus, jadi kita dapat dengan mudah menetapkan nilai kembalian ke variabel baru.
  4. Kamu harus ingat untuk memasukkan pernyataan return di callback-mu. Jika tidak, kamu akan mendapatkan array baru yang diisi dengan undefined.

Menghasilkan, semua fungsi yang akan kita lihat hari ini pada bagian karakteristik tersebut.

Fakta bahwa kita tidak harus mengelola keadaan perulangan secara manual membuat kode kita lebih sederhana dan lebih mudah dipelihara. Fakta bahwa kita dapat beroperasi secara langsung pada elemen daripada harus mengindeks ke dalam array membuat hal-hal lebih mudah dibaca.

Menggunakan perulangan forEach memecahkan kedua masalah ini untuk kita. Tetapi map masih memiliki setidaknya dua keuntungan berbeda:

  1. forEach mengembalikan undefined, sehingga tidak bertautan dengan metode array lainnya. map mengembalikan array, sehingga kamu bisa menautkannya dengan metode array lainnya.
  2. map mengembalikan array dengan produk jadi, daripada meminta kita untuk mem-mutasi array di dalam perulangan.

Menjaga jumlah tempat di mana kamu mengubah keadaan ke minimum absolut adalah prinsip penting dari pemrograman fungsional. Itu membuat kode lebih aman dan lebih dimengerti.

Sekarang juga saat yang tepat untuk menunjukkan bahwa jika kamu berada di Node, mengetes contoh ini di konsol browser Firefox, atau menggunakan Babel atau Traceur, kamu dapat menulis ini lebih singkat dengan fungsi panah ES6:

Fungsi panah membiarkan kita meninggalkan kata kunci return dalam satu baris.

Itu tidak jauh lebih mudah dibaca daripada itu.

Gotcha

Callback yang kamu teruskan ke map harus memiliki pernyataan return eksplisit, atau map akan memuntahkan array yang dengan dengan undefined. Tidak sulit untuk mengingat memasukkan suatu nilai return, tetapi itu tidak sulit untuk dilupakan.

Jika kamu lupa, map tidak akan mengeluh. Sebaliknya, itu akan diam-diam mengembalikan array penuh dengan kekosongan. Error yang senyap seperti itu dapat sangat sulit untuk didebug.

Untungnya, ini adalah satu-satunya gotcha dengan map. Tapi itu adalah perangkap yang cukup umum yang harus saya tekankan: Selalu pastikan callback-mu berisi pernyataan return!

Implementasi

Membaca implementasi adalah bagian penting dari pemahaman. Jadi, mari tulis map ringan kita sendiri untuk lebih memahami apa yang terjadi pada dasarnya. Jika kamu ingin melihat implementasi kualitas produksi, periksa Mozilla polyfill di MDN.

Kode ini menerima array dan fungsi callback sebagai argumen. Ini kemudian membuat array baru; menjalankan callback pada setiap elemen pada array yang kita teruskan; mendorong hasil ke dalam array baru; dan mengembalikan array baru. Jika kamu menjalankan ini di konsolmu, kamu akan mendapatkan hasil yang sama seperti sebelumnya. Pastikan kamu menginisialisasi tasks sebelum kamu mengetesnya!

Meskipun kkita menggunakan perulangan for pada dasarnya, membungkusnya ke dalam fungsi menyembunyikan detail dan memungkinkan kita bekerja dengan abstraksi sebagai gantinya.

Itu membuat kode kita lebih bersifat deklaratif—ia mengatakan apa yang harus dilakukan, bukan bagaimana melakukannya. Kamu akan menghargai betapa kodemu ini dibuat lebih mudah dibaca, dipelihara, dan, erm, mudah di-debug.

Menyaring Kebisingan

Selanjutnya dari operasi array kita adalah filter. Itu persis seperti apa terdengar: Dibutuhkan suatu array, dan menyaring elemen yang tidak diinginkan.

Seperti map, filter didefinisikan pada Array.prototype. Ini tersedia di berbagai array, dan kamu memberikannya callback sebagai argumen pertama. filter mengeksekusi callback itu pada setiap elemen dari array, dan memunculkan array baru yang hanya berisi elemen-elemen di mana callback itu mengembalikan nilai true.

Juga seperti map, filter meneruskan tiga argumen callback-mu:

  1. Item saat ini
  2. Indeks saat ini
  3. Array yang kamu sebut filter

filter dalam Prakteknya

Mari kita lihat kembali contoh tugas kita. Daripada menarik nama setiap tugas, katakanlah saya ingin mendapatkan daftar tugas yang membutuhkan waktu dua jam atau lebih untuk menyelesaikannya.

Dengan menggunakan forEach, kita akan menulis:

Dengan filter:

Di sini, saya telah melanjutkan dan meninggalkan argumen index dan array ke callback kita, karena kita tidak menggunakannya.

Sama seperti map, filter memungkinkan kita:

  • menghindari mutasi array di dalam perulangan forEach atau for
  • menetapkan hasilnya langsung ke variabel baru, daripada mendorong ke dalam array yang kita tentukan di tempat lain

Gotcha

Callback yang kamu berikan ke map harus menyertakan pernyataan return jika kamu ingin berfungsi dengan benar. Dengan filter, kamu juga harus menyertakan pernyataan pengembalian, dan kamu harus memastikannya mengembalikan nilai boolean.

Jika kamu lupa pernyataan return, callback-mu akan mengembalikan undefined, yang mana filter tidak akan membantu dengan paksa ke false. Daripada melemparkan error, itu akan secara senyap mengembalikan array kosong!

Jika kamu menuju ke rute lain, dan mengembalikan sesuatu yang tidak secara eksplisit true atau false, kemudian filter akan mencoba untuk mencari tahu apa yang kamu maksud dengan menerapkan aturan paksaan JavaScript. Lebih sering daripada tidak, ini adalah bug. Dan, seperti melupakan pernyataan return-mu, itu akan menjadi pernyataan senyap.

Selalu pastikan callbackmu menyertakan pernyataan return eksplisit. Dan selalu pastikan callback-mu di filter kembali mengembalikan nilai true atau false. Kewarasanmu akan berterima kasih.

Implementasi

Sekali lagi, cara terbaik untuk memahami sepotong kode adalah ... yah, dengan menulisnya. Mari kita gulirkan filter ringan kita sendiri. Orang-orang baik di Mozilla memiliki polyfill kekuatan industri untuk kamu baca juga.

Mengurangi Array

map membuat array baru dengan mengubah setiap elemen dalam array, secara terpisah. filter membuat array baru dengan menghapus elemen yang bukan miliknya. reduce, di sisi lain, mengambil semua elemen dalam array, dan menguranginya menjadi satu nilai.

Sama seperti map dan filter, reduce didefinisikan pada Array.prototype dan tersedia di array apa pun, dan kamu meneruskan callback sebagai argumen pertama. Tetapi ini juga membutuhkan argumen kedua yang opsional: nilai untuk mulai menggabungkan semua elemen array-mu ke dalamnya.

reduce meneruskan empat argumen callback-mu:

  1. Nilai saat ini
  2. Nilai sebelumnya
  3. Indeks saat ini
  4. Array yang kamu sebut reduce

Perhatikan bahwa callback mendapat nilai sebelumnya pada setiap perulangan. Pada perulangan pertama, tidak ada nilai sebelumnya. Inilah sebabnya mengapa kamu memiliki pilihan untuk meneruskan reduce suatu nilai awal: Ini bertindak sebagai "nilai sebelumnya" untuk perulangan pertama, ketika tidak ada yang akan menjadi yang pertama.

Akhirnya, ingatlah bahwa reduce mengembalikan nilai tunggal, bukan array yang berisi satu item. Hal ini lebih penting daripada yang terlihat, dan saya akan kembali ke contohnya.

reduce dalam Prakteknya

Karena reduce adalah fungsi yang orang-orang temukan sebagai yang paling asing pada awalnya, kita akan mulai dengan berjalan selangkah demi selangkah melalui sesuatu yang sederhana.

Katakanlah kita ingin mencari jumlah daftar angka. Menggunakan perulangan, itu terlihat seperti ini:

Meskipun ini bukan kasus penggunaan yang buruk untuk forEach, reduce masih memiliki keuntungan yang memungkinkan kita untuk menghindari mutasi. Dengan reduce, kita akan menulis:

Pertama, kita memanggil reduce pada daftar numbers kita. Kita memberikannya callback, yang menerima nilai sebelumnya dan nilai saat ini sebagai argumen, dan mengembalikan hasil penambahannya bersamaan. Karena kita meneruskan 0 sebagai argumen kedua untuk melakukan reduce, itu akan digunakan sebagai nilai previous (sebelumnya) pada perulangan pertama.

Jika kita selangkah demi selangkah, tampilannya seperti ini:

Perulangan Sebelumnya Saat ini Total
1 0 1 1
2 1 2 3
3 3 3 6
4 6 4 10
5 10 5 15

Jika kamu bukan penggemar tabel, jalankan cuplikan ini di konsol:

Ringkasnya: reduce melakukan perulangan atas semua elemen array, menggabungkan mereka namun kamu tentukan di callback-mu. Pada setiap iterasi, callback-mu memiliki akses ke nilai sebelumnya, yang merupakan total-sejauh-ini, atau nilai akumulasi; nilai saat ini; indeks saat ini; dan seluruh array, jika kamu membutuhkannya.

Mari kita kembali ke contoh tugas kita. Kita telah mendapatkan daftar nama tugas dari map, dan daftar tugas yang difilter yang memakan waktu lama dengan ... yah, filter.

Bagaimana jika kita ingin mengetahui jumlah total waktu yang kita habiskan bekerja hari ini?

Menggunakan perulangan forEach, kamu akan menulis:

Dengan reduce, itu menjadi:

Mudah.

Itu hampir seluruh yang ada untuk hal itu. Hampir, karena JavaScript memberi kita satu metode yang lebih sedikit diketahui, yang disebut reduceRight. Dalam contoh di atas, reduce mulai pada item pertama dalam array, perulangan dari kiri ke kanan:

reduceRight melakukan hal yang sama, tetapi dalam arah yang berlawanan:

Saya menggunakan reduce setiap hari, tetapi saya tidak pernah membutuhkan reduceRight. Saya rasa kamu mungkin tidak akan melakukannya juga. Tetapi jika kamu pernah melakukannya, sekarang kamu tahu itu ada di sana.

Gotcha

Tiga gotcha ​​besar dengan reduce adalah:

  1. Lupa untuk melakukan return
  2. Melupakan nilai awal
  3. Mengharapkan array saat reduce mengembalikan satu nilai

Untungnya, dua yang pertama mudah dihindari. Memutuskan apa nilai awalmu harus bergantung pada apa yang kamu lakukan, tetapi kamu akan cepat menguasainya.

Yang terakhir mungkin tampak agak aneh. Jika reduce hanya akan mengembalikan nilai tunggal, mengapa kamu mengharapkan sebuah array?

Ada beberapa alasan bagus untuk itu. Pertama, reduce selalu mengembalikan nilai tunggal, tidak selalu angka tunggal. Jika kamu mengurangi suatu array pada array-array, misalnya, ia akan mengembalikan array tunggal. Jika kamu dalam kebiasaan atau mengurangi array, akan adil untuk mengharapkan bahwa array yang berisi satu item tidak akan menjadi kasus khusus.

Kedua, jika reduce memang mengembalikan array dengan nilai tunggal, itu akan secara alami berjalan bagus dengan map dan filter, dan fungsi lain pada array yang mungkin kamu gunakan dengannya.

Implementasi

Saatnya untuk tampilan terakhir kita pada dasarnya. Seperti biasa, Mozilla memiliki polyfill antipeluru untuk reduce jika kamu ingin memeriksanya.

Dua hal yang perlu diperhatikan di sini:

  1. Kali ini, saya menggunakan nama accumulator daripada previous. Ini adalah apa yang biasanya kamu lihat di alam liar.
  2. Saya menetapkan accumulator sebagai nilai awal, jika pengguna menyediakannya, dan default-nya ke 0, jika tidak. Ini adalah bagaimana reduce yang nyata berperilaku, juga.

Menggunakannya bersamaan: Map, Filter, Reduce, dan Chainability

Pada titik ini, kamu mungkin tidak begitu terkesan.

Cukup adil: map, filter, dan reduce, dengan sendirinya, tidak terlalu menarik.

Setelah semua, kekuatan sejati mereka terletak pada keterkaitan mereka.

Katakanlah saya ingin melakukan hal berikut:

  1. Mengumpulkan tugas selama dua hari.
  2. Mengonversi durasi tugas ke jam, bukan menit.
  3. Memfilter semua yang membutuhkan waktu dua jam atau lebih.
  4. Menjumlahkan semuanya.
  5. Mengalikan hasilnya dengan tarif per jam untuk penagihan.
  6. Menghasilkan output jumlah dolar yang diformat.

Pertama, mari tentukan tugas-tugas kita untuk hari Senin dan Selasa:

Dan sekarang, transformasi kita yang indah:

Atau, lebih ringkas:

Jika kamu sudah sampai sejauh ini, ini seharusnya cukup mudah. Ada dua sedikit keanehan yang bisa dijelaskan.

Pertama, pada baris 10, saya seharusnya menulis:

Dua hal yang perlu dijelaskan di sini:

  1. Tanda plus di depan accumulator dan current memaksakan nilai-nilainya ke angka. Jika kamu tidak melakukan ini, nilai kembalian akan menjadi string yang agak tidak berguna, "12510075100".
  2. Jika tidak membungkus jumlah itu dalam tanda kurung, reduce akan memuntahkan nilai tunggal, bukan array. Itu akan berakhir dengan melempar TypeError, karena kamu hanya dapat menggunakan map pada array!

Bit kedua yang mungkin membuatmu sedikit tidak nyaman adalah reduce yang terakhir, yaitu:

Itu memanggil map untuk mengembalikan array yang berisi nilai tunggal. Di sini, kita memanggil reduce untuk menarik keluar nilai itu.

Cara lain untuk melakukan ini adalah dengan menghapus panggilan untuk mengurangi, dan mengindeks ke dalam array yang memuntahkan map:

Itu sangat benar. Jika kamu lebih nyaman menggunakan indeks array, silakan saja.

Tetapi saya mendorongmu untuk tidak melakukannya. Salah satu cara paling ampuh untuk menggunakan fungsi-fungsi ini adalah dalam bidang pemrograman reaktif, di mana kamu tidak akan bebas menggunakan indeks array. Menendang kebiasaan itu sekarang akan membuat teknik belajar reaktif jauh lebih mudah dalam keseluruhannya.

Akhirnya, mari kita lihat bagaimana teman kita perulangan forEach akan menyelesaikannya:

Ditoleransi, tetapi ramai.

Kesimpulan & Langkah Berikutnya

Pada tutorial ini, kamu telah belajar bagaimana map, filter, dan reduce bekerja; bagaimana cara menggunakannya; dan kira-kira bagaimana mereka diimplementasikan. Kamu telah melihat bahwa mereka semua memungkinkanmu untuk menghindari keadaan mutasi, yang mengharuskan penggunaan perulangan for dan foreach, dan kamu sekarang seharusnya memiliki gagasan yang baik tentang bagaimana untuk menyatukan mereka semua.

Sekarang, saya yakin kamu ingin berlatih dan membaca lebih lanjut. Berikut adalah tiga saran utama saya untuk ke mana harus menuju selanjutnya:

  1. Latihan yang luar biasa dari Jafar Husain tentang Pemrograman Fungsional dalam JavaScript, lengkap dengan pengenalan yang solid untuk Rx.js
  2. Pengajar Kursus Envato Tuts+ Jason Rhodes tentang Pemrograman Fungsional dalam JavaScript
  3. Panduan Yang Paling Memadai untuk Pemrograman Fungsional, yang lebih mendalam tentang mengapa kita menghindari mutasi, dan pemikiran fungsional secara umum

JavaScript telah menjadi salah satu bahasa de-facto yang bekerja di web. Bukan tanpa alur pembelajaran, dan ada banyak framework dan library untuk membuatmu sibuk juga. Jika kamu mencari sumber daya tambahan untuk dipelajari atau digunakan dalam pekerjaanmu, periksa apa yang kami miliki di Envato marketplace.

Jika kamu ingin lebih banyak tentang hal semacam ini, cek profil saya dari waktu ke waktu; tangkap saya di Twitter (@PelekeS); atau klik blog saya di http://peleke.me.

Pertanyaan, komentar, atau kebingungan? Biarkan mereka di bawah, dan saya akan melakukan yang terbaik untuk kembali ke masing-masing secara individual.

Advertisement
Did you find this post useful?
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.