Loading...
Loading...
Access nested values safely. Returns undefined instead of throwing errors.
Module 9 · Modern JavaScript (ES6+)
ES2015 and later additions transformed how JavaScript is written. let and const, template literals, modules, spread/rest, optional chaining, and nullish coalescing are now standard in every modern codebase.
Learn Optional Chaining in JavaScript — covering Property Access, Method Calls, Dynamic Properties, Short-Circuiting with interactive visual examples and step-by-step explanations.
ES2015 (ES6) and the releases that followed added the syntax modern JavaScript is written in today. let and const replaced var, template literals replaced string concatenation, and import/export replaced global script tags.
This module covers the ES6+ features you will see in every codebase and job interview. Each chapter shows the old pattern alongside the modern equivalent so you can read legacy code and write idiomatic JavaScript.
Understanding optional chaining is essential for every JavaScript developer. It shows up in frontend UI code, backend APIs, and framework internals — and getting it wrong leads to bugs that are hard to trace. This chapter builds intuition with visuals so the behavior sticks.
Use ?. to safely access nested properties.
// The problem: const user = { name: "Alice", address: null }; user.address.city; // ❌ TypeError: Cannot read properties of null // Old fix — verbose checking: const city = user && user.address && user.address.city; // Optional chaining — clean and safe: const city = user?.address?.city; // undefined (no error!) // How it works: // ?. checks if the left side is null/undefined // If yes → returns undefined immediately // If no → continues to the next property const data = { user: { profile: { avatar: "pic.jpg" } } }; data?.user?.profile?.avatar; // "pic.jpg" data?.user?.settings?.theme; // undefined (settings doesn't exist) data?.missing?.deep?.value; // undefined (short-circuits at missing)
Safely call methods that might not exist.
// Call a method only if it exists: const user = { name: "Alice", greet() { return "Hello!"; } }; user.greet?.(); // "Hello!" user.goodbye?.(); // undefined (doesn't throw) // Useful with optional callbacks: function fetchData(url, onSuccess, onError) { fetch(url) .then(res => res.json()) .then(data => onSuccess?.(data)) // call only if provided .catch(err => onError?.(err)); // call only if provided } // Without optional chaining: // if (onSuccess) onSuccess(data); // With: onSuccess?.(data); // On DOM elements: document.querySelector("#modal")?.remove(); // Removes if found, does nothing if null
Works with bracket notation too.
// Optional bracket access: const data = { users: ["Alice", "Bob"] }; data?.users?.[0]; // "Alice" data?.admins?.[0]; // undefined (admins doesn't exist) // With variables: const key = "email"; user?.[key]; // user.email if user exists, else undefined // Array access: const first = arr?.[0]; // safe first element const last = arr?.[arr.length - 1]; // safe last element // Combining all forms: const result = api ?.response ?.data ?.items?.[0] ?.getName?.(); // Each ?. checks null/undefined at that step
Evaluation stops at the first null/undefined.
// Once ?. hits null/undefined, the ENTIRE chain returns undefined: const obj = null; obj?.a.b.c; // undefined // Does NOT throw even though .a.b.c would normally error // ?. short-circuits — everything after is skipped // But be careful — only the chain after ?. is protected: const x = null; x.a?.b; // ❌ TypeError! (x.a throws before ?. is reached) x?.a?.b; // ✓ undefined (safe)
Once optional chaining encounters null/undefined, the entire rest of the expression evaluates to undefined.
Real-world patterns with optional chaining.
// 1. API response handling: const userName = response?.data?.user?.name ?? "Unknown"; const avatar = response?.data?.user?.avatar?.url; // 2. Config with nested optional values: const port = config?.server?.port ?? 3000; const debug = config?.features?.debug ?? false; // 3. DOM traversal: const text = document.querySelector(".title")?.textContent; const parent = element?.parentElement?.closest(".container"); // 4. Event handling: element?.addEventListener("click", handler); event?.target?.closest("button")?.dataset?.action; // 5. Map/WeakMap access: const cached = cache?.get(key)?.value; // 6. JSON parsing safety: const parsed = JSON.parse(text); const nested = parsed?.results?.[0]?.metadata?.tags ?? []; // 7. Combine with nullish coalescing (??): const theme = user?.preferences?.theme ?? "system"; const items = cart?.items?.length ?? 0;
Common questions about optional chaining.