DocsHub
Control Flow

Short Circuit Operators

Learn how &&, ||, and ?? work beyond conditions — and how to use them to write cleaner JavaScript.

Short Circuit Operators

You already know && and || from the Operators topic — they combine conditions and return true or false. But they actually do something more powerful than that.

These operators don't just return booleans. They return one of the actual values being evaluated — and they stop as early as possible. That early stopping is called short circuiting.

Understanding this unlocks a cleaner, more expressive way to write JavaScript.


How Short Circuiting Works

JavaScript evaluates expressions left to right and stops the moment the result is certain.

Think of it like this:

  • && needs both sides to be truthy. If the left side is falsy — the result is already decided. No need to check the right side.
  • || needs at least one side to be truthy. If the left side is truthy — the result is already decided. No need to check the right side.
// && stops at the first falsy value
false && console.log("This never runs"); // stopped at false

// || stops at the first truthy value
true || console.log("This never runs");  // stopped at true

&& — AND

Returns the first falsy value it finds. If all values are truthy, returns the last value.

console.log(true && "Hello");   // "Hello"  — left is truthy, returns right
console.log(false && "Hello");  // false    — left is falsy, stops here
console.log("Ali" && 42);       // 42       — both truthy, returns last
console.log(0 && "Hello");      // 0        — 0 is falsy, stops here

Real use — run something only if a condition is met

let isLoggedIn = true;
isLoggedIn && console.log("Welcome back!"); // Welcome back!

let isAdmin = false;
isAdmin && console.log("Opening admin panel."); // nothing runs

This pattern is very common in React for conditional rendering — show something only when a condition is true.

let user = { name: "Ali", age: 22 };

// Only access .name if user exists
let name = user && user.name;
console.log(name); // "Ali"

let guest = null;
let guestName = guest && guest.name;
console.log(guestName); // null — stopped at guest, never touched .name

This protects you from errors when a value might be null or undefined.


|| — OR

Returns the first truthy value it finds. If all values are falsy, returns the last value.

console.log(false || "Hello");  // "Hello" — left is falsy, checks right
console.log("Ali" || "Guest");  // "Ali"   — left is truthy, stops here
console.log(0 || 42);           // 42      — 0 is falsy, returns right
console.log(null || undefined); // undefined — both falsy, returns last

Real use — default values

This is the most common use of ||. Provide a fallback when a value might be empty or missing.

let username = "";
let displayName = username || "Guest";
console.log(displayName); // "Guest" — username is falsy, falls back
function greet(name) {
  let displayName = name || "Guest";
  console.log(`Hello, ${displayName}!`);
}

greet("Ali");   // Hello, Ali!
greet("");      // Hello, Guest!
greet();        // Hello, Guest! — name is undefined, falls back

This pattern — value || fallback — was the standard way to handle defaults in JavaScript for years.


The Problem With || for Defaults

|| has one gotcha. It treats all falsy values as "missing" — including 0, false, and "" which are sometimes perfectly valid values.

let volume = 0; // user set volume to 0 on purpose
let level = volume || 50;
console.log(level); // 50 — wrong! 0 was a valid value, not "missing"
let isDisabled = false; // user intentionally set this to false
let state = isDisabled || true;
console.log(state); // true — wrong again, false was intentional

|| cannot tell the difference between "no value was given" and "the value happens to be 0 or false". This is exactly the problem ?? was created to solve.


?? — Nullish Coalescing

The ?? operator works like || but is far more precise. It only falls back when the left side is null or undefined — not for any other falsy value.

console.log(null ?? "Default");      // "Default" — null triggers fallback
console.log(undefined ?? "Default"); // "Default" — undefined triggers fallback
console.log(0 ?? "Default");         // 0  — 0 is not null/undefined, keep it
console.log("" ?? "Default");        // "" — empty string is kept
console.log(false ?? "Default");     // false — kept as is

Now the volume problem is solved:

let volume = 0;
let level = volume ?? 50;
console.log(level); // 0 — correct, 0 is a valid value
let isDisabled = false;
let state = isDisabled ?? true;
console.log(state); // false — correct, intentional value is respected

Real use — API data with missing fields

let userData = {
  name: "Ali",
  score: 0,
  bio: null
};

console.log(userData.name  ?? "Anonymous"); // "Ali"
console.log(userData.score ?? 100);         // 0   — score exists, keep it
console.log(userData.bio   ?? "No bio yet"); // "No bio yet" — bio is null

Side by Side — || vs ??

let value = 0;

console.log(value || "fallback");  // "fallback" — 0 is falsy
console.log(value ?? "fallback");  // 0 — 0 is not null/undefined
Value|| result?? result
nullfallbackfallback
undefinedfallbackfallback
0fallback0
""fallback""
falsefallbackfalse
"Ali""Ali""Ali"

Rule of thumb: Use ?? when you only want to fall back for truly missing values (null or undefined). Use || only when any falsy value should trigger the fallback.


Combining && and ||

You can chain them together for more expressive logic.

let isLoggedIn = true;
let isAdmin = false;
let username = "Ali";

let greeting = isLoggedIn && (isAdmin ? "Welcome, Admin!" : `Welcome, ${username}!`);
console.log(greeting); // Welcome, Ali!
let cachedData = null;
let freshData = { items: [1, 2, 3] };

let data = cachedData || freshData;
console.log(data); // { items: [1, 2, 3] } — cache was null, used fresh data

Summary

  • Short circuit operators stop evaluating as soon as the result is certain
  • && returns the first falsy value, or the last value if all are truthy
  • || returns the first truthy value, or the last value if all are falsy
  • ?? returns the right side only when left is null or undefined
  • Use && to run something only when a condition is met
  • Use || for fallbacks when any falsy value means "missing"
  • Use ?? for fallbacks when only null and undefined mean "missing"
  • ?? is the safer default choice when dealing with real data

On this page