SKU // 22

JavaScript Logical Operators

A comparison checks one thing: is the score over 60? Real decisions usually depend on several things at once: is the player over 13 and has a parent approved? Is the user an admin or a moderator? Logical operators combine comparisons like these into one true/false answer.

// The Logical Operators

Given let x = 6; and let y = 3;:

Operator Name Example Result
&&ANDx < 10 && y > 1true
||ORx === 5 || y === 5false
!NOT!(x === y)true
??Nullish coalescingnull ?? "missing""missing"

// AND: &&

&& gives true only if both sides are true. If either side is false, the whole thing is false:

true && truetrue
true && falsefalse
false && truefalse
false && falsefalse
const age   = 21;
const hasId = true;

if (age >= 18 && hasId) {
  console.log("Entry allowed");
}
Entry allowed

A very common use is checking that a number is inside a range:

let age = 15;
console.log(age >= 13 && age <= 19);    // is it a teen?
true
Watch out: 13 <= age <= 19 does not work
Math class lets you write a range as 13 ≤ age ≤ 19, and JavaScript will even run 13 <= age <= 19. But it is wrong. It works left to right: 13 <= age gives true or false, and then that boolean (as 1 or 0) is compared with 19, which is always true. So even age = 50 passes. Always write both comparisons in full, joined with &&.

// OR: ||

|| gives true if at least one side is true. It is only false when both sides are false:

true || truetrue
true || falsetrue
false || truetrue
false || falsefalse
let x = 6;
let y = -3;
console.log(x > 0 || y > 0);    // is either one positive?

const isAdmin = false;
const isMod   = true;
if (isAdmin || isMod) {
  console.log("Can moderate");
}
true Can moderate
Watch out: x === "a" || "b"
To check if color is red or blue, you might write color === "red" || "blue". That does not mean what it says. It reads as (color === "red") || "blue", and "blue" is a non-empty string, which is truthy, so the check passes for every color. Repeat the comparison on both sides: color === "red" || color === "blue".

// NOT: !

! flips a value: true becomes false and false becomes true. It takes only one operand, placed right after it:

console.log(!true);
console.log(!(5 === 8));    // 5 === 8 is false, so this is true
console.log(!0);              // 0 is falsy, so ! gives true
console.log(!"hello");        // truthy, so ! gives false

let isLoading = false;
if (!isLoading) {
  console.log("Content ready");
}
false true true false Content ready

! is also the quick way to toggle a boolean, like a mute button: isMuted = !isMuted; flips it every time it runs.

Watch out: ! needs parentheses
! binds very tightly, to just the value right next to it. !score === 5 means (!score) === 5: it flips score to a boolean first, then compares that boolean with 5, which is always false. To negate a whole comparison, wrap it: !(score === 5), or just use score !== 5.

// Combining Operators

You can mix logical operators, but know their order: ! first, then &&, then ||. Just like * before +, && is done before ||:

console.log(true || false && false);     // same as true || (false && false)
console.log((true || false) && false);   // parentheses change the answer
true false

Rather than relying on the order, use parentheses to show exactly what you mean:

const score     = 88;
const attended  = true;
const submitted = false;

// Must have a good score AND (attended OR submitted)
if (score >= 80 && (attended || submitted)) {
  console.log("Passes criteria");
}
Passes criteria

// Short-Circuit Evaluation

JavaScript stops working out a logical expression as soon as it knows the answer. This is called short-circuiting:

There is a second surprise hiding here. && and || do not always give back true or false. They give back whichever operand decided the answer:

console.log("" || "Guest");     // "" is falsy, so || moves on and returns "Guest"
console.log("Ana" || "Guest");  // "Ana" is truthy, so || returns "Ana"
console.log(0 && "hi");        // 0 is falsy, so && stops and returns 0
console.log("a" && "b");       // "a" is truthy, so && returns the right side
Guest Ana 0 b

Inside an if this makes no difference, since the result is treated as truthy or falsy anyway. But it makes || a handy way to supply a default value:

let inputName = "";                        // user left the box blank
let display   = inputName || "Anonymous";
console.log(display);
Anonymous

// Nullish Coalescing: ??

The ?? operator (ES2020) returns the right side only when the left side is nullish: null or undefined. Otherwise it returns the left side:

let name = null;
let text = "missing";
console.log(name ?? text);
missing

Why have ?? when || can already supply defaults? Because || treats every falsy value as missing, including 0, "", and false, which are often perfectly good values:

let volume = 0;                      // the user muted it on purpose
console.log(volume || 50);            // 0 is falsy: replaced!
console.log(volume ?? 50);            // 0 is not null/undefined: kept

let timeout = null;                  // never set
console.log(timeout ?? 3000);
50 0 3000
Which default operator?
Use ?? when 0, "", or false are valid values that should be kept (a volume, a score, a setting). Use || when any empty or falsy value should be replaced (a blank name box).

// Quick Check

You want to allow entry if someone is a member or has a ticket, but only if they are also over 12. Which condition is right?

  1. isMember || hasTicket && age > 12
  2. (isMember || hasTicket) && age > 12
  3. isMember && hasTicket || age > 12
  4. isMember || (hasTicket || age > 12)
Show answer
B. The parentheses group the "either one" part, then && requires the age too. A looks close, but && runs first, so it means isMember || (hasTicket && age > 12): a member of any age gets in.

What does this log?

let score = 0;
console.log(score || "no score");
console.log(score ?? "no score");
Show answer
no score then 0. || treats the falsy 0 as missing. ?? only replaces null or undefined, so the real score of 0 is kept.

Why does if (color === "red" || "blue") run for every color?

Show answer
It means (color === "red") || "blue". When the color is not red, || moves on to "blue", a non-empty string, which is truthy. Write color === "red" || color === "blue".

// Try It

  1. Click Open Playground. Write a condition with && that checks n is between 1 and 10. Test with 0, 5, and 11
  2. Add let age = 50; console.log(13 <= age <= 19); and explain the wrong answer
  3. Toggle a boolean three times with on = !on; and log it each time
  4. Compare 0 || "default" with 0 ?? "default", then null || "default" with null ?? "default"
// Video Walkthroughs
Last updated: Oct 9, 2026, 11:53 PM ET