Siti mengelola pendaftaran lokakarya. Konfigurasinya bukan object sederhana: ada Date untuk tanggal pembukaan, Map untuk hitungan pendaftar per kanal, Set untuk daftar peserta, dan RegExp untuk memeriksa format kode pendaftaran. Saat ia perlu versi kerja untuk eksperimen — misalnya mencoba menambah peserta tanpa menyentuh data asli — salinan biasa ternyata tidak cukup: sebagian isi salinan masih terhubung ke data asli.
Chapter ini membahas tiga cara menyalin data di JavaScript dan batas masing-masing: spread yang hanya menyalin lapisan terluar, bolak-balik JSON yang mengubah bentuk data, dan structuredClone yang menyalin semuanya sampai ke lapisan dalam tanpa mengubah tipe.
Salinan Dangkal Masih Berbagi Isi #
Spread { ...objek } membuat object baru, tetapi hanya di lapisan terluar. Nilai yang bertipe object di dalamnya tetap ditunjuk bersama oleh asli dan salinan:
const asli = { meta: { halaman: 320 }, judul: "Bumi dan Api" };
const dangkal = { ...asli };
dangkal.meta.halaman = 321;
console.log(asli.meta.halaman);Output yang Dihasilkan:
321Kita hanya mengubah dangkal.meta.halaman, tetapi asli.meta.halaman ikut berubah. Mekanismenya: spread menyalin nilai setiap kunci, dan nilai meta adalah referensi — referensi itulah yang disalin, bukan object di baliknya. Akibatnya asli dan salinan berbagi object meta yang sama. Salinan seperti ini disebut shallow copy (salinan dangkal).
Hal yang sama terjadi pada array. [...array] membuat array baru, tetapi isinya yang bertipe referensi tetap ditunjuk bersama:
const daftar = [[1, 2], { nilai: 3 }];
const salinanMendalam = structuredClone(daftar);
salinanMendalam[0].push(99);
salinanMendalam[1].nilai = 30;
console.log(daftar[0], daftar[1]);Output yang Dihasilkan:
[ 1, 2 ] { nilai: 3 }Perhatikan bahwa data asli tidak berubah walau salinannya diubah di dua tempat sekaligus — array di dalam array maupun object di dalamnya ikut dibuat ulang. Inilah bedanya dengan salinan dangkal: structuredClone turun sampai lapisan terdalam.
structuredClone Menyalin Sampai ke Lapisan Dalam #
structuredClone(nilai) membuat salinan mendalam (deep copy): seluruh lapisan object dibuat ulang, dan tipe khusus seperti Date, Map, Set, serta RegExp tetap dipertahankan sebagai tipe yang sama. Di balik layar, algoritma salinannya menyusuri setiap nilai dari akar sampai daun, mencatat object mana yang sudah disalin, lalu membangun ulang semuanya di rumah baru. Catatan referensi itulah yang membuat object yang ditunjuk dua kunci tetap dipasangkan pada salinannya — kita lihat buktinya di bagian ketiga berkas berikut:
// salin-konfigurasi.js — structuredClone untuk data kompleks
const konfigurasi = {
dibuat: new Date("2026-08-01T04:00:00Z"),
kanal: new Map([
["whatsapp", 12],
["instagram", 5],
]),
peserta: new Set(["Siti", "Budi"]),
polaKode: /LOKA-\d+/g,
daftar: [{ nama: "Siti" }],
};
// --- 1. salinan mendalam dengan structuredClone ---
const salinan = structuredClone(konfigurasi);
console.log(salinan.dibuat instanceof Date);
console.log(salinan.kanal instanceof Map);
console.log(salinan.peserta instanceof Set);
console.log(salinan.polaKode instanceof RegExp);
console.log(salinan.polaKode.source);
// --- 2. salinan terpisah: mengubah salinan tidak menyentuh asli ---
salinan.daftar[0].nama = "Rina";
salinan.peserta.add("Rina");
console.log(konfigurasi.daftar[0].nama);
console.log(konfigurasi.peserta.size);
// --- 3. duplikat referensi internal tetap dipasangkan ---
const acara = { nama: "Lokakarya Menulis" };
const pendaftaran = { acaraUtama: acara, acaraCadangan: acara };
const salinanPendaftaran = structuredClone(pendaftaran);
console.log(salinanPendaftaran.acaraUtama === salinanPendaftaran.acaraCadangan);
salinanPendaftaran.acaraUtama.nama = "Lokakarya 2026";
console.log(salinanPendaftaran.acaraCadangan.nama);
// --- 4. batasan: function tidak bisa disalin ---
const denganFungsi = { nama: "Siti", sapa() { return "Halo!"; } };
try {
structuredClone(denganFungsi);
} catch (galat) {
console.log(galat.name + ": " + galat.message);
}Output yang Dihasilkan:
true
true
true
true
LOKA-\d+
Siti
2
true
Lokakarya 2026
DataCloneError: sapa() { return "Halo!"; } could not be cloned.Mari kita telaah baris-baris pentingnya:
- Baris 14–19 (
structuredClone(konfigurasi)dan pemeriksaan): salinan lapor dirinya satu per satu —dibuattetapDate,kanaltetapMap,pesertatetapSet, danpolaKodetetapRegExp(terbukti darisourceyang masih berisiLOKA-\d+). Tidak ada satu pun yang berubah menjadi object polos. - Baris 22–25 (mengubah salinan): nama di
daftardiganti dan peserta baru ditambah pada salinan saja. Data asli tetap menunjuk"Siti"danpesertatetap beranggota dua — pembuktian bahwa salinan benar-benar berdiri sendiri, bukan berbagi isi seperti salinan dangkal tadi. - Baris 28–33 (duplikat referensi internal): object
acaraditunjuk dua kunci sekaligus dipendaftaran. Pada salinan,acaraUtamadanacaraCadanganmasih saling sama (===bernilaitrue), dan mengubah lewatacaraUtamaterlihat lewatacaraCadangan.structuredClonememetakan referensi asli ke referensi salinan, sehingga bentuk hubungan antar nilai ikut tersalin — termasuk data yang merujuk dirinya sendiri (circular), yang justru membuatJSON.stringifygagal. - Baris 36–41 (batasan): function tidak termasuk data yang bisa disalin. Percobaan meng-clone object yang berisi method melempar
DataCloneError, dan pesannya menyebut potongan kode yang bermasalah. Inilah alasantry...catchdipasang di sekitarnya.
Satu penutup kecil sebelum banding-banding: nilai primitif bisa di-clone juga dan hasilnya tetap primitif — structuredClone(42) mengembalikan 42, begitu pula string dan null. Fungsi ini aman dipanggil pada nilai apa pun; pembedanya hanya pada kedalaman hasilnya untuk tipe referensi:
console.log(structuredClone(42), structuredClone("teks"), structuredClone(null));Output yang Dihasilkan:
42 teks nullPerbandingan dengan Bolak-Balik JSON #
Sebelum structuredClone tersedia, pola yang lazim untuk salinan mendalam adalah JSON.parse(JSON.stringify(data)). Pola itu bekerja untuk object sederhana, tetapi mengubah bentuk semua tipe khusus:
const data = {
tgl: new Date("2026-08-01T04:00:00Z"),
label: new Map([["wa", 12]]),
unik: new Set([1, 2]),
re: /LOKA-\d+/g,
};
const viaJson = JSON.parse(JSON.stringify(data));
console.log(viaJson.tgl, viaJson.label, viaJson.unik, viaJson.re);
console.log(viaJson.tgl instanceof Date);Output yang Dihasilkan:
2026-08-01T04:00:00.000Z {} {} {}
falseHasil bolak-balik JSON memperlihatkan kerugian satu per satu: tgl kini string ISO biasa (instanceof Date bernilai false), sedangkan label, unik, dan re — Map, Set, dan RegExp — semuanya menjadi object kosong {}, karena JSON tidak mengenal tipe-tipe itu. Data yang “kembali” sudah tidak sama bentuknya dengan data yang dikirim.
Kapan Memilih yang Mana #
Ketiga cara menyalin memiliki wilayah kerja masing-masing:
| Kebutuhan | Alat | Catatan |
|---|---|---|
| Teks untuk dikirim atau disimpan | JSON.stringify | hasilnya teks JSON; tipe khusus berubah bentuk |
| Salinan kerja di dalam program | structuredClone | salinan mendalam, tipe terjaga, function ditolak |
| Object sederhana tanpa lapisan dalam | spread { ...objek } | cepat, tetapi salinan dangkal |
Penggunaan structuredClone yang paling sering adalah menyimpan keadaan (state) sebelum diubah — pola snapshot untuk pembatalan langkah: salin keadaan sekarang, biarkan pengguna beraksi, dan bila ia membatalkan, kembalikan salinan tersebut. Tanpa salinan mendalam, “snapshot” itu ikut berubah setiap keadaan berubah, dan pembatalannya tidak berarti apa-apa.
Sebelum memanggil structuredClone, pastikan yang disalin memang data. Cara paling sederhana: kumpulkan field datanya ke object baru, tinggalkan method-nya di luar:
const tugas = {
judul: "Cetak undangan",
selesai: false,
tandaiSelesai() { this.selesai = true; },
};
const dataTugas = { judul: tugas.judul, selesai: tugas.selesai };
console.log(structuredClone(dataTugas));Output yang Dihasilkan:
{ judul: 'Cetak undangan', selesai: false }Object tugas tidak bisa di-clone utuh karena punya method, tetapi dataTugas — yang hanya memuat field-nya — tersalin mulus. Pola ini juga memaksa kita jujur tentang mana bagian data dan mana bagian perilaku.
Dengan structuredClone, salinan data di dalam program sudah aman. Pertanyaan berikutnya bergeser ke isi datanya sendiri: tanggal. Membuat, membaca, dan memformat tanggal di JavaScript punya aturan dan jebakan tersendiri — itulah bahasan chapter berikutnya.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
salin-konfigurasi.js
Unduh berkas// salin-konfigurasi.js — structuredClone untuk data kompleks
const konfigurasi = {
dibuat: new Date("2026-08-01T04:00:00Z"),
kanal: new Map([
["whatsapp", 12],
["instagram", 5],
]),
peserta: new Set(["Siti", "Budi"]),
polaKode: /LOKA-\d+/g,
daftar: [{ nama: "Siti" }],
};
// --- 1. salinan mendalam dengan structuredClone ---
const salinan = structuredClone(konfigurasi);
console.log(salinan.dibuat instanceof Date);
console.log(salinan.kanal instanceof Map);
console.log(salinan.peserta instanceof Set);
console.log(salinan.polaKode instanceof RegExp);
console.log(salinan.polaKode.source);
// --- 2. salinan terpisah: mengubah salinan tidak menyentuh asli ---
salinan.daftar[0].nama = "Rina";
salinan.peserta.add("Rina");
console.log(konfigurasi.daftar[0].nama);
console.log(konfigurasi.peserta.size);
// --- 3. duplikat referensi internal tetap dipasangkan ---
const acara = { nama: "Lokakarya Menulis" };
const pendaftaran = { acaraUtama: acara, acaraCadangan: acara };
const salinanPendaftaran = structuredClone(pendaftaran);
console.log(salinanPendaftaran.acaraUtama === salinanPendaftaran.acaraCadangan);
salinanPendaftaran.acaraUtama.nama = "Lokakarya 2026";
console.log(salinanPendaftaran.acaraCadangan.nama);
// --- 4. batasan: function tidak bisa disalin ---
const denganFungsi = { nama: "Siti", sapa() { return "Halo!"; } };
try {
structuredClone(denganFungsi);
} catch (galat) {
console.log(galat.name + ": " + galat.message);
}