JavaScript modern menambahkan operator dan fungsi bawaan yang menyingkat pola yang sebelumnya ditulis panjang. Topik ini memperdalam tiga di antaranya, yaitu nullish coalescing di luar pemakaian dasarnya, tiga operator logical assignment, dan structuredClone untuk menyalin data bersarang. Dasar ?? dan ?. sudah diperkenalkan pada topik optional chaining, sehingga fokus di sini adalah batasan dan kombinasi yang jarang disinggung.
Nullish coalescing di luar nilai cadangan#
Ekspresi a ?? b hanya menilai sisi kanannya bila a bernilai null atau undefined, dan sifat itu berlaku juga pada rantai cadangan yang lebih panjang. Rantai a ?? b ?? c mengambil a bila bukan nullish, lalu b, lalu c, sehingga daftar cadangan bertingkat dapat ditulis tanpa if bertingkat. Sifat kedua menyusul yang pertama, yaitu sisi kanan tidak dievaluasi sama sekali bila sisi kiri bukan nullish.
// Sisi kanan ?? hanya dievaluasi bila sisi kirinya nullish.
function samping() {
console.log("sisi kanan dievaluasi");
return "cadangan";
}
console.log(0 ?? samping());
console.log(null ?? samping());0
sisi kanan dievaluasi
cadanganAngka 0 bukan nullish, sehingga fungsi samping tidak pernah dipanggil pada baris pertama dan keluarannya hanya 0. Sifat berhenti lebih awal ini penting ketika sisi kanan membutuhkan perhitungan lama, misalnya pemanggilan fungsi yang menghitung banyak hal, atau ketika sisi kanan punya efek samping yang tidak boleh berjalan dua kali. Batasan sintaksnya perlu diingat, yaitu ?? tidak boleh digabung langsung dengan || atau && dalam satu ekspresi tanpa tanda kurung.
// new Function menilai teks sebagai kode, sehingga error penguraiannya bisa ditangkap.
try {
new Function("a", "return a ?? 0 || 1");
} catch (error) {
console.log(error.name + ": " + error.message);
}SyntaxError: Unexpected token '||'Penolakan ini bukan keanehan, melainkan perlindungan dari ambiguitas urutan penilaian, dan pesan errornya menunjuk token yang bermasalah. Triknya sederhana, yaitu membaca seluruh teks sebagai kode dengan new Function, sehingga kesalahan yang biasanya menghentikan penguraian berkas menjadi error yang bisa ditangkap. Dalam kode nyata, perbaikannya lebih pendek lagi, beri tanda kurung pada gabungan (a ?? b) || c atau a ?? (b || c), dan maksud ekspresinya menjadi jelas bagi pembaca maupun pengurai.
Kebiasaan yang serupa sudah ditemui pada parameter default, yang juga hanya mengisi bila nilai masukannya undefined dan tetap membiarkan 0 atau string kosong lolos. Perbedaannya ada pada letaknya, parameter default bekerja hanya pada parameter fungsi, sedangkan ?? bekerja di mana pun ekspresi ditulis. Dengan pemisahan ini, fungsi yang sudah menyediakan default pada parameternya tidak perlu mengulang pemeriksaan yang sama di badannya, kecuali nilai null dari sumber luar memang harus dibedakan dari undefined lebih dahulu.
Logical assignment: ||=, &&=, ??=#
Tiga operator logical assignment menyingkat pola periksa-kondisi-lalu-tugaskan menjadi satu tanda. Bentuk a ||= b setara dengan a || (a = b), artinya b hanya ditugaskan bila a bernilai falsy, yaitu nilai yang dianggap salah seperti 0, string kosong, dan null. Bentuk a &&= b menugaskan hanya bila a truthy, sedangkan a ??= b menugaskan hanya bila a bernilai null atau undefined.
const pengaturan = { volume: 0, tema: "", langganan: null };
pengaturan.volume ??= 50; // 0 bukan nullish, tetap 0
pengaturan.tema ||= "terang"; // string kosong falsy, diganti
pengaturan.langganan ??= false; // nullish, diisi
pengaturan.volume ||= 99; // 0 falsy, ikut diganti
console.log(pengaturan);{ volume: 99, tema: 'terang', langganan: false }Empat baris contoh memetakan perbedaan ketiganya secara berurutan. ??= mempertahankan 0 karena 0 adalah data yang sah, sedangkan ||= menggantinya karena 0 dianggap falsy, dan perbedaan inilah yang menentukan pilihan operator. Untuk nilai default yang memang boleh nol atau kosong, ??= adalah pilihan yang tepat, sedangkan ||= cocok untuk memastikan sebuah properti berisi sesuatu apa pun bentuk kosongnya.
Pemakaian &&= lebih jarang dan layak dicatat. Bentuk ini menugaskan hanya bila nilai awalnya truthy, sehingga cocok untuk pola “jika ada, timpa”. Pola pengosongan seperti daftar &&= [] misalnya hanya mengganti daftar bila daftarnya memang sudah ada, sehingga undefined tetap undefined bila memang belum pernah diisi.
structuredClone untuk salinan dalam#
structuredClone menyalin data bersarang sedalam-dalamnya sekaligus mempertahankan tipe khusus seperti Date, yang tidak dapat dilakukan spread maupun JSON. Penyalinan dangkal dari spread sudah dibahas pada topik referensi vs nilai, dan structuredClone menutup sisa masalahnya, yaitu object di dalam object yang masih berbagi referensi setelah penyalinan dangkal. Berkas berikut membandingkannya dengan cara JSON dan dapat dijalankan dengan node penyalinan.js.
// Perbandingan structuredClone dengan penyalinan lewat JSON.
const asli = {
nama: "rapor",
tanggal: new Date(2026, 2, 15),
catatan: undefined,
nilai: [80, [90, 95]],
};
const klon = structuredClone(asli);
console.log(klon.tanggal instanceof Date);
console.log(klon.nilai[1] === asli.nilai[1]);
const json = JSON.parse(JSON.stringify(asli));
console.log(json.tanggal instanceof Date);
console.log(json.tanggal);
console.log("catatan" in json);true
false
false
2026-03-15T00:00:00.000Z
falseDua baris pertama keluaran membuktikan dua janji structuredClone, Date tetap berupa Date, dan array bersarang [90, 95] berhenti berbagi referensi dengan aslinya. Tiga baris berikutnya memperlihatkan keterbatasan penyalinan lewat JSON. Date berubah menjadi string sehingga instanceof Date bernilai false, dan properti catatan yang bernilai undefined hilang tanpa jejak. structuredClone juga menerima Map, Set, dan ArrayBuffer, tetapi punya batasnya, yaitu fungsi tidak bisa dikloning dan penyalinannya melempar DataCloneError.
Penyalinan mendalam bukan berarti selalu diperlukan. Data satu tingkat dengan isi primitif tetap cukup disalin spread, dan menambah structuredClone pada tempat yang tidak bersarang justru menutupi bentuk data yang sebenarnya. Kebiasaan yang baik adalah menuliskan bentuk data lebih dahulu, lalu memilih alat salinannya berdasarkan kedalaman itu. Aturannya, satu tingkat memakai spread, lebih dari itu memakai structuredClone, dan JSON hanya untuk perjalanan data sebagai teks.
Ringkasan#
- Rantai
a ?? b ?? cmengambil nilai cadangan pertama yang non-nullish, sisi kanan hanya dinilai bila perlu, dan campuran??dengan||atau&&wajib diberi tanda kurung. ||=,&&=, dan??=menugaskan hanya bila kondisi logisnya terpenuhi, sehingga0dan string kosong tetap utuh pada??=.structuredClonemenyalin bersarang sedalam-dalamnya dan mempertahankanDate,Map, sertaSet, tetapi menolak fungsi denganDataCloneError.- Penyalinan lewat JSON mengubah bentuk data secara diam-diam, sehingga pola itu tidak cocok dijadikan alat salinan.
Referensi#
- Nullish coalescing operator (??) — MDN Web Docs — Aturan nilai cadangan dan larangan campuran tanpa tanda kurung.
- Logical OR assignment (||=) — MDN Web Docs — Semantik penugasan bersyarat beserta padanan panjangnya.
- structuredClone() — MDN Web Docs — Fungsi penyalinan mendalam dan batasan tipe yang bisa dikloning.