Optional chaining (?.), bir özelliğe erişirken ya da bir fonksiyonu çağırırken soldaki değer null veya undefined ise hata fırlatmak yerine işlemi durdurup undefined döndürür. Nullish coalescing (??) ise soldaki değer yalnızca null veya undefined olduğunda sağdaki varsayılan değeri verir. ??= da aynı mantıkla, değişken boşsa atama yapar.

Bu üç operatör birlikte, iç içe ve eksik olabilen verilerle (API yanıtları, ayar dosyaları, form verileri) çalışırken hem kısa hem güvenli kod yazmanızı sağlar. En önemli fark || operatörüyle ilgilidir: ||, 0 ve boş metin gibi geçerli değerleri de "yok" sayar. Aşağıdaki tüm örnekler Node.js 24 ile çalıştırıldı.

?. ile güvenli özellik erişimi

?. ile güvenli özellik erişimi: Kısa devre: zincirin geri kalanı hiç çalışmaz, Fonksiyon çağrısında ?. ve sınırları

Üç biçimi vardır: obj?.ozellik, obj?.[ifade] ve fonksiyon?.(argumanlar). Köşeli parantezli biçim özellikle dizi indeksleri ve değişken anahtarlar için kullanışlıdır.

javascript
const kullanici = {
  ad: "Zeynep",
  adres: { sehir: "İzmir" },
  etiketler: ["yeni"],
};

console.log(kullanici.adres?.sehir); // İzmir
console.log(kullanici.fatura?.sehir); // undefined
console.log(kullanici.etiketler?.[0]); // yeni
console.log(kullanici.bildir?.("merhaba")); // undefined

try {
  kullanici.fatura.sehir;
} catch (e) {
  console.log(e.message); // Cannot read properties of undefined (reading 'sehir')
}

?. öncesinde yaygın olan obj.a && obj.a.b kalıbının bir zaafı vardır: obj.a değeri 0 veya boş metin gibi falsy ama geçerli bir değerse ifade o değerde durur. ?. yalnızca null ve undefined için durur.

Kısa devre: zincirin geri kalanı hiç çalışmaz

Soldaki değer nullish olduğunda yalnızca o adım değil, aynı zincirin devamındaki tüm erişimler ve köşeli parantez içindeki ifadeler de atlanır. Zinciri parantezle bölerseniz bu koruma parantezin dışına taşmaz.

javascript
const bos = null;
let i = 0;

bos?.[i++];
console.log(i); // 0 (i++ hiç çalışmadı)
console.log(bos?.a.b.c); // undefined (a.b.c de atlandı)

try {
  (bos?.a).b;
} catch (e) {
  console.log(e.constructor.name); // TypeError
}

Fonksiyon çağrısında ?. ve sınırları

nesne.metot?.() yalnızca metot null veya undefined ise çağrıyı atlar. Özellik var ama fonksiyon değilse yine TypeError alırsınız. Nesnenin kendisi de boş olabiliyorsa her iki adıma da ?. koymanız gerekir: nesne?.metot?.(). İsteğe bağlı geri çağırma fonksiyonlarında bu kalıp çok işe yarar; geri çağırma kavramı için callback yazısına bakabilirsiniz.

javascript
const o = { yontem: 42 };
try {
  o.yontem?.();
} catch (e) {
  console.log(e.message); // o.yontem is not a function
}

function kaydet(veri, hataOlursa) {
  try {
    throw new Error("disk dolu");
  } catch (e) {
    hataOlursa?.(e.message); // verilmediyse sessizce geçer
  }
}
kaydet({}); // çıktı yok
kaydet({}, (m) => console.log("Hata:", m)); // Hata: disk dolu

?? ile varsayılan değer: || operatöründen farkı

a ?? b, a null veya undefined ise b, değilse a döndürür. a || b ise a herhangi bir falsy değer olduğunda (0, "", NaN, false, null, undefined) b verir. Sayfa başına kayıt sayısı, indirim oranı veya boş bırakılmış bir açıklama gibi alanlarda bu fark doğrudan hataya dönüşür.

javascript
const ayar = { sayfaBasi: 0, baslik: "", tema: null };

console.log(ayar.sayfaBasi || 20); // 20  (0 kayboldu)
console.log(ayar.sayfaBasi ?? 20); // 0
console.log(JSON.stringify(ayar.baslik || "Adsız")); // "Adsız"
console.log(JSON.stringify(ayar.baslik ?? "Adsız")); // ""
console.log(ayar.tema ?? "açık"); // açık
console.log(ayar.dil ?? "tr"); // tr
Sol değera || "x"a ?? "x"
nullxx
undefinedxx
0x0
"" (boş metin)x""
falsexfalse
NaNxNaN
"metin"metinmetin

Falsy kavramı ve tip dönüşümünün geri kalanı tip dönüşümü yazısında anlatılıyor.

?? de kısa devre yapar

Sol taraf nullish değilse sağ taraf hiç değerlendirilmez. Varsayılan değeri pahalı bir fonksiyon üretiyorsa bu, gereksiz çalışmayı önler.

javascript
function varsayilan() {
  console.log("varsayilan() çalıştı");
  return "yedek";
}

console.log(undefined ?? varsayilan());
// varsayilan() çalıştı
// yedek
console.log(false ?? varsayilan()); // false

?. ve ?? birlikte

İkisi doğal olarak birleşir: önce güvenli erişim, sonra eksikse varsayılan değer.

javascript
function sehirGetir(musteri) {
  return musteri?.adres?.sehir ?? "Bilinmeyen şehir";
}

console.log(sehirGetir({ adres: { sehir: "Bursa" } })); // Bursa
console.log(sehirGetir({ ad: "Can" })); // Bilinmeyen şehir
console.log(sehirGetir(undefined)); // Bilinmeyen şehir

Gerçek senaryo: API yanıtındaki ayarları okumak

Bir servisten gelen JSON yanıtında bazı alanlar hiç gelmeyebilir, bazıları null olabilir, bazıları da bilerek false veya 0 olarak ayarlanmıştır. Aşağıdaki örnekte kullanıcı bildirimleri kapatmış (false), dil tercihi boş (null) ve profil bilgisi hiç yok. ?. eksik ara nesnelerden korur, ?? yalnızca gerçekten boş olanlara varsayılan değer verir:

javascript
const yanit = {
  veri: {
    kullanici: { ad: "Ece", ayarlar: { bildirim: false, dil: null } },
  },
};

const k = yanit.veri?.kullanici;
const bildirim = k?.ayarlar?.bildirim ?? true;
const dil = k?.ayarlar?.dil ?? "tr";
const foto = k?.profil?.foto ?? "/varsayilan.png";
console.log(bildirim, dil, foto); // false tr /varsayilan.png

// || ile yazılsaydı kullanıcının tercihi kaybolurdu:
console.log(k?.ayarlar?.bildirim || true); // true

Son satırdaki hata kolay gözden kaçar: kullanıcı bildirimleri kapattığı hâlde kod onları açık sayar. Boolean ve sayısal ayarlarda varsayılan değer verirken ?? tercih etmek, bu tür sessiz hataların önüne geçer. JSON verisini ayrıştırma adımı için JSON.parse yazısına bakabilirsiniz.

??= ile yalnızca boşsa atama

x ??= y, x ?? (x = y) ile eşdeğerdir; tek farkı x ifadesinin bir kez değerlendirilmesidir. Sol taraf boş değilse atama yapılmaz, sağ taraf hiç çalıştırılmaz ve setter tetiklenmez. Ayar nesnelerine varsayılan değer yerleştirmek için idealdir; parametre varsayılanlarından farklı olarak null değerini de "boş" sayar.

javascript
function ayarla(secenek) {
  secenek.zamanAsimi ??= 5000;
  secenek.deneme ??= 3;
  return secenek;
}

console.log(ayarla({ zamanAsimi: 0 })); // { zamanAsimi: 0, deneme: 3 }
console.log(ayarla({ deneme: null })); // { deneme: 3, zamanAsimi: 5000 }

function selamla(ad = "misafir") {
  return ad;
}
console.log(selamla(undefined), selamla(null)); // misafir null

Son iki satır önemli bir farkı gösteriyor: varsayılan parametre yalnızca undefined için devreye girer, null geçildiğinde null kalır. Parametre varsayılanlarının ayrıntısı default ve rest parametreler yazısında.

Yaygın hatalar

Yaygın hatalar: Atamanın solunda ?. kullanmak, Tanımlanmamış değişkende ?. kullanmak, Her yere ?. koymak, new ve etiketli şablonla birleştirmek

?? ile || operatörünü parantezsiz karıştırmak

Dil, ?? operatörünün || veya && ile parantezsiz aynı ifadede kullanılmasına izin vermez; kod çalışmadan önce SyntaxError alırsınız. Önceliği parantezle açıkça belirtin.

javascript
// null || undefined ?? "foo";   // SyntaxError
console.log((null || undefined) ?? "foo"); // foo

Diğer tuzaklar

  • Atamanın solunda ?. kullanmak: obj?.ozellik = 1 geçersizdir (SyntaxError). Önce nesnenin var olduğunu kontrol edin veya ??= ile oluşturun.
  • Tanımlanmamış değişkende ?. kullanmak: tanimsizDegisken?.x yine ReferenceError verir. ?. yalnızca değeri undefined olan, ama bildirilmiş isimleri korur.
  • Her yere ?. koymak: Hiç boş olmaması gereken bir değeri ?. ile okumak, hatayı gizleyip sorunu ileriye taşır. Yalnızca gerçekten isteğe bağlı olan alanlarda kullanın.
  • new ve etiketli şablonla birleştirmek: new Map?.() ve String?.raw`...` sözdizimi hatasıdır.

Sık Sorulan Sorular

?. ne döndürür, null mu undefined mı?

Soldaki değer null olsa bile kısa devre sonucu her zaman undefined olur.

|| kullanmak ne zaman hâlâ doğru?

Boş metin, 0 veya false değerlerini de "değer yok" saymak istiyorsanız || doğru tercihtir. Örneğin boş bırakılmış bir arama kutusunu varsayılan metinle değiştirmek istiyorsanız || işinizi görür.

??= ile ||= arasındaki fark nedir?

??= yalnızca null ve undefined için atar; ||= tüm falsy değerler için atar. 0 geçerli bir değerse ??= kullanın.

Bu operatörler eski ortamlarda çalışır mı?

Güncel tarayıcılar ve Node.js 24 destekler. Hedeflediğiniz ortamlar için MDN uyumluluk tablosuna bakın.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: JavaScript öğrenme rehberi · Tip dönüşümü · Eşitlik operatörleri · Default ve rest parametreler · Destructuring ve spread · Sık JavaScript hata mesajları