USD ($)
$
United States Dollar
Euro Member Countries
India Rupee

Error Handling (try/catch), Optional Chaining (?.), and Nullish Coalescing (??)

Lesson 24/30 | Study Time: 25 Min

Error handling and safe value access are essential for building reliable JavaScript applications.

The try and catch mechanism allows developers to handle runtime errors gracefully without breaking the application flow.

Optional chaining provides a safe way to access deeply nested object properties without causing errors when values are missing.

Nullish coalescing helps define default values only when a variable is null or undefined. Together, these features improve code safety, readability, and robustness.

Error Handling with try/catch

try/catch lets you anticipate errors and handle them gracefully instead of letting your app crash. Introduced in ES3 but refined in modern JS, this pattern is essential for API calls, user inputs, and file operations where things inevitably go wrong.


Basic try/catch Syntax and Flow

The structure wraps risky code in try, catches errors in catch, and optionally runs cleanup in finally.

javascript
try {
// Risky code here
const data = JSON.parse(userInput);
} catch (error) {
console.error('Parse failed:', error.message);
} finally {
// Always runs - cleanup code
}


Key Components


Practical Error Handling Patterns

Real apps deal with multiple error types. Here's how to handle them systematically:


1. Validate inputs first

javascript
function divide(a, b) {
if (typeof b !== 'number' || b === 0) {
throw new Error('Divisor must be non-zero number');
}
return a / b;
}

try {
console.log(divide(10, 'abc')); // Throws custom error
} catch (error) {
alert(`Calculation error: ${error.message}`);
}


2. Network request handling

javascript
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return await response.json();
} catch (error) {
console.error('Fetch failed:', error);
return null; // Graceful fallback
}
}

Error Types Comparision



Pro Tip: Always log error.stack in development but sanitize in production.


Optional Chaining (?.)

Optional chaining (?.)) safely accesses nested object properties without throwing errors when values are null or undefined.

Before ES2020, developers wrote verbose null checks; now one operator handles it elegantly.


The Problem Optional Chaining Solves

Consider this common crash scenario

javascript
// ❌ Crashes if user or address is undefined
const city = user.address.city;


With optional chaining

javascript
// ✅ Returns undefined safely
const city = user?.address?.city;


Chaining Variants


1. ?.: Property access (obj?.prop)
2. ?[ ]: Array index (arr?.[0])
3. ?(): Method calls (func?.())
4. ?.[ ]: Dynamic property access


API Response Handling

javascript
const apiResponse = {
data: {
user: { name: 'Jane', profile: { avatar: null } }
}
};

// Safe nested access
const avatar = apiResponse?.data?.user?.profile?.avatar;
// Returns: null (no crash)

// Array access
const firstItem = apiResponse?.data?.items?.[0]?.name;
// Returns: undefined if items missing

Nullish Coalescing (??)

Nullish coalescing (??) provides default values only when a variable is null or undefined—unlike || which triggers on any falsy value (0, '', false). This distinction prevents bugs in real data scenarios.


Nullish vs Logical OR Operator

The Problem with ||:

javascript
// ❌ Wrong defaults for falsy-but-valid values
const userCount = 0;
const count = userCount || 10; // Becomes 10 (wrong!)


With ??

javascript
// ✅ Respects 0, '', false
const count = userCount ?? 10; // Stays 0 (correct!)

Combined Patterns (?. + ??)

These operators work beautifully together:

javascript
function displayUser(user) {
const name = user?.name ?? 'Anonymous';
const age = user?.age ?? 0;
const isActive = user?.isActive ?? false;

console.log(`${name}, ${age}yo, Active: ${isActive}`);
}

// Works with messy API data:
displayUser({ name: '', age: 0 }); // "Anonymous, 0yo, Active: false"
displayUser({}); // "", 0, false (respects falsy values)


Configuration Objects

javascript
const config = {
theme: null,
timeout: 0,
debug: false
};

const settings = {
theme: config.theme ?? 'light',
timeout: config.timeout ?? 5000, // Keeps 0!
debug: config.debug ?? true
};

Production Best Practices

Combine these features for bulletproof code:


1. Always wrap async operations

javascript
async function safeAPIcall(url) {
try {
const data = await fetch(url).then(r => r.json());
return data?.user?.profile ?? null;
} catch (error) {
console.error('API failed:', error);
return null;
}
}


2. Default parameter objects:

javascript
function createUser({ name, age = 0, email } = {}) {
const safeEmail = email ?? 'no-email@domain.com';
// Safe property access guaranteed
}

Sales Campaign

Sales Campaign

We have a sales campaign on our promoted courses and products. You can purchase 1 products at a discounted price up to 15% discount.