Tur sintaks modern

Nullish coalescing mendalam, logical assignment, dan structuredClone.

Daftar isi

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.

js Contoh: evaluasi yang berhenti lebih awal pada ??
// 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());
text Keluaran
0
sisi kanan dievaluasi
cadangan

Angka 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.

js Contoh: pengurai menolak campuran ?? dengan ||
// 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);
}
text Keluaran
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.

js Contoh: tiga operator penugasan logis pada satu object
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);
text Keluaran
{ 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.

js 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);
text Keluaran
true
false
false
2026-03-15T00:00:00.000Z
false

Dua 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 ?? c mengambil 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, sehingga 0 dan string kosong tetap utuh pada ??=.
  • structuredClone menyalin bersarang sedalam-dalamnya dan mempertahankan Date, Map, serta Set, tetapi menolak fungsi dengan DataCloneError.
  • Penyalinan lewat JSON mengubah bentuk data secara diam-diam, sehingga pola itu tidak cocok dijadikan alat salinan.

Referensi#