DocsHub
Objects

Nullish Coalescing

Learn how to provide fallback values cleanly using the nullish coalescing operator in JavaScript.

Nullish Coalescing

We already covered nullish coalescing in the Short Circuit Operators topic under Control Flow. You know what ?? does and why it exists.

This topic is short — it focuses specifically on how ?? is used with objects, and how it pairs with optional chaining to handle missing data cleanly.


Quick Recap

?? returns the right side only when the left side is null or undefined — not for any other falsy value like 0, false, or "".

console.log(null ?? "default");      // default
console.log(undefined ?? "default"); // default
console.log(0 ?? "default");         // 0 — 0 is valid, kept
console.log("" ?? "default");        // "" — empty string is valid, kept
console.log(false ?? "default");     // false — valid, kept

This makes it far more precise than || for fallback values on object properties.


Why It Matters With Objects

Object properties are often optional — some users have a bio, some do not. Some products have a discount, some have a price of 0. Using || for these fallbacks causes bugs because it treats valid falsy values as missing.

const product = {
  name: "Budget Cable",
  price: 0,        // genuinely free or zero cost
  inStock: false,  // genuinely not in stock
  description: ""  // genuinely empty
};

// ❌ || treats 0, false, "" as missing — wrong results
console.log(product.price       || "Price not set");   // "Price not set" — wrong, 0 is valid
console.log(product.inStock     || "Status unknown");  // "Status unknown" — wrong, false is valid
console.log(product.description || "No description");  // "No description" — wrong, "" might be intentional

// ✅ ?? only falls back for null and undefined
console.log(product.price       ?? "Price not set");   // 0 — correct
console.log(product.inStock     ?? "Status unknown");  // false — correct
console.log(product.description ?? "No description");  // "" — correct

Pairing With Optional Chaining

This is the most powerful combination in modern JavaScript. Optional chaining accesses the property safely — nullish coalescing provides the fallback if it is missing.

object?.property ?? "fallback"
const user = {
  name: "Ali",
  profile: {
    bio: null,
    website: "ali.dev"
  }
};

console.log(user?.profile?.bio     ?? "No bio added");    // No bio added — bio is null
console.log(user?.profile?.website ?? "No website");      // ali.dev — exists
console.log(user?.profile?.twitter ?? "No twitter");      // No twitter — property missing
console.log(user?.contact?.phone   ?? "No phone");        // No phone — contact missing

Every access is safe and every missing value gets a meaningful fallback — no errors, no empty output.


With Dynamic Object Data

When you build UI from data — like a user profile page or a product listing — some fields will always be missing for some records. ?. and ?? together handle this gracefully.

const profiles = [
  {
    username: "ali_dev",
    stats: { posts: 42, followers: 1200 },
    location: "Lahore"
  },
  {
    username: "sara_design",
    stats: { posts: 18, followers: null },
    // no location
  },
  {
    username: "zara_writes"
    // no stats, no location
  }
];

for (const profile of profiles) {
  const posts     = profile?.stats?.posts     ?? 0;
  const followers = profile?.stats?.followers ?? 0;
  const location  = profile?.location         ?? "Location not set";

  console.log(`@${profile.username}`);
  console.log(`  Posts: ${posts} | Followers: ${followers}`);
  console.log(`  Location: ${location}`);
  console.log("---");
}

// @ali_dev
//   Posts: 42 | Followers: 1200
//   Location: Lahore
// ---
// @sara_design
//   Posts: 18 | Followers: 0
//   Location: Location not set
// ---
// @zara_writes
//   Posts: 0 | Followers: 0
//   Location: Location not set
// ---

Nullish Assignment ??=

ES2021 added a shorthand — nullish assignment. It assigns a value only if the current value is null or undefined.

let username = null;
username ??= "Guest";
console.log(username); // Guest — was null, assigned

let theme = "dark";
theme ??= "light";
console.log(theme); // dark — was not null/undefined, kept

This is equivalent to:

username = username ?? "Guest";

Real use — setting defaults on an object only for missing properties:

const settings = {
  theme: "dark",
  language: null,
  fontSize: undefined
};

settings.theme    ??= "light";  // already "dark" — not changed
settings.language ??= "en";     // was null — set to "en"
settings.fontSize ??= 14;       // was undefined — set to 14

console.log(settings);
// { theme: "dark", language: "en", fontSize: 14 }

?? vs || vs ?. — Knowing Which to Use

These three are often used together. Here is a clear breakdown of what each one does:

OperatorPurposeTriggers fallback on
||Fallback for any falsy valuefalse, 0, "", null, undefined, NaN
??Fallback for missing values onlynull, undefined
?.Safe property accessStops if null or undefined
const user = { score: 0, name: "" };

// || — wrong for scores and empty strings
console.log(user.score || "No score"); // "No score" — wrong, 0 is valid
console.log(user.name  || "Anonymous"); // "Anonymous" — maybe wrong, "" might be valid

// ?? — correct
console.log(user.score ?? "No score"); // 0 — correct
console.log(user.name  ?? "Anonymous"); // "" — correct, name exists

// ?. — safe access
console.log(user?.profile?.avatar ?? "No avatar"); // "No avatar" — safe and clean

The combination of ?. and ?? is now the standard way to handle optional object data in modern JavaScript. You will see it everywhere — in React components, API handlers, and utility functions.


A Real Example — Product Page

function renderProduct(product) {
  const name        = product?.name              ?? "Unnamed Product";
  const price       = product?.price             ?? "Price not available";
  const discount    = product?.discount          ?? 0;
  const rating      = product?.rating            ?? "No ratings yet";
  const description = product?.details?.desc     ?? "No description available";
  const stock       = product?.inventory?.count  ?? 0;
  const stockLabel  = stock > 0 ? `${stock} in stock` : "Out of stock";

  console.log(`${name}`);
  console.log(`Price: Rs. ${price}${discount ? ` (${discount}% off)` : ""}`);
  console.log(`Rating: ${rating}`);
  console.log(`${description}`);
  console.log(`${stockLabel}`);
  console.log("---");
}

renderProduct({
  name: "Mechanical Keyboard",
  price: 8500,
  discount: 10,
  rating: 4.5,
  details: { desc: "RGB backlit, tactile switches" },
  inventory: { count: 15 }
});

renderProduct({
  name: "Old Mouse",
  price: 0,
  inventory: { count: 0 }
});

renderProduct(null);

// Mechanical Keyboard
// Price: Rs. 8500 (10% off)
// Rating: 4.5
// RGB backlit, tactile switches
// 15 in stock
// ---
// Old Mouse
// Price: Rs. 0
// Rating: No ratings yet
// No description available
// Out of stock
// ---
// Unnamed Product
// Price: Rs. Price not available
// Rating: No ratings yet
// No description available
// Out of stock
// ---

All three cases handled — complete data, partial data, and completely missing data — cleanly and without a single if statement.


Summary

  • ?? returns the right side only when the left is null or undefined
  • Use ?? instead of || when 0, false, or "" are valid values
  • Pair with ?. for the safest and cleanest way to handle optional object data — obj?.prop ?? "fallback"
  • ??= assigns a value only if the current one is null or undefined
  • || fallback — any falsy value triggers it
  • ?? fallback — only null and undefined trigger it
  • ?. access — stops the chain safely if null or undefined

On this page