Kodeloka
  1. Kodeloka
  2. Kelas JavaScript
  3. Materi

2 · Objek & Data · Modul 4 dari 22

Objek dan Array Modern: Destructuring, Immutability (ES2023+), dan Object.groupBy

Mengolah struktur data objek dan array secara bersih menggunakan destructuring, operator spread, penyalinan mendalam structuredClone(), transformasi deklaratif (map, filter, reduce), metode array tak-mutasi ES2023 (toSorted, toSpliced, with), serta pengelompokan Object.groupBy().

1. Destructuring dan Spread Operator (...)

Dalam aplikasi modern, kita hampir setiap saat mengekstrak data dari respons JSON API atau merangkai objek konfigurasi baru tanpa merusak data aslinya.

A. Object & Array Destructuring

Destructuring memungkinkan Anda membongkar properti objek atau elemen array langsung ke dalam variabel bernama, lengkap dengan **nilai bawaan (default value) dan penggantian nama (aliasing)**:

const responsKelas = {
  id: 101,
  judul: "Dasar JavaScript Modern",
  penulis: { nama: "Tim Kodeloka" }
};

// Mengambil 'judul', mengganti nama 'id' menjadi 'idKelas',
// memberikan nilai bawaan 'tingkat = "Dasar"', dan membongkar objek bersarang 'penulis.nama'
const {
  id: idKelas,
  judul,
  tingkat = "Dasar",
  penulis: { nama: namaPenulis }
} = responsKelas;

console.log(idKelas, judul, tingkat, namaPenulis);
// 101 "Dasar JavaScript Modern" "Dasar" "Tim Kodeloka"

B. Menyalin Objek: Shallow Copy (...) vs Deep Copy (structuredClone)

Operator spread ({ ...objekLama } atau [ ...arrayLama ]) membuat **salinan dangkal (shallow copy)**: ia menyalin properti tingkat pertama, tetapi objek yang bersarang di dalamnya masih menunjuk ke referensi memori yang sama!

Untuk membuat **salinan mendalam (deep clone) dari objek atau array bersarang secara aman tanpa pustaka eksternal, gunakan fungsi standar web structuredClone() (status Baseline Widely Available** sejak 2022):

const negaraAsli = {
  nama: "Indonesia",
  ibuKota: { kota: "Jakarta", pulau: "Jawa" }
};

// Salinan mendalam dengan structuredClone()
const salinanMandiri = structuredClone(negaraAsli);
salinanMandiri.ibuKota.kota = "Nusantara";

console.log(negaraAsli.ibuKota.kota);     // Tetap "Jakarta" (Tidak ikut berubah!)
console.log(salinanMandiri.ibuKota.kota); // "Nusantara"

2. Transformasi Array Deklaratif: map, filter, reduce, find, some, every

Daripada menulis perulangan for panjang yang mencampuradukkan logika penyaringan, perubahan bentuk, dan penjumlahan di satu tempat, gunakan metode array deklaratif yang tidak mengubah array aslinya:

const daftarModul = [
  { id: 1, judul: "Tipe Data", durasiMenit: 15, selesai: true },
  { id: 2, judul: "Closure",   durasiMenit: 25, selesai: true },
  { id: 3, judul: "Fetch API", durasiMenit: 20, selesai: false }
];

// 1. filter(): Menyaring elemen yang memenuhi syarat -> menghasilkan Array baru
const modulSelesai = daftarModul.filter((m) => m.selesai);

// 2. map(): Mengubah setiap elemen dengan rumus 1-ke-1 -> menghasilkan Array baru dengan panjang sama
const daftarJudul = daftarModul.map((m) => m.judul);

// 3. reduce(): Merangkum seluruh elemen menjadi satu nilai akhir (selalu berikan nilai awal di argumen ke-2!)
const totalMenit = daftarModul.reduce((akumulator, m) => akumulator + m.durasiMenit, 0);

// 4. find(): Mencari SATU elemen pertama yang cocok (atau undefined jika tidak ditemukan)
const modulBelumSelesai = daftarModul.find((m) => !m.selesai);

// 5. every() dan some(): Menghasilkan boolean (Apakah SEMUA selesai? Apakah ADA minimal satu yang selesai?)
const semuaLulus = daftarModul.every((m) => m.selesai); // false
const adaProgres = daftarModul.some((m) => m.selesai);  // true
⚠️ Kesalahan Umum pada .reduce()

Jangan pernah lupa menyertakan **nilai awal (initial value) sebagai argumen kedua (misalnya angka 0 pada .reduce((acc, item) => ..., 0)). Jika Anda memanggil .reduce() tanpa nilai awal pada sebuah array yang kebetulan kosong [], JavaScript akan langsung melempar TypeError: Reduce of empty array with no initial value**!

3. Metode Array Tak-Mutasi (Copying Array Methods — Sejak ES2023)

Selama puluhan tahun, empat metode array klasik di JavaScript memiliki efek samping berbahaya karena **mengubah (mutate) array aslinya secara langsung di tempat**:

  • array.sort() mengubah urutan array asli!
  • array.reverse() membalik array asli!
  • array.splice() memotong isi array asli!
  • array[i] = nilaiBaru mengubah elemen di array asli!

Sejak ECMAScript 2023 (status Baseline Widely Available), hadir pasangan metode baru yang selalu mengembalikan salinan array baru dan membiarkan array aslinya tetap utuh:

Metode Lama (Merusak/Mutasi Array Asli)Metode Baru ES2023 (Aman / Mengembalikan Array Baru)
arr.sort(fn)arr.toSorted(fn)
arr.reverse()arr.toReversed()
arr.splice(mulai, hapus, ...item)arr.toSpliced(mulai, hapus, ...item)
arr[indeks] = nilaiBaruarr.with(indeks, nilaiBaru)
const skorAsli = [85, 100, 70, 92];

// Mengurutkan dari terkecil ke terbesar TANPA mengubah skorAsli
const skorUrut = skorAsli.toSorted((a, b) => a - b);

// Mengganti elemen pada indeks ke-2 (70 -> 78) TANPA mengubah skorAsli
const skorKoreksi = skorAsli.with(2, 78);

console.log(skorAsli);    // [85, 100, 70, 92] (Utuh 100%!)
console.log(skorUrut);    // [70, 85, 92, 100]
console.log(skorKoreksi); // [85, 100, 78, 92]
💡 Jangan Lupa Pembanding Angka (a, b) => a - b pada sort() / toSorted()!

Jika Anda memanggil [10, 2, 100].toSorted() tanpa fungsi pembanding, JavaScript akan mengubah semua angka menjadi teks string lalu mengurutkannya berdasarkan urutan kode karakter UTF-16, sehingga menghasilkan [10, 100, 2]! Untuk mengurutkan angka, selalu berikan (a, b) => a - b (naik) atau (a, b) => b - a (turun).

Mengambil Elemen dari Belakang dengan .at(-1)

Daripada menulis daftar[daftar.length - 1] yang panjang untuk mengambil elemen paling akhir dari sebuah array, gunakan metode daftar.at(-1) (Baseline Widely Available)!

4. Mengelompokkan Data dengan Object.groupBy() (Sejak ES2024)

Sebelumnya, mengelompokkan daftar objek berdasarkan kategori mengharuskan penulisan .reduce() yang bertele-tele. Sejak ECMAScript 2024 (status Baseline Widely Available; didukung semua peramban utama sejak Maret 2024), Anda cukup memanggil Object.groupBy(iterable, callback):

const inventarisServer = [
  { nama: "db-utama",     wilayah: "jakarta" },
  { nama: "api-gateway",  wilayah: "singapura" },
  { nama: "worker-antre", wilayah: "jakarta" }
];

const perWilayah = Object.groupBy(inventarisServer, (srv) => srv.wilayah);
console.log(perWilayah.jakarta);
// [{ nama: "db-utama", wilayah: "jakarta" }, { nama: "worker-antre", wilayah: "jakarta" }]

Latihan Praktik: Pipeline Analisis Data Nilai Peserta

Buatlah berkas olah-data.js dan jalankan dengan Node.js:

  1. Sediakan array peserta berisi 5 objek { nama, kelas, nilai }.
  2. Gunakan .toSorted((a, b) => b.nilai - a.nilai) untuk membuat daftar peringkat nilai tertinggi ke terendah tanpa mengubah urutan array peserta asli.
  3. Gunakan Object.groupBy() untuk mengelompokkan peserta menjadi kelompok "Lulus" (nilai >= 75) dan "Remedial" (nilai < 75).
  4. Hitung rata-rata nilai keseluruhan menggunakan .reduce(..., 0).