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

AND (&&)
T && Ttrue
T && Ffalse
F && Tfalse
F && Ffalse
OR (||)
T || Ttrue
T || Ftrue
F || Ttrue
F || Ffalse

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

25
$50k
720
age >= 21
&&
income >= 30000
||
creditScore >= 700
✓ Approved

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.

1 / 3
// ⚠️ || 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.