Tangan seseorang sedang mengetik di laptop untuk menyalin objek JavaScript

Anda punya objek user dan ingin membuat salinannya untuk diedit tanpa mengubah data asli. Anda menulis const userCopy = user, mengubah properti di userCopy, lalu terkejut karena user ikut berubah. Penyebabnya, Anda hanya menyalin referensinya. Cara menyalin objek di JavaScript bergantung pada dua pendekatan, shallow copy dan deep copy, dan memilih yang salah bisa memunculkan bug yang sulit dilacak.

Pembahasan berikut mencakup perbedaan keduanya, metode yang tersedia, dan situasi yang cocok untuk masing-masing.

Mengapa Menyalin Objek Tidak Cukup dengan Tanda Sama Dengan

Di JavaScript, objek disimpan sebagai referensi. Ketika Anda menulis const copy = original, variabel copy menunjuk ke objek yang sama dengan original. Perubahan pada salah satu variabel akan memengaruhi yang lain.

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

Untuk benar-benar menyalin, Anda perlu membuat objek baru yang berisi properti yang sama. Di sinilah shallow copy dan deep copy berperan.

Shallow Copy: Menyalin Satu Level Pertama

Shallow copy membuat objek baru dengan properti yang merujuk ke nilai yang sama. Jika properti tersebut adalah objek atau array, referensinya tetap sama. Artinya, perubahan pada objek bersarang akan memengaruhi objek asli.

Metode untuk Shallow Copy

  • Object.assign(): Menyalin properti enumerable dari satu atau lebih objek sumber ke objek target.
  • Spread operator (…): Sintaks modern yang lebih ringkas untuk menyalin properti.

Contoh penggunaan spread operator:

const original = { nama: 'Budi', alamat: { kota: 'Jakarta' } };
const copy = { ...original };
copy.nama = 'Ani';
console.log(original.nama); // 'Budi' (tidak berubah)
copy.alamat.kota = 'Bandung';
console.log(original.alamat.kota); // 'Bandung' (berubah!)

Properti nama tidak terpengaruh karena nilainya primitif. Properti alamat adalah objek, sehingga referensinya masih sama. Inilah keterbatasan shallow copy.

Deep Copy: Menyalin Hingga Level Terdalam

Deep copy membuat salinan rekursif dari semua properti, termasuk objek bersarang. Perubahan pada salinan tidak akan memengaruhi objek asli sama sekali. Namun, deep copy memiliki biaya performa dan kompleksitas sendiri.

Metode untuk Deep Copy

  • JSON.parse(JSON.stringify(obj)): Cara klasik, tetapi tidak cocok untuk fungsi, undefined, NaN, Infinity, Date, atau properti dengan referensi sirkular.
  • structuredClone(): Fungsi bawaan yang lebih modern dan mendukung banyak tipe data, termasuk Date, Map, Set, dan ArrayBuffer. Tidak mendukung fungsi.
  • Library pihak ketiga: seperti Lodash cloneDeep, jika Anda sudah menggunakannya.

Contoh dengan structuredClone:

const original = { nama: 'Budi', alamat: { kota: 'Jakarta' } };
const deepCopy = structuredClone(original);
deepCopy.alamat.kota = 'Bandung';
console.log(original.alamat.kota); // 'Jakarta' (tidak berubah)

structuredClone tersedia di sebagian besar browser modern dan Node.js versi terbaru. Jika target lingkungan Anda lebih lama, gunakan JSON atau library.

Kapan Menggunakan Shallow Copy dan Deep Copy?

Gunakan shallow copy ketika objek Anda hanya memiliki properti primitif atau ketika Anda memang ingin berbagi referensi untuk objek bersarang. Shallow copy cepat dan cukup untuk banyak kasus, misalnya saat memperbarui state di React dengan spread operator.

Gunakan deep copy ketika Anda perlu memodifikasi salinan secara independen tanpa risiko mengubah data asli, terutama jika objek memiliki struktur bersarang yang dalam. Namun, waspadai performa jika objek sangat besar atau sering disalin.

Pitfall yang Sering Terjadi

Banyak pengembang terjebak menggunakan JSON untuk deep copy pada objek yang mengandung Date. JSON akan mengubah Date menjadi string, sehingga kehilangan tipe aslinya. Selain itu, properti yang tidak dapat dienumerasi atau simbol akan hilang. structuredClone mengatasi sebagian masalah ini, tetapi tetap tidak bisa menyalin fungsi.

Untuk objek dengan referensi sirkular, JSON akan melempar error. structuredClone mendukung referensi sirkular, tetapi tidak semua lingkungan menyediakannya.

Ringkasan

Menyalin objek di JavaScript memerlukan pemahaman tentang shallow copy dan deep copy. Gunakan shallow copy untuk salinan cepat dengan properti primitif, dan deep copy ketika Anda perlu isolasi penuh. Pilih metode yang sesuai dengan tipe data dan lingkungan target. Uji perilaku salinan pada struktur objek yang kompleks untuk memastikan tidak ada bug tersembunyi.

Pertanyaan yang Sering Diajukan

Apakah spread operator melakukan deep copy?

Tidak. Spread operator hanya melakukan shallow copy. Properti yang berupa objek atau array akan tetap memiliki referensi yang sama dengan objek asli.

Apakah JSON.parse(JSON.stringify(obj)) aman untuk semua objek?

Tidak. Metode ini gagal untuk fungsi, undefined, NaN, Infinity, Date, dan properti dengan referensi sirkular. Gunakan structuredClone atau library jika objek Anda mengandung tipe data tersebut.

Kapan sebaiknya menggunakan structuredClone?

Gunakan structuredClone ketika Anda perlu deep copy yang mendukung banyak tipe data dan lingkungan target Anda sudah mendukungnya. Untuk kompatibilitas yang lebih luas, pertimbangkan library seperti Lodash.