Menyalin objek di JavaScript sering dianggap remeh, padahal hasilnya berbeda tergantung teknik yang dipakai. Ada yang menyalin referensi, ada yang menyalin properti satu level, dan ada yang menyalin seluruh struktur bersarang. Pilihan yang salah bisa menyebabkan perubahan tak terduga pada objek asli. Tujuh teknik menyalin objek berikut disusun dari yang paling sederhana hingga paling dalam.

1. Assignment Biasa: Salin Referensi, Bukan Salin Objek

Operator = untuk menyalin objek tidak membuat objek baru. Variabel kedua menunjuk ke objek yang sama di memori.

const asli = { nama: 'Budi', umur: 30 };
const salinan = asli;
salinan.umur = 31;
console.log(asli.umur); // 31

Perubahan pada salinan ikut mengubah asli karena keduanya merujuk ke objek yang sama. Teknik ini cocok jika kamu memang ingin berbagi referensi, misalnya saat meneruskan objek ke fungsi yang boleh memodifikasinya. Untuk membuat salinan independen, lanjutkan ke teknik berikutnya.

2. Object.assign: Menyalin Properti ke Objek Baru

Object.assign menyalin properti enumerable dari satu atau lebih objek sumber ke objek target. Jika target adalah objek kosong, hasilnya objek baru dengan properti dangkal.

const asli = { nama: 'Budi', alamat: { kota: 'Jakarta' } };
const salinan = Object.assign({}, asli);
salinan.nama = 'Ani';
console.log(asli.nama); // 'Budi' (tidak berubah)
salinan.alamat.kota = 'Bandung';
console.log(asli.alamat.kota); // 'Bandung' (ikut berubah)

alamat adalah objek bersarang. Object.assign hanya menyalin referensi ke objek alamat, sehingga perubahan pada properti di dalamnya masih memengaruhi objek asli. Teknik ini disebut shallow copy.

3. Spread Operator: Sintaks Ringkas untuk Shallow Copy

Spread operator (...) pada objek menyalin properti enumerable ke objek baru dengan sintaks pendek. Hasilnya serupa dengan Object.assign({}, obj).

const asli = { nama: 'Budi', hobi: ['membaca', 'menulis'] };
const salinan = { ...asli };
salinan.nama = 'Ani';
console.log(asli.nama); // 'Budi'
salinan.hobi.push('melukis');
console.log(asli.hobi); // ['membaca', 'menulis', 'melukis']

Array hobi juga disalin referensinya, bukan diduplikasi. Spread operator tetap dangkal. Keunggulannya adalah sintaks yang lebih bersih dan mudah dibaca, terutama saat menggabungkan beberapa objek.

4. Array.prototype.slice dan Array.from untuk Objek Array

Jika objek yang akan disalin adalah array, slice() atau Array.from() dapat membuat salinan dangkal array baru. Keduanya menyalin elemen level pertama saja.

const arr = [1, 2, 3];
const salinan1 = arr.slice();
const salinan2 = Array.from(arr);
console.log(salinan1); // [1, 2, 3]

Keduanya tidak cocok untuk array yang berisi objek bersarang jika kamu ingin salinan sepenuhnya independen. Untuk array of objects, tetap perlu deep copy.

5. JSON.parse dan JSON.stringify: Deep Copy dengan Keterbatasan

Mengubah objek menjadi string JSON lalu mengurainya kembali menghasilkan objek baru yang sepenuhnya terpisah, termasuk untuk properti bersarang.

const asli = { nama: 'Budi', alamat: { kota: 'Jakarta' }, hobi: ['membaca'] };
const salinan = JSON.parse(JSON.stringify(asli));
salinan.alamat.kota = 'Bandung';
console.log(asli.alamat.kota); // 'Jakarta' (tidak berubah)

Teknik ini memiliki beberapa batasan: properti dengan nilai undefined, fungsi, atau Symbol akan hilang; tanggal berubah menjadi string; dan objek dengan referensi melingkar menyebabkan error. Gunakan hanya untuk objek yang berisi data JSON murni.

6. structuredClone: Deep Copy Modern

structuredClone adalah fungsi bawaan JavaScript yang tersedia di lingkungan modern (browser dan Node.js versi terbaru). Fungsi ini membuat deep copy yang mendukung banyak tipe data seperti Date, Map, Set, dan ArrayBuffer.

const asli = { nama: 'Budi', tanggal: new Date(), data: new Map() };
const salinan = structuredClone(asli);
salinan.nama = 'Ani';
console.log(asli.nama); // 'Budi'
console.log(salinan.tanggal instanceof Date); // true

Fungsi tidak dapat disalin, dan properti yang tidak dapat diserialisasi menyebabkan error. Untuk objek kompleks non-JSON, structuredClone sering menjadi pilihan terbaik.

7. Library Pihak Ketiga: Lodash cloneDeep

Jika kamu membutuhkan deep copy yang lebih toleran terhadap berbagai tipe data, library seperti Lodash menyediakan _.cloneDeep. Fungsi ini menangani objek bersarang, array, Date, RegExp, Map, Set, dan bahkan referensi melingkar.

import cloneDeep from 'lodash/cloneDeep';
const asli = { a: 1, b: { c: 2 } };
const salinan = cloneDeep(asli);
salinan.b.c = 3;
console.log(asli.b.c); // 2

Menggunakan library menambah dependensi, tetapi bisa menghemat waktu jika kamu sering berurusan dengan struktur data kompleks. Pertimbangkan ukuran bundle, terutama untuk aplikasi frontend.

Untuk perbandingan lebih lanjut antara shallow copy dan deep copy, termasuk contoh kode dan penjelasan detail, kamu bisa membaca artikel Cara Menyalin Objek di JavaScript: Shallow vs Deep Copy. Jika kamu juga bekerja dengan PHP, ada pembahasan cara menampilkan pesan error validasi form PHP agar pengalaman pengguna tetap baik.

Pilihan teknik menyalin objek bergantung pada struktur data dan kebutuhanmu. Assignment hanya untuk berbagi referensi. Object.assign dan spread operator cocok untuk shallow copy yang cepat. Untuk deep copy, JSON.parse(JSON.stringify()) bekerja pada data JSON murni, structuredClone lebih modern, dan Lodash memberikan fleksibilitas ekstra. Uji perilakunya, terutama jika objek memiliki properti bersarang atau tipe data khusus.

Pertanyaan yang Sering Diajukan

Apa bedanya shallow copy dan deep copy?

Shallow copy hanya menyalin referensi ke objek bersarang, sehingga perubahan pada properti di dalamnya masih memengaruhi objek asli. Deep copy membuat salinan independen untuk seluruh tingkat, termasuk objek bersarang.

Kapan sebaiknya menggunakan structuredClone?

Gunakan structuredClone ketika kamu perlu deep copy untuk objek yang mengandung Date, Map, Set, atau tipe data kompleks lain, dan tidak ada fungsi di dalamnya. Fungsi ini tidak didukung di lingkungan lama, jadi periksa kompatibilitas.

Apakah JSON.parse(JSON.stringify()) selalu aman untuk deep copy?

Tidak. Teknik ini gagal untuk properti yang tidak dapat diserialisasi seperti fungsi, undefined, Symbol, dan mengubah Date menjadi string. Gunakan hanya untuk data yang seluruhnya JSON-compatible.