Belajar dengan membaca secara berurutan

null dan undefined — Membaca dengan Aman Pakai ?. dan ??

Pelajari beda null dan undefined, lalu cara membaca object nested dengan aman lewat ?. dan ??.

Menampilkan data order dari server, kamu akan menemui address yang tidak pernah diisi, atau metode pembayaran yang belum dipilih. JavaScript punya 2 value untuk kondisi "tidak ada apa-apa di sini" ini — undefined dan null — dan pembacaan yang gagal menghentikan proses dengan TypeError.

Artikel ini membahas perbedaan keduanya, membaca lewat langkah yang hilang tanpa berhenti, dan menerapkan default value saat sesuatu hilang.

2 Value yang Berarti Tidak Ada Apa-Apa — undefined dan null

undefined (value yang otomatis diisi JavaScript saat belum ada yang di-assign) muncul dengan sendirinya — kamu tidak perlu meng-assign-nya sendiri. Kamu sudah melihatnya dikembalikan dari membaca melewati akhir array atau key object yang tidak terdaftar, dan variable yang cuma dideklarasikan juga masuk kategori ini.

  • Variable yang cuma dideklarasikan, tanpa pernah diberi value, seperti let couponCode;
  • Key yang tidak terdaftar di object, seperti order.customer (sudah dilihat sebelumnya)
  • Index di luar jangkauan pada array 2 element, seperti tags[5] (sudah dilihat sebelumnya)

null (value yang sengaja di-assign penulisnya untuk menandakan kekosongan), di sisi lain, tidak pernah muncul dengan sendirinya. Saat kamu mau ketiadaan value itu sendiri jadi data — "belum ada shipping address yang dipilih," "tidak ada coupon yang dipakai" — kamu meng-assign null sendiri.

JSON yang kembali dari API juga bisa membawa null untuk menandakan sebuah field kosong.

Karena keduanya value berbeda, === mengembalikan false saat membandingkannya. ==, meski begitu, memperlakukan keduanya sebagai sama dan mengembalikan true.

Saat menulis pengecekan, sengaja pilih mana yang kamu maksud dan cek hanya sisi itu, seperti === null, atau serahkan sepenuhnya ke ?. dan ??, yang dibahas mulai dari sini.

Siapa yang Menaruh undefined dan null
Baca variableyang belum diisiJavaScriptmengisinyaundefinedBaca key hilangatau index salahJavaScriptmengisinyaundefinedMau menandakankekosonganPenulisnyameng-assignnullDiisi otomatisDi-assign penulisnya
Di 2 baris atas, undefined adalah value yang diisi otomatis JavaScript; di baris bawah, null adalah value yang di-assign penulisnya.
let couponCode;                 // cuma dideklarasikan, tanpa value
console.log(couponCode);        // undefined

const order = { orderId: "ORD-1105", total: 12800 };
console.log(order.customer);    // undefined (key yang tidak terdaftar)

const tags = ["Limited", "Preorder"];
console.log(tags[5]);           // undefined (index di luar jangkauan)

// null di-assign oleh penulisnya
let shippingAddress = null;     // belum ada shipping address yang dipilih
console.log(shippingAddress);   // null

console.log(shippingAddress === undefined);  // false (keduanya value berbeda)
console.log(shippingAddress == undefined);   // true (== memperlakukan keduanya sama)

Tidak Berhenti Saat Langkah Nested Hilang — Optional Chaining ?.

Data yang kembali dari API tidak selalu punya tiap field terisi. Kode yang membaca dalam, seperti order.customer.address.city, berhenti begitu ada 1 order yang tidak punya address di tengah jalan.

Inilah saatnya kamu mau pembacaannya sendiri tidak gagal — terus jalan sebagai "tidak ada apa-apa" sebagai gantinya.

Saat order.customer.address adalah undefined, mencoba membaca .city setelahnya melempar TypeError: Cannot read properties of undefined (reading 'city'). Langkah pembacaan ke-1 lancar, tapi berhenti di ke-2.

Untuk itulah optional chaining ada (operator ?., yang mengembalikan undefined tanpa membaca lebih jauh kalau sisi kirinya null atau undefined). Tulis address?.city, dan .city hanya dibaca kalau address punya value — kalau tidak, pembacaannya berhenti di situ dan mengembalikan undefined.

Saat mengirim key lewat [], tulis sebagai ?.[field].

Di Mana ?. Berhenti Membaca
customerpunya value?.addresspunya value?.cityAustinshippingnull?.carrierberhenti di siniundefinedpaymentkey tidak ada?.methodberhenti di siniundefined
Kalau ada value-nya, dia terus jalan. Begitu ketemu null, undefined, atau key yang hilang, dia berhenti dan mengembalikan undefined tanpa membaca sisanya.
const order = {
  orderId: "ORD-1105",
  customer: { name: "Ryan Cole" },
};

// address hilang, jadi membaca city setelahnya akan berhenti
// console.log(order.customer.address.city);
// TypeError: Cannot read properties of undefined (reading 'city')

// Sisipkan ?. dan pembacaannya berhenti, mengembalikan undefined
console.log(order.customer.address?.city);   // undefined

// Kalau ada value-nya, terus jalan seperti biasa
console.log(order.customer.name);            // Ryan Cole

// Kirim key lewat variable dengan ?.[]
const field = "city";
console.log(order.customer.address?.[field]);   // undefined

Pakai Ini Hanya di Field yang Memang Bisa Hilang

Taruh ?. di tiap langkah, dan bahkan nama key yang typo bisa lolos jadi undefined tanpa error. Lewati field yang dijamin ada, dan pakai ini hanya tepat sebelum field yang memang bisa hilang secara sah — dengan begitu error yang sebenarnya kamu mau tangkap tetap menghentikan eksekusi.

Baca value dari object berbentuk response API order, tanpa berhenti saat field hilang. response sudah dideklarasikan, dan customer selalu ada.

① Tampilkan kota shipping, ditulis supaya tidak berhenti bahkan kalau ada yang hilang di tengah jalan.

② Tampilkan nama kurir, shipping.carrier, dengan syntax yang sama.

③ Tampilkan metode pembayaran, payment.method, dengan syntax yang sama.

④ Baca nama field dari variable, dan tampilkan kode pos shipping.

(Kalau berjalan dengan benar, penjelasan akan muncul.)

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Menyiapkan Default Value — ?? vs ||

Daripada menampilkan undefined polos saat sebuah field hilang, biasanya kamu mau menampilkan default — "Guest," "20 item."

Pakai || untuk ini, meski begitu, kadang value yang sebenarnya ada malah diganti dengan default-nya. Jumlah stok 0, atau field catatan kosong, adalah contohnya.

null dan undefined bersama disebut nullish. Pakai Nullish coalescing operator (operator ??, yang mengembalikan sisi kanan hanya kalau sisi kiri nullish), dan 0, string kosong, atau false tetap persis apa adanya.

|| mengembalikan sisi kanan kapan pun sisi kirinya falsy, jadi dia tidak bisa membedakan "tidak ada value" dari "value-nya 0." Saat tujuanmu menerapkan default, ?? menghindari penggantian yang tidak diinginkan itu.

?? dan || Berbeda pada Value Falsy
stock adalah 0|| cek diaganti yang falsy20digantistock adalah 0?? cek diaganti hanya null0tidak berubahstock adalah null?? cek diaganti hanya null20diganti
Hasilnya cuma berbeda saat stock adalah 0. ?? hanya mengganti null dan undefined, jadi 0 tetap jadi value-nya.
Value Sisi KiriYang Dikembalikan ||Yang Dikembalikan ??
nulldefault-nyadefault-nya
undefineddefault-nyadefault-nya
0default-nyatetap 0
string kosongdefault-nyatetap string kosong
falsedefault-nyatetap false
const settings = { displayName: null, itemsPerPage: 0 };

// ?? mengembalikan sisi kanan hanya kalau kiri null atau undefined
console.log(settings.displayName ?? "Guest");   // Guest
console.log(settings.itemsPerPage ?? 20);        // 0 (tetap apa adanya)

// || mengembalikan sisi kanan kapan pun kiri falsy, jadi bahkan 0 pun diganti
console.log(settings.itemsPerPage || 20);        // 20

// Key yang tidak terdaftar jatuh ke default keduanya
console.log(settings.language ?? "en");          // en
console.log(settings.language || "en");          // en

Perhatikan menulis ?? dan || bersebelahan tanpa tanda kurung, seperti displayName ?? "Guest" || "Anonymous", adalah syntax error — JavaScript tidak bisa memutuskan mana yang dievaluasi dulu. Untuk memakai keduanya, pisahkan dengan tanda kurung, seperti (displayName ?? "Guest") || "Anonymous".

Terapkan default pada tiap field object user settings, membangun value yang akan kamu tampilkan. Field yang sudah punya value harus tetap tidak berubah. userSettings sudah dideklarasikan.

① Terapkan default "Guest" ke display name dan tampilkan.

② Terapkan default "en" ke display language dan tampilkan.

③ Terapkan default 20 ke jumlah item-per-halaman dan tampilkan.

④ Terapkan default false ke setting notifications yang tidak terdaftar dan tampilkan.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Jangan Biarkan Default Menghapus 0 atau String Kosong

Jumlah stok 0, discount rate 0, catatan kosong — semuanya terhitung "ada value-nya." Terapkan default dengan ||, dan karena semuanya falsy, mereka diganti dengan default-nya, membuat ketidakcocokan seperti item habis stok tampil seolah masih ada. Pakai ?? saat yang kamu pedulikan cuma apakah ada value sama sekali.

Bandingkan bagaimana tampilan berubah tergantung operator default mana yang kamu pakai, untuk produk dengan stok 0 dan catatan kosong. product sudah dideklarasikan.

① Terapkan default 10 ke jumlah stok dengan || dan tampilkan.

② Terapkan default 10 yang sama ke jumlah stok dengan ?? dan tampilkan.

③ Terapkan default "No notes" ke catatannya dengan ||, bungkus dengan kurung siku, dan tampilkan.

④ Terapkan default "No notes" yang sama ke catatannya dengan ??, bungkus dengan kurung siku, dan tampilkan.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output

Tidak Memanggil Sesuatu yang Tidak Ada — Pemanggilan ?.()

Dalam pemrosesan order, kadang kamu menyimpan "apa yang dilakukan saat sukses" dan "apa yang dilakukan saat gagal" di dalam sebuah object, memanggilnya saat perlu. Panggil field yang belum diisi apa pun, meski begitu, dan itu berhenti dengan TypeError: handlers.onError is not a function — jadi kamu perlu cara memanggilnya hanya saat itu benar-benar ada.

Function yang dibahas di artikel 3 juga bisa hidup di dalam object sebagai value sebuah property. () => ... di contoh berikutnya adalah syntax untuk membuat function di tempat — syntax itu sendiri dibahas di kategori syntax, jadi di sini cukup fokus pada bagaimana hasilnya berubah tergantung apakah sebuah function ada di property-nya.

Panggil property yang mungkin memegang function sebagai handlers.onError?.(), dan saat onError adalah null atau undefined, pemanggilannya dilewati dan undefined kembali sebagai gantinya.

?.() Melewati Pemanggilan Saat Tidak Ada yang Terdaftar
onSuccesssebuah functionPanggil dengan?.()BerjalanonErrornullPanggil dengan?.()Dilewati,undefinedonErrornullDipanggiltanpa ?.Berhenti denganTypeError
Panggil kalau sebuah function ada di sana; kembalikan undefined tanpa memanggil apa pun kalau null. Panggil tanpa ?. dan itu berhenti dengan TypeError.
const handlers = {
  onSuccess: () => console.log("Order confirmed"),
  onError: null,
};

// Ada function-nya, jadi dipanggil
handlers.onSuccess?.();              // Order confirmed

// null, jadi pemanggilannya dilewati dan undefined kembali
console.log(handlers.onError?.());   // undefined

// Memanggil tanpa ?. menghentikan eksekusi
// handlers.onError();
// TypeError: handlers.onError is not a function

Bandingkan memanggil dengan ?. dengan memanggil tanpanya, memakai object yang membundel handler pemrosesan order. handlers sudah dideklarasikan.

① Panggil success handler memakai syntax yang melewati pemanggilan kalau tidak terdaftar.

② Panggil failure handler dengan cara yang sama, dan tampilkan apa pun yang kembali.

③ Panggil failure handler yang sama tanpa ?., dan lihat message apa yang menghentikan eksekusi.

JavaScript / TypeScript Editor

Jalankan kode untuk melihat output
QUIZ

Cek Pemahaman

Jawab setiap pertanyaan satu per satu.

Soal 1Tulis let couponCode; dan bacalah tanpa meng-assign value. Berapa value variable itu?

Soal 2Saat sisi kiri ?. adalah null atau undefined, apa yang terjadi pada sisa rantainya?

Soal 3Dengan const discountRate = 0;, apa yang dikembalikan discountRate || 5 dan discountRate ?? 5 masing-masing?