Docs

README

3.9 Nullish Coalescing Operator

Table of Contents

  1. •What Is Nullish Coalescing
  2. •Nullish vs Falsy
  3. •Comparison with OR Operator
  4. •Common Use Cases
  5. •Nullish Coalescing Assignment
  6. •Combining with Optional Chaining
  7. •Operator Precedence

What Is Nullish Coalescing

The nullish coalescing operator (??) returns the right-hand operand when the left-hand operand is null or undefined, otherwise returns the left-hand operand.

Syntax

const result = leftExpr ?? rightExpr;

Basic Behavior

// Returns right side only for null/undefined
null ?? 'default'; // "default"
undefined ?? 'default'; // "default"

// Returns left side for everything else (including falsy values!)
0 ?? 'default'; // 0
'' ?? 'default'; // ""
false ?? 'default'; // false
NaN ?? 'default'; // NaN

Visual Representation

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│                  value ?? default                           │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                             │
│  Is value null or undefined?                               │
│         │                                                   │
│     ā”Œā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”                                              │
│     │       │                                              │
│    YES      NO                                              │
│     │       │                                              │
│     ā–¼       ā–¼                                              │
│  return   return                                           │
│  default  value                                            │
│                                                             │
│  Only null and undefined trigger the default!              │
│                                                             │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Nullish vs Falsy

Understanding the Difference

Nullish values: Only null and undefined

Falsy values: null, undefined, 0, "", false, NaN

// Falsy values in JavaScript
Boolean(null); // false - also nullish
Boolean(undefined); // false - also nullish
Boolean(0); // false - NOT nullish
Boolean(''); // false - NOT nullish
Boolean(false); // false - NOT nullish
Boolean(NaN); // false - NOT nullish

Comparison Table

ValueIs Falsy?Is Nullish?|| returns default?? returns default
nullāœ…āœ…āœ…āœ…
undefinedāœ…āœ…āœ…āœ…
0āœ…āŒāœ…āŒ
""āœ…āŒāœ…āŒ
falseāœ…āŒāœ…āŒ
NaNāœ…āŒāœ…āŒ

Comparison with OR Operator

The Problem with OR (||)

// OR returns the right side for any falsy value
const count = 0;
const displayCount = count || 'No items';
console.log(displayCount); // "No items" - WRONG! We wanted 0!

const name = '';
const displayName = name || 'Anonymous';
console.log(displayName); // "Anonymous" - But empty string was intentional!

The Solution with Nullish Coalescing (??)

// ?? only returns right side for null/undefined
const count = 0;
const displayCount = count ?? 'No items';
console.log(displayCount); // 0 - Correct!

const name = '';
const displayName = name ?? 'Anonymous';
console.log(displayName); // "" - Respects empty string!

Side-by-Side Comparison

const examples = [null, undefined, 0, '', false, 'hello'];

console.log('Value\t\t|| result\t?? result');
console.log('─'.repeat(40));

examples.forEach((val) => {
  const orResult = val || 'default';
  const nullishResult = val ?? 'default';
  console.log(`${String(val)}\t\t${orResult}\t\t${nullishResult}`);
});

// Output:
// Value         || result    ?? result
// ────────────────────────────────────────
// null          default      default
// undefined     default      default
// 0             default      0
//               default
// false         default      false
// hello         hello        hello

When to Use Each

Use CaseUse ??Use ||
Default for missing dataāœ…
Default for any falsy valueāœ…
Preserving 0 as validāœ…
Preserving "" as validāœ…
Preserving false as validāœ…
Fallback for "empty" valuesāœ…

Common Use Cases

1. Function Default Parameters

// ?? is better for optional parameters with valid falsy values
function createUser(name, age, isActive) {
  return {
    name: name ?? 'Guest',
    age: age ?? 0, // 0 is a valid age!
    isActive: isActive ?? true, // false is a valid status!
  };
}

console.log(createUser('John', 0, false));
// { name: "John", age: 0, isActive: false }

console.log(createUser('John'));
// { name: "John", age: 0, isActive: true }

2. Configuration Objects

const userConfig = {
  theme: 'dark',
  fontSize: 0, // User wants smallest size
  showTips: false, // User disabled tips
};

const defaultConfig = {
  theme: 'light',
  fontSize: 14,
  showTips: true,
};

// With ?? - respects 0 and false
const config = {
  theme: userConfig.theme ?? defaultConfig.theme,
  fontSize: userConfig.fontSize ?? defaultConfig.fontSize,
  showTips: userConfig.showTips ?? defaultConfig.showTips,
};

console.log(config);
// { theme: 'dark', fontSize: 0, showTips: false }

3. API Response Handling

function displayUserInfo(response) {
  const name = response.data?.user?.name ?? 'Unknown User';
  const postCount = response.data?.user?.posts ?? 0;
  const bio = response.data?.user?.bio ?? 'No bio provided';

  return `${name} has ${postCount} posts. Bio: ${bio}`;
}

// Works correctly even with empty strings or zero
const response = {
  data: {
    user: {
      name: 'John',
      posts: 0, // New user, no posts yet
      bio: '', // Empty bio
    },
  },
};

console.log(displayUserInfo(response));
// "John has 0 posts. Bio: "  (preserves 0 and "")

4. Chained Nullish Coalescing

const a = null;
const b = undefined;
const c = 0;
const d = 'value';

// Returns first non-nullish value
const result = a ?? b ?? c ?? d;
console.log(result); // 0 (c is first non-nullish)

Nullish Coalescing Assignment

Basic Syntax (??=)

The nullish coalescing assignment operator assigns the right-hand value only if the left-hand variable is nullish.

let x = null;
x ??= 'default';
console.log(x); // "default"

let y = 0;
y ??= 'default';
console.log(y); // 0 (not reassigned - 0 is not nullish)

Practical Examples

// Initialize optional properties
const settings = {};

settings.theme ??= 'light';
settings.fontSize ??= 14;
settings.volume ??= 50;

console.log(settings);
// { theme: 'light', fontSize: 14, volume: 50 }

// Won't override existing values
settings.theme = 'dark';
settings.theme ??= 'light'; // Won't change
console.log(settings.theme); // 'dark'

Lazy Initialization

let cachedValue;

function getCachedValue() {
  cachedValue ??= expensiveComputation();
  return cachedValue;
}

function expensiveComputation() {
  console.log('Computing...');
  return 42;
}

getCachedValue(); // "Computing..." → 42
getCachedValue(); // Returns 42 (no recomputation)

Combining with Optional Chaining

Perfect Partners

Nullish coalescing (??) and optional chaining (?.) work great together:

const user = {
  profile: {
    // name is missing
    settings: {
      notifications: false,
    },
  },
};

// Safe access with default value
const userName = user?.profile?.name ?? 'Anonymous';
console.log(userName); // "Anonymous"

// Respects false as a valid value
const notifications = user?.profile?.settings?.notifications ?? true;
console.log(notifications); // false (not replaced with default)

Common Pattern

function getConfig(options) {
  return {
    host: options?.server?.host ?? 'localhost',
    port: options?.server?.port ?? 3000,
    ssl: options?.server?.ssl ?? false,
    timeout: options?.server?.timeout ?? 5000,
  };
}

console.log(getConfig({}));
// { host: 'localhost', port: 3000, ssl: false, timeout: 5000 }

console.log(getConfig({ server: { port: 8080, ssl: true } }));
// { host: 'localhost', port: 8080, ssl: true, timeout: 5000 }

Operator Precedence

Precedence Rules

?? has lower precedence than most operators, but there's a special rule:

You cannot directly mix ?? with && or || without parentheses.

// āŒ SyntaxError - ambiguous without parentheses
// const result = a || b ?? c;
// const result = a && b ?? c;

// āœ… Use parentheses to clarify intent
const result1 = (a || b) ?? c; // OR first, then nullish
const result2 = a || (b ?? c); // Nullish first, then OR
const result3 = (a && b) ?? c; // AND first, then nullish

Why This Rule Exists

// Without the rule, this would be ambiguous:
const value = null;
const fallback = false;
const default = "default";

// Does this mean:
// (null || false) ?? "default" → "default"
// or
// null || (false ?? "default") → false

Safe Combinations

// Arithmetic operators - OK
const a = null;
const result = (a ?? 0) + 10; // 10

// Comparison operators - OK
const value = null ?? 5;
const isPositive = value > 0; // true

// Ternary operator - OK
const message = (value ?? 0) > 0 ? 'positive' : 'not positive';

Summary

Aspect?? (Nullish Coalescing)|| (Logical OR)
Triggers onnull, undefinedAll falsy values
Preserves 0āœ… YesāŒ No
Preserves ""āœ… YesāŒ No
Preserves falseāœ… YesāŒ No
Use forNull/undefined defaultsFalsy fallbacks

Quick Reference

// Nullish coalescing
value ?? default          // Returns default only for null/undefined

// Nullish assignment
variable ??= value        // Assigns only if variable is null/undefined

// With optional chaining
obj?.prop ?? default      // Safe access with default

// Must use parentheses with && or ||
(a || b) ?? c            // OK
(a && b) ?? c            // OK
a || b ?? c              // SyntaxError!

Next Steps

After mastering nullish coalescing, proceed to:

  1. •3.10 Optional Chaining - Safe property access
  2. •Combine both operators for robust data handling
  3. •Refactor existing code to use ?? where appropriate
README - JavaScript Tutorial | DeepML