Idenya
Loop bisa melakukan apa saja, tetapi loop memaksamu membaca setiap baris untuk mengetahui apa yang dilakukannya. Method array menamai maksudnya: filter mempertahankan sebagian item, map mengubah setiap item, reduce menggabungkannya menjadi satu nilai. Rangkaian seperti products.filter(inStock).map(toCard) terbaca seperti kalimat. Inilah gaya sehari-hari JavaScript modern, dan idenya sama dengan operasi pandas pada kolom.
Semua contoh memakai data ini:
const products = [
{ name: "Arabica Gayo", category: "coffee", price: 95000, stock: 12 },
{ name: "Toraja Kalosi", category: "coffee", price: 110000, stock: 0 },
{ name: "French Press", category: "equipment", price: 245000, stock: 4 },
{ name: "Paper filters", category: "equipment", price: 35000, stock: 40 },
];
console.log(products.length);
4
Setiap blok di bawah mengulang datanya supaya bisa berjalan sendiri.
map: ubah setiap item
Halaman produk butuh daftar yang hanya berisi nama-nama produk, dan daftar harga butuh setiap harga yang sudah ditambah PPN. Keduanya berarti "lakukan hal yang sama pada setiap item lalu simpan hasilnya". Itulah map:
const products = [
{ name: "Arabica Gayo", category: "coffee", price: 95000, stock: 12 },
{ name: "Toraja Kalosi", category: "coffee", price: 110000, stock: 0 },
{ name: "French Press", category: "equipment", price: 245000, stock: 4 },
{ name: "Paper filters", category: "equipment", price: 35000, stock: 40 },
];
const names = products.map((p) => p.name);
const withVat = products.map((p) => ({ ...p, price: Math.round(p.price * 1.11) }));
console.log(names);
console.log(withVat[0].price, products[0].price);
["Arabica Gayo", "Toraja Kalosi", "French Press", "Paper filters"]
105450 95000
map mengembalikan array baru dengan panjang yang sama, dengan setiap item diganti oleh apa yang dikembalikan callback. Array aslinya tidak berubah. (Untuk mengembalikan objek dari arrow function, bungkus dengan tanda kurung: ({ ... }), kalau tidak kurung kurawalnya dibaca sebagai isi function.)
filter, find, some, every
Kelompok pertanyaan berikutnya memilih item, bukan mengubahnya. Produk mana yang masih ada stoknya? Apa produk pertama yang harganya di atas Rp 100.000? Apakah ada yang habis? Apakah semua harganya positif? Setiap pertanyaan punya method-nya sendiri:
const products = [
{ name: "Arabica Gayo", category: "coffee", price: 95000, stock: 12 },
{ name: "Toraja Kalosi", category: "coffee", price: 110000, stock: 0 },
{ name: "French Press", category: "equipment", price: 245000, stock: 4 },
{ name: "Paper filters", category: "equipment", price: 35000, stock: 40 },
];
console.log(products.filter((p) => p.stock > 0).length);
console.log(products.find((p) => p.price > 100000).name);
console.log(products.find((p) => p.price > 1000000));
console.log(products.some((p) => p.stock === 0), products.every((p) => p.price > 0));
3
Toraja Kalosi
undefined
true true
filter(test)→ array baru berisi item yang test-nya mengembalikan true (bisa kosong).find(test)→ item pertama yang cocok, atauundefined. (findIndexmemberikan posisinya.)some(test)→ true kalau setidaknya satu cocok;every(test)→ true kalau semuanya cocok.
reduce: gabungkan menjadi satu nilai
Ada pertanyaan yang meringkas seluruh daftar menjadi satu jawaban: total nilai semua stok, atau berapa banyak produk di setiap kategori. reduce menyusuri array dan membangun jawaban itu satu item demi satu item:
const products = [
{ name: "Arabica Gayo", category: "coffee", price: 95000, stock: 12 },
{ name: "Toraja Kalosi", category: "coffee", price: 110000, stock: 0 },
{ name: "French Press", category: "equipment", price: 245000, stock: 4 },
{ name: "Paper filters", category: "equipment", price: 35000, stock: 40 },
];
const stockValue = products.reduce((sum, p) => sum + p.price * p.stock, 0);
console.log(stockValue);
const countByCategory = products.reduce((counts, p) => {
counts[p.category] = (counts[p.category] ?? 0) + 1;
return counts;
}, {});
console.log(countByCategory);
3520000
{ coffee: 2, equipment: 2 }
reduce(callback, start) menelusuri array sambil membawa sebuah akumulator: callback menerima akumulator sejauh ini dan item saat ini, lalu mengembalikan akumulator yang baru. Selalu berikan nilai awalnya (0, {}, []). reduce itu ampuh tetapi paling sulit dibaca di antara method-method ini; untuk penjumlahan sederhana tidak masalah, untuk apa pun yang kompleks loop for...of sering lebih jelas.
sort (dengan hati-hati)
Mengurutkan terlihat sederhana, dan justru itulah yang membuatnya berbahaya di JavaScript. Baris pertama di bawah mengurutkan empat angka tanpa instruksi tambahan apa pun. Perhatikan baik-baik hasilnya sebelum lanjut membaca:
console.log([10, 9, 100, 25].sort());
console.log([10, 9, 100, 25].sort((a, b) => a - b));
const products = [
{ name: "Arabica Gayo", price: 95000 },
{ name: "French Press", price: 245000 },
{ name: "Paper filters", price: 35000 },
];
const cheapestFirst = products.toSorted((a, b) => a.price - b.price);
console.log(cheapestFirst.map((p) => p.name));
console.log(products[0].name);
console.log(["Toraja", "arabica", "Gayo"].toSorted((a, b) => a.localeCompare(b)));
[10, 100, 25, 9]
[9, 10, 25, 100]
["Paper filters", "Arabica Gayo", "French Press"]
Arabica Gayo
["arabica", "Gayo", "Toraja"]
Dua jebakan:
- Tanpa compare function,
sortmembandingkan item sebagai string, jadi100muncul sebelum25. Untuk angka, selalu berikan(a, b) => a - b(naik) ataub - a(turun). sortmengubah array aslinya.toSorted(lebih baru) mengembalikan salinan yang terurut dan membiarkan aslinya. Gunakan itu, atau salin dulu:[...arr].sort(...).
Untuk teks, a.localeCompare(b) mengurutkan secara alfabetis, mengabaikan huruf besar-kecil seperti yang diharapkan orang.
Merangkai menjadi pipeline
Halaman sungguhan menggabungkan langkah-langkah ini. Daftar "produk tersedia" di toko hanya boleh menampilkan barang yang ada stoknya, yang termahal di atas, masing-masing sebagai label yang diformat rapi. Karena setiap langkah mengembalikan array baru, kamu bisa merangkainya satu demi satu:
const products = [
{ name: "Arabica Gayo", category: "coffee", price: 95000, stock: 12 },
{ name: "Toraja Kalosi", category: "coffee", price: 110000, stock: 0 },
{ name: "French Press", category: "equipment", price: 245000, stock: 4 },
{ name: "Paper filters", category: "equipment", price: 35000, stock: 40 },
];
const labels = products
.filter((p) => p.stock > 0)
.toSorted((a, b) => b.price - a.price)
.map((p) => `${p.name} (Rp ${p.price.toLocaleString("id-ID")})`);
console.log(labels);
products.forEach((p, i) => console.log(i, p.name));
["French Press (Rp 245.000)", "Arabica Gayo (Rp 95.000)", "Paper filters (Rp 35.000)"]
0 Arabica Gayo
1 Toraja Kalosi
2 French Press
3 Paper filters
Setiap langkah mengembalikan array baru, jadi bisa dirangkai. Satu langkah per baris menjaga pipeline-nya mudah dibaca.
forEach menjalankan function untuk setiap item dan tidak mengembalikan apa-apa. Itu untuk efek samping (logging, memperbarui halaman). Kalau kamu sedang membangun array baru, gunakan map atau filter alih-alih forEach + push.
map mengubah, filter mempertahankan, find mengambil satu, some/every mengetes, reduce menggabungkan, toSorted mengurutkan (dengan compare function!). Semuanya mengembalikan array baru dan bisa dirangkai menjadi pipeline; forEach hanya untuk efek samping.
Mengapa ini penting untuk kode yang bersih
Method array membuat kode deklaratif: menyatakan apa yang kamu inginkan alih-alih bagaimana caranya melakukan loop. Method-method ini juga menghindari mutasi secara default, yang menghilangkan seluruh keluarga bug di mana sebuah function diam-diam mengubah data yang masih dipakai pemanggilnya. Beri nama pada callback-mu saat ia membawa aturan bisnis (const isAvailable = (p) => p.stock > 0), dan pipeline-nya menjadi spesifikasi yang mudah dibaca.
Rangkuman
map(fn)→ panjang sama, sudah diubah;filter(fn)→ sebagian;find(fn)→ item pertama atauundefined.some/every→ boolean;reduce((acc, x) => ..., start)→ satu nilai.sortmembandingkan string secara default dan memutasi; gunakantoSorted((a, b) => a - b)ataulocaleCompare.- Rangkai:
.filter(...).toSorted(...).map(...). forEachhanya untuk efek samping.