Kenapa ini penting
Bayangkan kamu membuat aplikasi toko online. Satu produk punya nama, harga, stok, kategori, dan foto. Satu pengguna punya nama, email, alamat, dan riwayat pesanan. Semua itu disimpan sebagai object. Setiap hari kodemu akan menggabungkan object (misalnya data default + data dari form), menyalin object (supaya data asli tidak rusak), membaca semua kuncinya (untuk membuat tabel), dan membuat kunci secara dinamis (misalnya dari nama kolom yang dipilih pengguna).
Kalau kamu tidak paham cara menyalin object dengan benar, kamu akan bertemu bug klasik: "Kok data di keranjang A ikut berubah waktu saya ubah keranjang B?" Bug seperti ini susah dilacak karena kodenya kelihatan benar. Modul ini membekali kamu dengan alat-alat modern untuk mengolah object tanpa jebakan semacam itu.
Konsep inti
Object literal, shorthand, dan computed property
Object literal adalah cara menulis object langsung dengan kurung kurawal {}. Ada beberapa fitur yang membuat penulisannya lebih ringkas:
- Property shorthand: kalau nama variabel sama dengan nama kunci, cukup tulis sekali.
{ nama: nama }bisa ditulis{ nama }. - Method shorthand: function di dalam object bisa ditulis
sapa() { ... }tanpasapa: function() { ... }. - Computed property (properti dinamis): nama kunci dihitung dari ekspresi, ditulis dalam kurung siku.
{ [kolom]: nilai }artinya kuncinya adalah isi variabelkolom, bukan teks "kolom".
Analogi computed property: kamu punya lemari arsip dan label laci ditulis berdasarkan nama bulan yang sedang berjalan. Labelnya tidak ditentukan dari awal, tapi dihitung saat itu juga.
Membaca isi object: keys, values, entries
Tiga method statis ini mengubah object menjadi array, sehingga kamu bisa memakai loop atau method array:
| Method | Hasil | Contoh hasil untuk {a: 1, b: 2} |
|---|---|---|
Object.keys(obj) |
array kunci | ['a', 'b'] |
Object.values(obj) |
array nilai | [1, 2] |
Object.entries(obj) |
array pasangan [kunci, nilai] |
[['a', 1], ['b', 2]] |
Ketiganya hanya mengambil properti milik object itu sendiri (own property) yang enumerable (bisa dihitung), dan tidak mengambil kunci berupa Symbol (dibahas di modul 5).
Menggabungkan object: spread dan Object.assign
Spread syntax ... "menumpahkan" isi object ke object baru. { ...a, ...b } membuat object baru berisi semua properti a, lalu ditimpa oleh properti b kalau ada kunci yang sama. Urutan penting: yang ditulis belakangan menang.
Object.assign(target, sumber1, sumber2) melakukan hal serupa, tapi mengubah target secara langsung dan mengembalikan target itu. Kalau kamu tidak ingin mengubah object yang sudah ada, pakai Object.assign({}, a, b) atau lebih sederhana pakai spread.
Shallow copy vs deep copy
Ini konsep paling penting di modul ini. Object disimpan sebagai referensi (alamat). Saat kamu menulis const b = a, kamu tidak menyalin object, kamu hanya memberi nama kedua ke alamat yang sama. Mirip memberi kunci duplikat rumah ke teman: rumahnya tetap satu.
- Shallow copy (salinan dangkal): menyalin lapisan pertama saja. Spread dan
Object.assigntermasuk shallow. Kalau ada object di dalam object (nested), bagian dalamnya masih menunjuk ke alamat yang sama. - Deep copy (salinan dalam): menyalin semua lapisan sampai ke dalam. Cara modern dan resmi adalah
structuredClone(obj), yang tersedia di browser modern dan Node.js 17 ke atas.
structuredClone bisa menyalin Date, Map, Set, array, dan object bersarang, bahkan referensi melingkar. Tapi ia tidak bisa menyalin function (akan melempar error DataCloneError) dan tidak membawa prototype class (hasilnya object biasa). Trik lama JSON.parse(JSON.stringify(obj)) juga deep copy, tapi merusak Date menjadi string, membuang undefined dan function, dan gagal pada Map/Set.
Contoh kode
// 1) Shorthand dan computed property
const nama = "Kopi Susu";
const harga = 18000;
const kolomDiskon = "diskon_" + "member"; // kunci dihitung saat runtime
const produk = {
nama, // sama dengan nama: nama
harga, // sama dengan harga: harga
[kolomDiskon]: 10, // kuncinya jadi "diskon_member"
info() { // method shorthand
return `${this.nama} - Rp${this.harga}`;
},
};
console.log(produk.diskon_member); // → 10
console.log(produk.info()); // → Kopi Susu - Rp18000
// 2) keys, values, entries
const stok = { kopi: 12, teh: 0, coklat: 5 };
console.log(Object.keys(stok)); // → [ 'kopi', 'teh', 'coklat' ]
console.log(Object.values(stok)); // → [ 12, 0, 5 ]
for (const [item, jumlah] of Object.entries(stok)) {
console.log(`${item}: ${jumlah > 0 ? "tersedia" : "habis"}`);
}
// → kopi: tersedia
// → teh: habis
// → coklat: tersedia
// 3) Menggabungkan pengaturan default dengan pilihan pengguna
const defaultSetting = { tema: "terang", bahasa: "id", notifikasi: true };
const pilihanUser = { tema: "gelap" };
const setting = { ...defaultSetting, ...pilihanUser };
console.log(setting); // → { tema: 'gelap', bahasa: 'id', notifikasi: true }
const target = { a: 1 };
const hasil = Object.assign(target, { b: 2 });
console.log(target, hasil === target); // → { a: 1, b: 2 } true (target ikut berubah!)
// 4) Shallow copy: bagian dalam masih berbagi alamat
const pesanan = { id: 1, alamat: { kota: "Bandung" } };
const salinanDangkal = { ...pesanan };
salinanDangkal.id = 2;
salinanDangkal.alamat.kota = "Jakarta";
console.log(pesanan.id); // → 1 (lapisan luar aman)
console.log(pesanan.alamat.kota); // → Jakarta (lapisan dalam ikut berubah!)
// 5) Deep copy dengan structuredClone
const asli = { id: 1, alamat: { kota: "Bandung" }, dibuat: new Date(0), tag: new Set(["baru"]) };
const salinanDalam = structuredClone(asli);
salinanDalam.alamat.kota = "Surabaya";
console.log(asli.alamat.kota); // → Bandung (aman)
console.log(salinanDalam.dibuat instanceof Date); // → true
console.log(salinanDalam.tag.has("baru")); // → true
// 6) Bandingkan dengan trik JSON yang merusak tipe data
const viaJson = JSON.parse(JSON.stringify(asli));
console.log(typeof viaJson.dibuat); // → string (Date berubah jadi teks)
console.log(viaJson.tag); // → {} (Set hilang isinya)
// 7) structuredClone tidak bisa menyalin function
try {
structuredClone({ hitung() {} });
} catch (err) {
console.log(err.name); // → DataCloneError
}
Kesalahan umum
- Mengira
const b = aitu menyalin. Itu hanya menyalin alamat. Pakai{ ...a }untuk salinan dangkal ataustructuredClone(a)untuk salinan dalam. - Memakai spread untuk object bersarang lalu kaget data asli berubah. Spread hanya menyalin lapisan pertama. Kalau ada object di dalam object dan kamu akan mengubah bagian dalamnya, pakai
structuredClone. - Salah urutan saat menggabungkan.
{ ...pilihanUser, ...defaultSetting }membuat default menimpa pilihan pengguna. Taruh yang ingin "menang" di paling belakang. - Lupa kurung siku pada computed property.
{ kolom: 1 }menghasilkan kunci bernama "kolom". Untuk memakai isi variabel, tulis{ [kolom]: 1 }. Object.assign(a, b)tanpa sadar mengubaha. Kalauaadalah data dari luar (misalnya props atau state), ini bisa menimbulkan bug. PakaiObject.assign({}, a, b)atau spread.
Latihan
- Mudah, Diberikan
const nilai = { budi: 80, sari: 92, joko: 75 }. Cetak total semua nilai memakaiObject.values. - Sedang, Buat function
setField(obj, kunci, nilai)yang mengembalikan object baru dengan kunci dinamis tersebut ditambahkan atau diganti, tanpa mengubah object asli. - Menantang, Diberikan object
profilbersarang (berisialamatdanhobiberupa array). Buat salinan yang aman, ubah kota dan tambahkan satu hobi pada salinan, lalu buktikan denganconsole.logbahwa object asli tidak berubah.
Lihat solusi
// 1) Mudah
const nilai = { budi: 80, sari: 92, joko: 75 };
let total = 0;
for (const n of Object.values(nilai)) total += n;
console.log(total); // → 247
// 2) Sedang
function setField(obj, kunci, nilai) {
return { ...obj, [kunci]: nilai };
}
const awal = { a: 1 };
const baru = setField(awal, "b", 2);
console.log(awal, baru); // → { a: 1 } { a: 1, b: 2 }
// 3) Menantang
const profil = { nama: "Rina", alamat: { kota: "Medan" }, hobi: ["baca"] };
const salinan = structuredClone(profil);
salinan.alamat.kota = "Padang";
salinan.hobi.push("renang");
console.log(profil.alamat.kota, profil.hobi); // → Medan [ 'baca' ]
console.log(salinan.alamat.kota, salinan.hobi); // → Padang [ 'baca', 'renang' ]
Ringkasan
- Shorthand
{ nama }dan methodsapa() {}membuat object literal lebih ringkas; computed property{ [kunci]: nilai }membuat nama kunci dinamis. Object.keys,Object.values, danObject.entriesmengubah object menjadi array supaya mudah di-loop.- Spread
{ ...a, ...b }membuat object baru;Object.assign(target, ...)mengubahtarget. Yang ditulis terakhir menimpa. - Spread dan
Object.assignadalah shallow copy: object di dalamnya masih dipakai bersama. structuredCloneadalah cara resmi untuk deep copy, tapi tidak bisa menyalin function.