JavaScript Logical Operators
Logical operators are used to combine or modify boolean expressions. JavaScript has four logical operators: AND (&&), OR (||), NOT (!), and Nullish Coalescing (??). They are essential for conditional logic and flow control.
Logical AND (&&)
The AND operator returns true if BOTH operands are truthy. It actually returns the first falsy value it finds, or the last value if all are truthy.
// Basic boolean AND
console.log(true && true); // true
console.log(true && false); // false
console.log(false && true); // false
console.log(false && false); // false
// Returns first falsy value or last value
console.log(1 && 2 && 3); // 3 (all truthy, returns last)
console.log(1 && 0 && 3); // 0 (returns first falsy)
console.log(1 && "" && 3); // "" (returns first falsy)
console.log("hello" && 42); // 42
// Practical: conditional execution
let isLoggedIn = true;
isLoggedIn && console.log("Welcome back!"); // "Welcome back!"Logical OR (||)
The OR operator returns true if at least ONE operand is truthy. It returns the first truthy value it finds, or the last value if all are falsy.
// Basic boolean OR
console.log(true || false); // true
console.log(false || true); // true
console.log(false || false); // false
// Returns first truthy value or last value
console.log(0 || "hello"); // "hello"
console.log("" || 0 || 42); // 42
console.log(null || undefined || "default"); // "default"
console.log(0 || "" || null); // null (all falsy, returns last)
// Practical: default values
let username = "" || "Guest";
console.log(username); // "Guest"
let port = 0 || 3000;
console.log(port); // 3000 (PROBLEM: 0 is a valid port!)Logical NOT (!)
The NOT operator inverts a boolean value. It first converts the operand to boolean, then negates it. Double NOT (!!) converts any value to its boolean equivalent.
console.log(!true); // false
console.log(!false); // true
console.log(!0); // true
console.log(!1); // false
console.log(!"hello"); // false
console.log(!""); // true
console.log(!null); // true
// Double NOT for boolean conversion
console.log(!!"hello"); // true
console.log(!!0); // false
console.log(!!null); // false
console.log(!!{}); // trueNullish Coalescing (??)
The ?? operator returns the right operand only when the left is null or undefined. Unlike ||, it does NOT treat 0, false, or empty string as triggers.
| Expression | || Result | ?? Result |
|---|---|---|
| 0 || 10 / 0 ?? 10 | 10 | 0 |
| "" || "default" / "" ?? "default" | "default" | "" |
| false || true / false ?? true | true | false |
| null || 10 / null ?? 10 | 10 | 10 |
| undefined || 10 / undefined ?? 10 | 10 | 10 |
// ?? only triggers on null or undefined
console.log(null ?? "default"); // "default"
console.log(undefined ?? "default"); // "default"
console.log(0 ?? "default"); // 0
console.log("" ?? "default"); // ""
console.log(false ?? "default"); // false
// Compare with ||
console.log(0 || 100); // 100 (0 is falsy)
console.log(0 ?? 100); // 0 (0 is not null/undefined)
// Practical: API responses where 0 is valid
let score = 0;
let displayScore = score ?? "No score";
console.log(displayScore); // 0 (correct!)Short-Circuit Evaluation
Logical operators evaluate left to right and stop as soon as the result is determined. This is called short-circuit evaluation. Code after the short-circuit point is never executed.
// AND short-circuits on first falsy
let result1 = false && console.log("never runs");
console.log(result1); // false
// OR short-circuits on first truthy
let result2 = true || console.log("never runs");
console.log(result2); // true
// Practical: safe property access
let user = null;
let name = user && user.name;
console.log(name); // null (safe, no error)
// Modern alternative: optional chaining
let name2 = user?.name;
console.log(name2); // undefined
// Combining patterns
let config = null;
let theme = config?.theme ?? "light";
console.log(theme); // "light"Logical Assignment Operators
ES2021 introduced logical assignment operators that combine logical operations with assignment: &&=, ||=, and ??=.
// ||= assigns if current value is falsy
let a = "";
a ||= "default";
console.log(a); // "default"
// &&= assigns if current value is truthy
let b = 1;
b &&= 2;
console.log(b); // 2
let c = 0;
c &&= 2;
console.log(c); // 0 (not assigned, 0 is falsy)
// ??= assigns if current value is null/undefined
let d = null;
d ??= "fallback";
console.log(d); // "fallback"
let e = 0;
e ??= 99;
console.log(e); // 0 (not null/undefined)