DataLens

Method array (map, filter, reduce, forEach)

Ubah data secara deklaratif dengan map, filter, reduce, find, some, every, dan sort, rangkai menjadi pipeline yang mudah dibaca, dan hindari jebakan klasik sort dan mutasi.

Level: Menengah · 10 menit baca

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.

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

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:

  1. Tanpa compare function, sort membandingkan item sebagai string, jadi 100 muncul sebelum 25. Untuk angka, selalu berikan (a, b) => a - b (naik) atau b - a (turun).
  2. sort mengubah 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.

Ide utama

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

Latihan modul ini

Soal-soal untuk pelajaran ini berjalan di browser-mu dan langsung mengecek jawabanmu.