Array adalah struktur untuk daftar berurutan: baris hasil query database, daftar berkas di sebuah folder, kumpulan item pesanan. Hampir setiap program Node.js yang kita tulis akan memutar data berbentuk array, dan cara memutarnya menentukan apakah kode terbaca sebagai rangkaian langkah yang jelas atau sebagai tumpukan loop yang saling bertumpuk. Sejak ES 5, JavaScript membawa higher-order function bawaan untuk array — method yang menerima callback dan mengembalikan array baru — sehingga transformasi data bisa dinyatakan sebagai aliran: saring, petakan, lipat. Pada chapter ini kita akan menguasai map, filter, reduce, find, some, every, sort dengan comparator, sampai flatMap.
map, filter, dan reduce #
Tiga method ini adalah trio yang paling sering dipakai. map memanggil callback untuk setiap elemen lalu mengembalikan array hasil transformasi dengan panjang yang sama. filter mempertahankan elemen yang callback-nya mengembalikan nilai truthy. reduce melipat seluruh array menjadi satu nilai dengan cara mengoperasikan akumulator dari elemen pertama sampai terakhir. Berkas map-filter-reduce.mjs menerapkan ketiganya pada data produk:
const produk = [
{ nama: "Kopi Arabika", harga: 85000, stok: 12 },
{ nama: "Teh Hijau", harga: 45000, stok: 30 },
{ nama: "Susu UHT", harga: 18000, stok: 8 },
{ nama: "Gula Aren", harga: 32000, stok: 0 },
];
// map: ubah setiap elemen menjadi bentuk baru
const namaProduk = produk.map((p) => p.nama);
// filter: pilih elemen yang lolos syarat
const tersedia = produk.filter((p) => p.stok > 0);
// reduce: lipat seluruh array menjadi satu nilai
const nilaiStok = produk.reduce((total, p) => total + p.harga * p.stok, 0);
console.log(`nama : ${namaProduk.join(", ")}`);
console.log(`tersedia : ${tersedia.map((p) => p.nama).join(", ")}`);
console.log(`nilai stok : Rp${nilaiStok}`);Output yang Dihasilkan:
nama : Kopi Arabika, Teh Hijau, Susu UHT, Gula Aren
tersedia : Kopi Arabika, Teh Hijau, Susu UHT
nilai stok : Rp2514000Mari kita bedah tiga baris intinya:
produk.map((p) => p.nama): callback menerima satu object produk dan hanya mengembalikan string namanya. Array empat object berubah menjadi array empat string, urutannya terjaga.produk.filter((p) => p.stok > 0): hanyaGula Arenyang tersaring karena stoknya0. Callback yang mengembalikanfalsemembuat elemen dibuang dari hasil.produk.reduce((total, p) => total + p.harga * p.stok, 0): angka0adalah nilai awal akumulator. Pada tiap langkah,totalberisi hasil penjumlahan sebelumnya; setelah elemen terakhir,reducemengembalikan akumulator akhir2514000.
Ketiganya sering dirangkai menjadi chaining — keluaran satu method menjadi masukan method berikutnya:
const siapJual = produk
.filter((p) => p.stok > 0)
.map((p) => `${p.nama} (stok ${p.stok})`);Rantai di atas terbaca seperti kalimat: saring produk yang stoknya tersisa, lalu petakan setiap produk menjadi label. Tidak ada variable sementara, tidak ada loop manual, dan maksud setiap langkah terlihat dari nama method-nya.
find, some, dan every #
Ketiga method ini menjawab pertanyaan tentang isi array, bukan mengubahnya. find mengembalikan elemen pertama yang memenuhi syarat (atau undefined bila tidak ada), findIndex mengembalikan posisinya, some menguji “apakah minimal satu elemen lolos”, dan every menguji “apakah seluruh elemen lolos”. Berkas pencarian.mjs mempraktikkan keempatnya:
const nilaiUjian = [78, 85, 92, 60, 74];
// find: elemen pertama yang memenuhi syarat
const lulusPertama = nilaiUjian.find((n) => n >= 80);
// findIndex: posisi elemen pertama yang memenuhi syarat
const posisi92 = nilaiUjian.findIndex((n) => n === 92);
// some: true bila minimal satu elemen lolos syarat
const adaYangTinggi = nilaiUjian.some((n) => n >= 90);
// every: true bila seluruh elemen lolos syarat
const semuaLulus = nilaiUjian.every((n) => n >= 70);
console.log(`lulus pertama : ${lulusPertama}`);
console.log(`posisi nilai 92 : ${posisi92}`);
console.log(`ada nilai >= 90 : ${adaYangTinggi}`);
console.log(`semua nilai >= 70 : ${semuaLulus}`);Output yang Dihasilkan:
lulus pertama : 85
posisi nilai 92 : 2
ada nilai >= 90 : true
semua nilai >= 70 : falseNilai 78 tidak lolos syarat n >= 80, tetapi 85 lolos — find langsung berhenti di 85 dan tidak pernah menengok 92. Hasil every bernilai false karena 60 dan 74 ada di bawah ambang 70; satu elemen gagal saja cukup membuat every mengembalikan false. Perbedaan penting dibanding filter: find menghentikan pencarian begitu jawaban ditemukan, sehingga untuk sekadar “cari satu”, find lebih murah daripada filter(...)[0].
Pengurutan yang Aman dengan Comparator #
Method sort() punya dua sifat yang wajib kita pahami sebelum dipakai. Pertama, sort() mengurutkan in place — array asli yang berubah, bukan salinan baru. Kedua, tanpa argument, sort() mengonversi setiap elemen ke string lalu mengurutkannya sebagai teks, sehingga urutan angka jadi mengejutkan. Berkas urutkan.mjs memperlihatkan kedua hal itu sekaligus solusinya:
const versi = [10, 9, 100, 1];
// Tanpa comparator: elemen dikonversi ke string lalu diurutkan sebagai teks
const salah = [...versi].sort();
// Dengan comparator angka: hasil negatif berarti a maju sebelum b
const benar = [...versi].sort((a, b) => a - b);
const produk = [
{ nama: "Teh Hijau", harga: 45000 },
{ nama: "Kopi Arabika", harga: 85000 },
{ nama: "Susu UHT", harga: 18000 },
];
// Comparator berbasis property tertentu
const termurahDulu = [...produk].sort((a, b) => a.harga - b.harga);
console.log(`sort() bawaan : ${salah.join(", ")}`);
console.log(`angka naik : ${benar.join(", ")}`);
console.log(`termurah dulu : ${termurahDulu.map((p) => p.nama).join(", ")}`);Output yang Dihasilkan:
sort() bawaan : 1, 10, 100, 9
angka naik : 1, 9, 10, 100
termurah dulu : Susu UHT, Teh Hijau, Kopi ArabikaMari kita baca hasilnya:
sort()bawaan menghasilkan1, 10, 100, 9: string"10"dan"100"memang mendahului"9"dalam urutan kamus, sama seperti halaman"10"muncul sebelum"9"di daftar isi. Untuk angka, hasil ini hampir selalu salah.- Comparator
(a, b) => a - bmengembalikan angka: negatif bilaaharus berdiri sebelumb, positif bila sesudah, nol bila dianggap setara. Ekspresia - bmenghasilkan urutan menaik; balik menjadib - auntuk urutan menurun. [...versi]di awal: spread menyalin array sebelumsort()dijalankan, karenasort()memindahkan elemen di array aslinya. Tanpa salinan,versiikut terurut dan data mentah kita berubah diam-diam.
flatMap untuk Struktur Bertingkat #
Method flatMap adalah gabungan map lalu flatten satu level: setiap elemen dipetakan menjadi array (atau nilai biasa), lalu hasil yang bertingkat diratakan. Kasus klasiknya: setiap pengguna memiliki banyak item, dan kita ingin satu array berisi seluruh item dari seluruh pengguna:
const pesanan = [
{ nama: "Budi", item: ["kopi", "teh"] },
{ nama: "Siti", item: ["susu"] },
];
const denganMap = pesanan.map((p) => p.item);
const denganFlatMap = pesanan.flatMap((p) => p.item);
console.log(`map : ${JSON.stringify(denganMap)}`);
console.log(`flatMap : ${JSON.stringify(denganFlatMap)}`);Output yang Dihasilkan:
map : [["kopi","teh"],["susu"]]
flatMap : ["kopi","teh","susu"]map menghasilkan array bertingkat [["kopi","teh"],["susu"]] karena callback-nya mengembalikan array per pengguna. flatMap meratakan hasil itu satu level menjadi ["kopi","teh","susu"] — tepat untuk kasus “kumpulkan semua sub-item”. Perhatikan bahwa perataan hanya satu level; struktur yang lebih dalam tetap perlu diratakan bertahap atau dengan flat(2).
Referensi lanjutan untuk topik chapter ini:
- Array.prototype.map — MDN
- Array.prototype.reduce — MDN
- Array.prototype.sort — MDN
- Array.prototype.flatMap — MDN
Dengan map, filter, dan kawan-kawannya, kita bisa mengolah kumpulan data object secara deklaratif. Berikutnya kita naik satu tingkat: membungkus data beserta perilakunya menjadi satu unit yang bisa diwariskan — class. Chapter Class dan Prototype menunggu kita.