Fungsi Adalah Nilai
Di JavaScript, fungsi adalah nilai seperti nilai lainnya. Kamu bisa menyimpannya di variabel, memasukkannya ke array, memberikannya ke fungsi lain, atau mengembalikannya dari sebuah fungsi. Fakta itu saja sudah membuka satu gaya pemrograman tersendiri:
Begitu kamu terbiasa memperlakukan fungsi sebagai nilai, higher-order function tidak lagi terasa misterius. Higher-order function hanyalah fungsi yang menerima fungsi sebagai argumen, mengembalikan fungsi, atau keduanya. Itulah seluruh definisinya.
Menerima Fungsi sebagai Argumen
Bentuk yang paling umum: fungsi yang menerima callback dan menjalankannya untukmu. Kamu sudah memakainya tanpa memikirkannya.
forEach adalah higher-order: ia menerima fungsimu dan memanggilnya sekali untuk setiap item. setTimeout adalah higher-order: ia menerima fungsimu dan memanggilnya setelah jeda. Kamu fokus pada apa yang dilakukan; mereka mengurus kapan dan berapa kali.
Menulis versimu sendiri terlihat sama. Berikut fungsi kecil yang menjalankan callback hanya kalau sebuah kondisi bernilai true:
action adalah parameter yang kebetulan berisi fungsi. Memanggilnya dengan action() menjalankan apa pun yang diberikan.
Tiga yang Benar-Benar Akan Kamu Pakai: map, filter, reduce
Array dilengkapi method higher-order yang menggantikan sebagian besar loop for yang seharusnya kamu tulis. Kuasai ketiganya, dan banyak sekali kode sehari-hari jadi lebih pendek dan jelas.
map: mengubah setiap item
map memanggil fungsimu sekali untuk setiap item dan mengumpulkan nilai kembaliannya ke array baru. Panjangnya sama, isinya sudah diubah. Array aslinya tidak dimodifikasi.
filter: menyimpan yang cocok
filter menyimpan item yang membuat callback mengembalikan nilai truthy dan membuang sisanya. Nilai kembaliannya array baru, mungkin lebih pendek.
reduce: meringkas array menjadi satu nilai
reduce adalah yang serbaguna. Callback menerima akumulator yang terus berjalan dan item saat ini; apa pun yang kamu kembalikan menjadi akumulator berikutnya. Argumen kedua (di sini 0) adalah nilai awalnya.
Kamu bisa merangkainya. Di sinilah gaya ini terbayar:
Baca dari atas ke bawah: simpan pesanan yang sudah dibayar, ambil harganya, lalu jumlahkan. Tanpa loop, tanpa counter yang berubah-ubah, tanpa error selisih satu yang perlu dikhawatirkan.
Mengembalikan Fungsi dari Fungsi
Separuh lainnya dari higher-order. Fungsi yang membangun lalu mengembalikan fungsi lain:
multiplyBy(2) berjalan sekali dan menyerahkan fungsi yang benar-benar baru. Fungsi baru itu masih mengingat factor. Itulah closure, dan nanti ada halamannya sendiri. Untuk sekarang, pelajarannya: memanggil multiplyBy dengan argumen berbeda memberimu fungsi-fungsi khusus yang berbeda, dibangun dari templat yang sama.
Pola ini muncul di mana-mana:
Satu definisi, dua fungsi yang bisa dipakai ulang. Lebih baik daripada menulis warn dan info secara manual lalu menjaga keduanya tetap sinkron.
Fungsi Bernama vs Callback Inline
Kamu bisa memberikan arrow function langsung di tempat, atau memberikan fungsi lewat namanya. Keduanya berfungsi, pilih yang lebih enak dibaca:
Saat kamu memberikan isEven (tanpa kurung), kamu menyerahkan fungsinya sendiri. Menambahkan () akan langsung memanggilnya dan memberikan hasilnya, kesalahan umum para pemula:
nums.filter(isEven); // correct: passes the function
nums.filter(isEven()); // wrong: calls isEven with no args, passes the result
Kalau callback-nya mulai melebar lebih dari beberapa baris, pisahkan dan beri nama. Kode di sekitarnya biasanya jadi lebih enak dibaca.
Contoh Lengkap
Higher-order function bersinar saat kamu menyusun potongan-potongan kecil. Misalkan kamu punya daftar produk dan ingin nama barang yang terjangkau dan tersedia, dalam huruf kapital:
Setiap helper punya satu tugas. Setiap method array melakukan satu transformasi. Pipeline-nya terbaca seperti spesifikasi tentang apa yang kamu mau, bukan penjelasan tentang cara melakukan perulangan.
Kapan Tidak Memakainya
Method higher-order memang hebat, tetapi bukan pengganti loop untuk setiap situasi:
- Kalau kamu perlu berhenti di tengah jalan,
forataufor...ofdenganbreaklebih jelas daripada mencoba keluar dariforEach. - Kalau kamu melakukan sesuatu yang async di dalam callback,
mapdanforEachtidak akan menunggunya. Pakaifor...ofdenganawait, atauPromise.alldenganmap. - Kalau callback-nya mengubah state bersama, kamu mulai menjauh dari keunggulan gaya ini. Pakai loop biasa atau refactor agar mengembalikan nilai baru.
Kalau dipakai di tempat yang tepat, map, filter, dan reduce memangkas sebagian besar boilerplate loop dari kode sehari-hari. Kalau dipakai di mana-mana, keterbacaan justru menurun. Pilih alat yang membuat maksudmu paling jelas.
Berikutnya: Objek
Fungsi bukan satu-satunya nilai yang layak dijadikan fondasi. Objek adalah andalan JavaScript untuk mengelompokkan data dan perilaku yang saling berkaitan, dan objek jugalah yang mengisi sebagian besar array yang baru saja kamu filter dan map. Itu topik halaman berikutnya.
Pertanyaan yang sering diajukan
Apa itu higher-order function di JavaScript?
Higher-order function adalah fungsi yang melakukan setidaknya satu dari dua hal: menerima fungsi lain sebagai argumen, atau mengembalikan fungsi sebagai hasilnya. Array.prototype.map, setTimeout, dan addEventListener semuanya higher-order: ketiganya menerima callback dan menjalankannya untukmu.
Apa bedanya map, filter, dan reduce?
map mengubah setiap item dan mengembalikan array baru dengan panjang yang sama. filter menyimpan item yang membuat callback mengembalikan nilai truthy dan mengembalikan array (yang mungkin lebih pendek). reduce meringkas array menjadi satu nilai dengan menggabungkan item satu per satu. Ketiganya adalah higher-order function yang menerima callback.
Mengapa kita mengembalikan fungsi dari fungsi lain?
Untuk membangun helper kecil yang bisa dikonfigurasi tanpa mengulang logika. Fungsi seperti multiplyBy(n) mengembalikan fungsi baru yang mengalikan dengan n, jadi multiplyBy(2) dan multiplyBy(10) memberimu dua fungsi khusus dari satu definisi. Pola ini memakai closure dan umum ditemukan di event handler, middleware, dan library utilitas.