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 hereReal 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 runsThis 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 .nameThis 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 lastReal 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 backfunction greet(name) {
let displayName = name || "Guest";
console.log(`Hello, ${displayName}!`);
}
greet("Ali"); // Hello, Ali!
greet(""); // Hello, Guest!
greet(); // Hello, Guest! — name is undefined, falls backThis 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 isNow the volume problem is solved:
let volume = 0;
let level = volume ?? 50;
console.log(level); // 0 — correct, 0 is a valid valuelet isDisabled = false;
let state = isDisabled ?? true;
console.log(state); // false — correct, intentional value is respectedReal 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 nullSide 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 |
|---|---|---|
null | fallback | fallback |
undefined | fallback | fallback |
0 | fallback | 0 |
"" | fallback | "" |
false | fallback | false |
"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 dataSummary
- 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 isnullorundefined- Use
&&to run something only when a condition is met - Use
||for fallbacks when any falsy value means "missing" - Use
??for fallbacks when onlynullandundefinedmean "missing" ??is the safer default choice when dealing with real data