Logical Thinking
Combine conditions, think in booleans, and build complex decision logic.
Boolean Logic
The foundation of all decision making in programming.
Every decision in programming boils down to true or false. Boolean logic gives us tools to combine and manipulate these values.
&&
AND
Both must be true
||
OR
At least one true
!
NOT
Flips the value
// AND (&&) — both conditions must be true
let age = 25;
let hasLicense = true;
if (age >= 18 && hasLicense) {
console.log("Can drive"); // ✓ Both true
}
// OR (||) — at least one must be true
let isWeekend = true;
let isHoliday = false;
if (isWeekend || isHoliday) {
console.log("Day off!"); // ✓ One is true
}
// NOT (!) — inverts the value
let isLoggedIn = false;
if (!isLoggedIn) {
console.log("Please log in"); // ✓ !false = true
}Truth Tables
See every possible combination of AND, OR, and NOT.
A && B
false
A || B
true
!A
false
| T && T | true |
| T && F | false |
| F && T | false |
| F && F | false |
| T || T | true |
| T || F | true |
| F || T | true |
| F || F | false |
Complex Conditions
Combine multiple checks with parentheses for grouping.
// Loan approval logic: const approved = age >= 21 && (income >= 30000 || creditScore >= 700); // Reads as: // "Age at least 21 AND (income 30k+ OR credit 700+)" // Parentheses control grouping: // A && B || C → (A && B) || C (AND first) // A && (B || C) → different! (OR first)
Loan Approval Simulator
Short-Circuit Evaluation
JavaScript stops evaluating as soon as the result is determined.
JavaScript is lazy — it won't evaluate more than it needs to. This is called short-circuit evaluation.
AND (&&) — stops at first false
false && anything → false
"anything" is never evaluated — why check more if one is already false?
OR (||) — stops at first true
true || anything → true
"anything" is never evaluated — already found one true value.
// && returns the first falsy value (or last value)
console.log(0 && "hello"); // 0
console.log(1 && "hello"); // "hello"
console.log("a" && "b" && "c"); // "c"&& doesn't return true/false — it returns the actual value where it stopped. If all truthy, returns the last one.
// ⚠️ || vs ?? for defaults: let count = 0; count || 10; // 10 ← wrong! 0 is falsy count ?? 10; // 0 ← correct! ?? only checks null/undefined let text = ""; text || "default"; // "default" ← wrong! text ?? "default"; // "" ← correct!
Decision Patterns
Common patterns for making decisions in real code.
1. Guard Clause Pattern
function processOrder(order) {
if (!order) return; // guard
if (!order.items.length) return; // guard
if (!order.payment) return; // guard
// Happy path — all checks passed
shipOrder(order);
}Exit early for invalid cases. Main logic stays un-nested.
2. Lookup Object Pattern
// Instead of long if/else chains:
const actions = {
"save": () => saveDocument(),
"delete": () => deleteDocument(),
"share": () => shareDocument(),
};
const handler = actions[command];
if (handler) handler();Replace switch/if-else with an object map. Cleaner and extensible.
3. Validation Chain
function validateForm(data) {
const errors = [];
if (!data.email) errors.push("Email required");
if (!data.email?.includes("@")) errors.push("Invalid email");
if (data.password?.length < 8) errors.push("Password too short");
return errors; // empty = valid
}Collect all issues instead of stopping at the first one.
4. State Machine
function getNextState(current, event) {
const transitions = {
idle: { click: "loading" },
loading: { success: "done", error: "failed" },
done: { reset: "idle" },
failed: { retry: "loading", reset: "idle" },
};
return transitions[current]?.[event] ?? current;
}Model complex logic as states and transitions.
Frequently Asked Questions
Common questions about logical thinking.