Object pesanan sudah jadi, lalu pelanggan meminta penyesuaian: level kepedasan diganti, catatan ditambah. Mengubah object asal langsung bisa saja, tetapi sering kali kita justru perlu versi baru — object asal dipakai lagi untuk pesanan berikutnya. Menyalin properti satu per satu dengan assignment jelas melelahkan dan mudah terlewat.
Operator tiga titik ... (spread syntax) menyelesaikan penyalinan dan penggabungan object dalam satu ekspresi. Dikombinasikan dengan rest pattern dari chapter destructuring, ... juga bisa memisahkan sebagian properti dari sisanya. Chapter ini membahas tiga peran tersebut, aturan urutan penimpaan key yang menentukan hasil penggabungan, dan satu batasan penting soal kedalaman salinan.
Menyalin Object dengan Spread #
Aturannya: tulis ...object di dalam literal baru, dan seluruh properti object sumber disebarkan ke object tersebut. Hasilnya object baru yang berdiri sendiri — mengubah salinan tidak memengaruhi asalnya pada tingkat pertama:
const asal = { menu: "Es Teh", harga: 8000 };
const salinan = { ...asal };
console.log(salinan.menu, salinan.harga);Output yang Dihasilkan:
Es Teh 8000Spread menyalin properti, bukan hubungan. Variabel salinan menunjuk object yang berbeda dari asal — perbandingan asal === salinan menghasilkan false. Mekanismenya: engine membaca setiap properti milik object sumber satu per satu, lalu menulisnya kembali ke object baru. Kita buktikan kemandiriannya secara penuh di berkas contoh bawah, dan kita periksa batasnya di bagian akhir chapter.
Satu batasan isi yang perlu dicatat sejak awal: spread hanya menyalin properti milik object itu sendiri — properti yang diwariskan lewat prototype tidak ikut. Untuk object literal yang kita tulis sendiri, seluruh properti memang milik sendiri, sehingga batasan ini jarang terasa; kegunaannya baru nyata di section Object-Oriented JavaScript, saat object berasal dari class atau constructor function.
Spread juga aman dipanggil terhadap nilai yang mungkin tidak ada. Menyebarkan undefined atau null menghasilkan object kosong, tanpa error:
const opsi = undefined;
const aman = { ...opsi };
console.log(Object.keys(aman));Output yang Dihasilkan:
[]Sifat ini sering dimanfaatkan di kode konfigurasi: { ...opsiPengguna } tetap berjalan meskipun variabel opsinya belum diisi. Patut diingat juga bahwa sebaran itu sekali jadi — nilai properti disalin pada saat literal dievaluasi. Perubahan yang terjadi pada object sumber setelahnya tidak mengalir ke salinan, karena yang disalin adalah nilai saat itu, bukan hubungan dengan object sumbernya.
Menggabungkan Object dan Urutan Override #
Dua atau lebih object bisa disebarkan dalam satu literal. Bila ada key yang sama, key dari object yang ditulis lebih kanan menimpa yang di kiri — sama seperti assignment berulang pada key yang sama:
const dasar = { kirim: "reguler", packing: "kertas" };
const ubah = { kirim: "kilat" };
const hasil = { ...dasar, ...ubah };
console.log(hasil.kirim, hasil.packing);Output yang Dihasilkan:
kilat kertaskirim berasal dari ubah karena ubah ditulis terakhir; packing tidak disentuh ubah, sehingga nilai dari dasar bertahan. Aturan ini yang membuat pola “default dulu, penyesuaian belakangan” bekerja: object berisi pilihan bawaan ditulis lebih dulu, object berisi preferensi pengguna ditulis setelahnya.
Aturan yang sama berlaku untuk key eksplisit yang ditulis setelah spread. Bentuk { ...dasar, harga: 25000 } selalu menghasilkan harga sebesar 25000, karena key eksplisit di kanan menimpa hasil sebaran apa pun di kirinya. Sumber yang boleh dirangkai pun tidak terbatas dua: pola { ...bawaan, ...preferensi, ...penyesuaianTerakhir } lazim dipakai agar setiap lapis konfigurasi punya posisi prioritas yang jelas — makin ke kanan, makin menang.
Memperbarui Object Bertingkat dengan Aman #
Ketika object punya properti berisi object lain, pembaruan satu field nested memerlukan spread di dua tingkat sekaligus. Pola ini salah satu yang paling sering dipakai dalam kode nyata, jadi mari kita bedah:
const state = { status: "aktif", alamat: { kota: "Bandung", kode: "40111" } };
const stateBaru = { ...state, alamat: { ...state.alamat, kota: "Jakarta" } };
console.log(state.alamat.kota);
console.log(stateBaru.alamat.kota, stateBaru.alamat.kode);
console.log(state.alamat === stateBaru.alamat);Output yang Dihasilkan:
Bandung
Jakarta 40111
falseSpread luar membuat object stateBaru dengan status ikut tersalin. Spread dalam — di posisi nilai alamat — membuat object alamat baru: kota ditimpa menjadi "Jakarta", sedangkan kode diambil dari sebaran sebelumnya. Baris terakhir adalah bukti keberhasilannya: alamat lama dan alamat baru kini dua object terpisah (false). Tanpa spread di tingkat dalam, object alamat akan tetap ditunjuk bersama oleh state dan stateBaru — perilaku shallow copy yang kita bedah tuntas di chapter Copying dan Comparing Objects.
Contoh Lengkap: Gabungan Pesanan #
Berkas berikut merangkum ketiga peran spread — menyalin, menggabungkan dengan penimpaan, dan memisahkan dengan rest:
// gabung-pesanan.js
// Spread (...): menyalin, menggabungkan, dan memisahkan object.
const pesananDasar = {
id: "INV-104",
menu: "Nasi Goreng",
level: 1,
harga: 20000
};
// menyalin object: salinan berdiri sendiri
const salinan = { ...pesananDasar };
salinan.harga = 22000;
console.log("Harga asli :", pesananDasar.harga);
console.log("Harga salinan:", salinan.harga);
// menggabungkan: key yang sama ditimpa oleh object di kanan
const tambahan = {
level: 3,
catatan: "Tanpa bawang"
};
const pesananAkhir = { ...pesananDasar, ...tambahan };
console.log("Level akhir:", pesananAkhir.level, "| Catatan:", pesananAkhir.catatan);
// override dengan key eksplisit yang ditulis setelah spread
const pesananSedang = { ...pesananDasar, level: 2 };
console.log("Level sedang:", pesananSedang.level);
// rest di object: memisahkan id dari properti sisanya
const { id, ...detail } = pesananAkhir;
console.log("id :", id);
console.log("detail:", detail.menu, "-", detail.catatan);
console.log("id di detail:", detail.id);Output yang Dihasilkan:
Harga asli : 20000
Harga salinan: 22000
Level akhir: 3 | Catatan: Tanpa bawang
Level sedang: 2
id : INV-104
detail: Nasi Goreng - Tanpa bawang
id di detail: undefinedMari kita telaah apa yang terjadi pada baris-baris kode di atas:
- Baris 14–15 (
const salinan = { ...pesananDasar };dansalinan.harga = 22000;): spread membuat object baru dengan keempat propertipesananDasar, lalu perubahan harga ditujukan ke salinan saja. - Baris 16–17 (
console.log("Harga asli :", ...)): bukti kemandirian —pesananDasar.hargatetap20000sementarasalinan.hargamenjadi22000. Dua variabel menunjuk dua object yang berbeda. - Baris 25 (
const pesananAkhir = { ...pesananDasar, ...tambahan };): penggabungan.tambahanmenyertakan keylevelyang sudah ada, sehingga nilai1dari pesanan dasar ditimpa menjadi3. Properticatatanyang baru ikut masuk. - Baris 29 (
const pesananSedang = { ...pesananDasar, level: 2 };): variasi penimpaan oleh key eksplisit. Penulisanlevel: 2setelah spread memastikan nilai akhirnya2, tanpa perlu membuat object terpisah untuk itu. - Baris 32 (
const { id, ...detail } = pesananAkhir;): rest pattern — tanda...di sisi kiri destructuring. Propertiiddikumpulkan ke variabelnya sendiri, lalu seluruh properti sisanya dikumpulkan menjadi object baru bernamadetail. - Baris 33–35 (
console.log(...)):detailberisimenu,level,harga, dancatatan— tetapi tidakid, yang dibuktikan oleh baris terakhir:detail.idmenghasilkanundefined.
Satu aturan sintaks untuk rest object: posisinya wajib paling akhir dalam pola. Penulisan const { ...detail, id } = pesananAkhir; — rest di tengah, ada kunci yang mengikutinya — ditolak saat penguraian kode dengan pesan SyntaxError: Rest element must be last element. Logikanya masuk akal: rest adalah “sisanya”, dan sisa hanya bermakna setelah semua yang ditunjuk namanya selesai dikumpulkan.
Pola kecil lain yang paling sering dipakai sehari-hari adalah menambah satu properti baru dengan tetap mempertahankan object asal: const denganCatatan = { ...pesananDasar, catatan: "Pedas sedang" };. Tanda ... menyalin seluruh properti lama, dan key eksplisit di belakangnya menambah yang baru — hasilnya object yang lebih lengkap tanpa menyentuh pesananDasar. Pola ini merupakan kebalikan dari rest di baris 32 berkas contoh: rest memisahkan satu properti keluar dari object, sedangkan spread menyisipkan satu properti masuk ke object baru.
Dengan spread, kita kini punya kendali penuh atas pembentukan object. Chapter berikutnya memperkenalkan perangkat bawaan Object.* untuk melihat, menggabungkan, dan membekukan object dari luar.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
gabung-pesanan.js
Unduh berkas// gabung-pesanan.js
// Spread (...): menyalin, menggabungkan, dan memisahkan object.
const pesananDasar = {
id: "INV-104",
menu: "Nasi Goreng",
level: 1,
harga: 20000
};
// menyalin object: salinan berdiri sendiri
const salinan = { ...pesananDasar };
salinan.harga = 22000;
console.log("Harga asli :", pesananDasar.harga);
console.log("Harga salinan:", salinan.harga);
// menggabungkan: key yang sama ditimpa oleh object di kanan
const tambahan = {
level: 3,
catatan: "Tanpa bawang"
};
const pesananAkhir = { ...pesananDasar, ...tambahan };
console.log("Level akhir:", pesananAkhir.level, "| Catatan:", pesananAkhir.catatan);
// override dengan key eksplisit yang ditulis setelah spread
const pesananSedang = { ...pesananDasar, level: 2 };
console.log("Level sedang:", pesananSedang.level);
// rest di object: memisahkan id dari properti sisanya
const { id, ...detail } = pesananAkhir;
console.log("id :", id);
console.log("detail:", detail.menu, "-", detail.catatan);
console.log("id di detail:", detail.id);