Kenapa ini penting
Data nyata sering berbentuk bersarang dan berantakan. Respons API bisa berisi daftar pesanan yang masing-masing punya daftar item. Data tag artikel bisa berisi duplikat. Laporan penjualan perlu dikelompokkan per kategori atau per bulan. Kalau hanya mengandalkan map, filter, dan reduce, kodenya bisa jadi panjang dan sulit dibaca.
Modul ini menambah perkakas yang membuat pekerjaan semacam itu jauh lebih ringkas: flat dan flatMap untuk meratakan array bersarang, Object.groupBy untuk mengelompokkan data, chaining (merangkai method) untuk membangun "pipa" pengolahan data, Set untuk membuang duplikat, dan destructuring untuk membongkar isi array ke variabel dengan rapi. Teknik-teknik ini sering muncul di kode profesional dan wawancara kerja.
Konsep inti
flat: meratakan array bersarang
arr.flat(kedalaman) membuat array baru dengan sub-array "dibongkar" sampai kedalaman tertentu. Bawaannya kedalaman 1. Pakai flat(Infinity) untuk meratakan sampai habis. Analogi: kamu punya kardus berisi kotak-kotak kecil berisi barang; flat mengeluarkan barang dari kotak kecil dan menjajarkannya langsung di dalam kardus.
flatMap: map lalu flat satu level
arr.flatMap(fn) sama dengan arr.map(fn).flat(1), tapi lebih efisien. Callback boleh mengembalikan array (akan diratakan) atau nilai tunggal. Trik berguna: mengembalikan [] artinya "buang elemen ini", sehingga flatMap bisa sekaligus menyaring dan mengubah.
Object.groupBy: mengelompokkan data
Object.groupBy(daftar, fn) mengelompokkan elemen berdasarkan kunci yang dikembalikan callback. Hasilnya object dengan setiap kunci berisi array elemen. Ada juga Map.groupBy yang hasilnya Map (berguna kalau kuncinya bukan string, misalnya object atau angka yang ingin dipertahankan tipenya).
Beberapa hal penting yang perlu kamu tahu:
Object.groupByadalah method statis diObject, bukan method array. TulisObject.groupBy(arr, fn), bukanarr.groupBy(fn).- Object hasilnya punya prototype null. Itu sebabnya Node.js menampilkannya sebagai
[Object: null prototype]. Akibatnya, method sepertihasil.hasOwnPropertytidak ada; pakaiObject.hasOwn(hasil, kunci)ataukunci in hasil. - Fitur ini masuk standar ES2024. Didukung Node.js 21 ke atas dan browser modern (Chrome 117+, Firefox 119+, Safari 17.4+). Untuk lingkungan lama, gunakan
reducesebagai cadangan. Kamu bisa mengecek ketersediaannya dengantypeof Object.groupBy === "function".
Chaining: merangkai method
Karena map, filter, flatMap, dan toSorted mengembalikan array baru, kamu bisa menyambungnya seperti pipa: data masuk di satu ujung, diolah bertahap, hasil keluar di ujung lain. Tulis satu method per baris supaya mudah dibaca dan mudah dikomentari. Urutan penting untuk efisiensi: lakukan filter sedini mungkin supaya langkah berikutnya memproses lebih sedikit data.
Dedupe dengan Set
Set adalah koleksi yang hanya menyimpan nilai unik (dibahas lengkap di modul 14). Trik paling populer: [...new Set(arr)] membuang duplikat dari array nilai primitif. Untuk array berisi object, keunikan dihitung berdasarkan referensi, jadi kamu perlu memilih kunci unik (misalnya id) lalu memakai Map atau filter dengan pelacakan.
Destructuring array
Destructuring membongkar elemen array ke variabel berdasarkan posisi:
const [a, b] = [1, 2]mengambil elemen pertama dan kedua.const [, kedua] = arrmelewati elemen pertama dengan koma kosong.const [pertama, ...sisa] = arrmengumpulkan sisanya dengan rest.const [x = 10] = []memberi nilai default kalau elemennyaundefined.[a, b] = [b, a]menukar nilai dua variabel tanpa variabel sementara.
Destructuring juga bisa dipakai langsung di parameter function dan di for...of atas Object.entries, seperti yang sudah kamu lihat di modul-modul sebelumnya.
Contoh kode
// 1) flat
const bersarang = [1, [2, 3], [4, [5, [6]]]];
console.log(bersarang.flat()); // → [ 1, 2, 3, 4, [ 5, [ 6 ] ] ]
console.log(bersarang.flat(2)); // → [ 1, 2, 3, 4, 5, [ 6 ] ]
console.log(bersarang.flat(Infinity)); // → [ 1, 2, 3, 4, 5, 6 ]
// 2) flatMap: setiap pesanan punya banyak item
const pesanan = [
{ id: "P1", items: ["kopi", "roti"] },
{ id: "P2", items: ["teh"] },
{ id: "P3", items: ["kopi", "donat", "teh"] },
];
console.log(pesanan.map((p) => p.items)); // → [ [ 'kopi', 'roti' ], [ 'teh' ], [ 'kopi', 'donat', 'teh' ] ]
console.log(pesanan.flatMap((p) => p.items)); // → [ 'kopi', 'roti', 'teh', 'kopi', 'donat', 'teh' ]
// flatMap untuk menyaring + mengubah sekaligus: kembalikan [] untuk membuang
const input = ["12", "abc", "7", ""];
const angkaValid = input.flatMap((s) => {
const n = Number(s);
return s !== "" && !Number.isNaN(n) ? [n] : [];
});
console.log(angkaValid); // → [ 12, 7 ]
// 3) Object.groupBy (ES2024)
console.log(typeof Object.groupBy); // → function
const penjualan = [
{ produk: "Kaos", kategori: "pakaian", total: 150000 },
{ produk: "Topi", kategori: "aksesoris", total: 90000 },
{ produk: "Jaket", kategori: "pakaian", total: 320000 },
{ produk: "Gelang", kategori: "aksesoris", total: 40000 },
];
const perKategori = Object.groupBy(penjualan, (p) => p.kategori);
console.log(Object.keys(perKategori)); // → [ 'pakaian', 'aksesoris' ]
console.log(perKategori.pakaian.map((p) => p.produk)); // → [ 'Kaos', 'Jaket' ]
console.log(Object.getPrototypeOf(perKategori)); // → null
console.log(Object.hasOwn(perKategori, "pakaian")); // → true
// Kelompok berdasarkan kondisi
const perUkuran = Object.groupBy(penjualan, (p) => (p.total >= 100000 ? "besar" : "kecil"));
console.log(perUkuran.besar.length, perUkuran.kecil.length); // → 2 2
// Cadangan untuk lingkungan lama: reduce
const perKategoriLama = penjualan.reduce((grup, p) => {
(grup[p.kategori] ??= []).push(p);
return grup;
}, {});
console.log(perKategoriLama.aksesoris.length); // → 2
// Map.groupBy: kunci tetap bertipe aslinya
const perTotalGenap = Map.groupBy([1, 2, 3, 4, 5], (n) => n % 2 === 0);
console.log(perTotalGenap.get(true), perTotalGenap.get(false)); // → [ 2, 4 ] [ 1, 3, 5 ]
// 4) Chaining: total per kategori, diurutkan dari yang terbesar
const ringkasan = Object.entries(Object.groupBy(penjualan, (p) => p.kategori))
.map(([kategori, daftar]) => ({
kategori,
total: daftar.reduce((jumlah, p) => jumlah + p.total, 0),
}))
.toSorted((a, b) => b.total - a.total);
console.log(ringkasan);
// → [ { kategori: 'pakaian', total: 470000 }, { kategori: 'aksesoris', total: 130000 } ]
// 5) Dedupe dengan Set
const semuaItem = pesanan.flatMap((p) => p.items);
const itemUnik = [...new Set(semuaItem)];
console.log(itemUnik); // → [ 'kopi', 'roti', 'teh', 'donat' ]
// Dedupe object berdasarkan kunci id (yang terakhir menang)
const pengguna = [
{ id: 1, nama: "Ana" },
{ id: 2, nama: "Bob" },
{ id: 1, nama: "Ana (update)" },
];
const unikById = [...new Map(pengguna.map((u) => [u.id, u])).values()];
console.log(unikById); // → [ { id: 1, nama: 'Ana (update)' }, { id: 2, nama: 'Bob' } ]
// 6) Destructuring array
const skor = [95, 88, 76, 64];
const [juara1, juara2, ...lainnya] = skor;
console.log(juara1, juara2, lainnya); // → 95 88 [ 76, 64 ]
const [, , ketiga] = skor;
console.log(ketiga); // → 76
const [warna = "hitam", ukuran = "M"] = ["putih"];
console.log(warna, ukuran); // → putih M
let kiri = "A";
let kanan = "B";
[kiri, kanan] = [kanan, kiri];
console.log(kiri, kanan); // → B A
// Destructuring di parameter function
const luasPersegiPanjang = ([panjang, lebar]) => panjang * lebar;
console.log(luasPersegiPanjang([8, 5])); // → 40
Kesalahan umum
- Menulis
arr.groupBy(...). Method itu tidak ada di array. Yang benarObject.groupBy(arr, fn)atauMap.groupBy(arr, fn). - Memakai
hasil.hasOwnProperty(...)pada hasilObject.groupBy. Object-nya tanpa prototype, jadi method itu tidak ada dan memanggilnya melemparTypeError. PakaiObject.hasOwn. - Mengira
flat()meratakan sampai habis. Bawaannya hanya satu level. Tentukan kedalaman atau pakaiInfinity. - Dedupe array object dengan
new Set. Dua object berisi sama tetap dianggap berbeda karena referensinya berbeda. Dedupe berdasarkan kunci unik denganMap. - Rantai method yang terlalu panjang di satu baris. Sulit dibaca dan sulit di-debug. Pisahkan satu method per baris, dan simpan hasil antara ke variabel bernama jelas kalau rantainya mulai rumit.
Latihan
- Mudah, Diberikan
const kelas = [["Ani", "Budi"], ["Caca"], ["Dodi", "Eka", "Ani"]]. Buat daftar nama unik dan urutkan secara alfabet. - Sedang, Diberikan array kalimat
["belajar javascript", "javascript itu seru"]. PakaiflatMapuntuk menghasilkan daftar semua kata, lalu hitung jumlah kata unik. - Menantang, Diberikan transaksi
{ tanggal: "2026-10-01", jumlah }dari beberapa bulan. Kelompokkan per bulan (format"2026-10") denganObject.groupBy, lalu hasilkan array{ bulan, total, jumlahTransaksi }yang diurutkan per bulan.
Lihat solusi
// 1) Mudah
const kelas = [["Ani", "Budi"], ["Caca"], ["Dodi", "Eka", "Ani"]];
const namaUnik = [...new Set(kelas.flat())].toSorted((a, b) => a.localeCompare(b, "id"));
console.log(namaUnik); // → [ 'Ani', 'Budi', 'Caca', 'Dodi', 'Eka' ]
// 2) Sedang
const kalimat = ["belajar javascript", "javascript itu seru"];
const kata = kalimat.flatMap((k) => k.split(" "));
console.log(kata); // → [ 'belajar', 'javascript', 'javascript', 'itu', 'seru' ]
console.log(new Set(kata).size); // → 4
// 3) Menantang
const transaksi = [
{ tanggal: "2026-09-12", jumlah: 200000 },
{ tanggal: "2026-10-01", jumlah: 150000 },
{ tanggal: "2026-09-30", jumlah: 50000 },
{ tanggal: "2026-10-15", jumlah: 300000 },
{ tanggal: "2026-08-05", jumlah: 75000 },
];
const perBulan = Object.entries(Object.groupBy(transaksi, (t) => t.tanggal.slice(0, 7)))
.map(([bulan, daftar]) => ({
bulan,
total: daftar.reduce((s, t) => s + t.jumlah, 0),
jumlahTransaksi: daftar.length,
}))
.toSorted((a, b) => a.bulan.localeCompare(b.bulan));
console.log(perBulan);
// → [
// → { bulan: '2026-08', total: 75000, jumlahTransaksi: 1 },
// → { bulan: '2026-09', total: 250000, jumlahTransaksi: 2 },
// → { bulan: '2026-10', total: 450000, jumlahTransaksi: 2 }
// → ]
Ringkasan
flat(n)meratakan array bersarang sampai kedalamann;flatMapadalahmaplaluflat(1)dan bisa sekaligus menyaring.Object.groupBy(arr, fn)(ES2024, Node 21+) mengelompokkan data menjadi object berprototype null;Map.groupBymenghasilkanMap.- Chaining method membentuk pipa pengolahan data yang mudah dibaca; lakukan
filtersedini mungkin. [...new Set(arr)]membuang duplikat nilai primitif; untuk object, dedupe berdasarkan kunci memakaiMap.- Destructuring array membongkar elemen berdasarkan posisi, mendukung lompatan, rest, nilai default, dan tukar nilai.