Phase 3: JavaScript • Lesson 11

Conditionals & Control Flow — Teaching Code to Make Decisions

Learn how computers evaluate conditions, compare values, branch execution paths, and implement real-world business logic like pros.

1. Learning Objective

Until now, your JavaScript code has executed strictly from top to bottom, running every single line in order. Real software doesn't work like that! Real software makes decisions based on data.

In this lesson, you will learn how to control the flow of execution using conditionals and logic:

💡 Why this matters in real-world development

Every dynamic web application is built on conditionals:

  • Auth Guards: if (!user.isLoggedIn) { redirectToLogin(); }
  • E-Commerce Checkout: if (cartTotal > 50) { applyFreeShipping(); }
  • UI Rendering in React: {isLoading ? <Spinner /> : <ProductList />}
  • Form Validation: if (email.includes("@")) { submitForm(); } else { showError(); }

2. Prerequisites Revision

Before diving in, let's quickly review the core concepts from previous lessons that conditionals build upon:

Concept What It Means Example
Variables Containers that store values in memory. const userAge = 20;
Boolean Type A primitive data type with only two values: true or false. const isOver18 = true;
Functions Reusable blocks of code that take inputs and return outputs. function checkAge(age) { ... }
Events User interactions like clicks or input changes that trigger code. button.addEventListener("click", handleClick);

3. Concept Explanation (From Scratch)

What is "Control Flow"?

By default, JavaScript reads and executes your script line by line from top to bottom. This sequential execution is called default control flow. Conditionals are special structures that interrupt this straight-line path, allowing your program to take different branches based on whether a condition is true or false.

1. Comparison Operators

Before making a decision, JavaScript needs to compare values. A comparison expression always evaluates to a Boolean: true or false.

Operator Name Example Result Why / Notes
=== Strict Equality 5 === 5
5 === "5"
true
false
Checks both value AND data type. Always use this!
!== Strict Inequality 10 !== 5
5 !== "5"
true
true
Returns true if value OR data type is different.
> Greater Than 10 > 5 true Is left value strictly larger than right value?
< Less Than 3 < 8 true Is left value strictly smaller than right value?
>= Greater Than or Equal 18 >= 18 true Is left value larger than or equal to right value?
<= Less Than or Equal 5 <= 10 true Is left value smaller than or equal to right value?
== Loose Equality ⚠️ 5 == "5" true DANGER! Converts types automatically before comparing. Avoid in production!

2. The if, else if, and else Decision Ladder

The basic structure for decision-making in JavaScript:

if (condition) {
  // Runs if condition is true
} else if (anotherCondition) {
  // Runs if first condition was false AND anotherCondition is true
} else {
  // Runs if all previous conditions were false
}

3. Truthy and Falsy Values

In JavaScript, every single value has an inherent boolean equivalent when converted to a boolean (a process called coercion).

❌ The EXACT 8 Falsy Values in JavaScript

Only these 8 values evaluate to false in a boolean context:

    false (the boolean false) 0 (number zero) -0 (negative zero) 0n (BigInt zero) "" (empty string) null (absence of value) undefined (unassigned) NaN (Not-a-Number)

✅ Truthy Values

EVERYTHING ELSE in JavaScript is Truthy! This includes:

    All non-zero numbers (42, -1, 3.14) Non-empty strings ("hello", "0", "false") Empty arrays [] (Yes! An empty array is truthy!) Empty objects {} (Yes! An empty object is truthy!) Functions function() {}

4. Logical Operators: &&, ||, !

Logical operators let you combine multiple conditions together:

5. Short-Circuit Evaluation

JavaScript evaluates logical expressions from left to right and stops as soon as the outcome is guaranteed:

6. Nullish Coalescing Operator (??)

Introduced in ES2020, ?? returns the right side ONLY if the left side is null or undefined. Unlike ||, it does NOT treat 0 or "" as missing!

const userScore = 0;

// Problem with OR (||): treats 0 as falsy and overwrites valid score 0!
const score1 = userScore || 10; // score1 is 10 (Wrong!)

// Solution with Nullish Coalescing (??): keeps 0!
const score2 = userScore ?? 10; // score2 is 0 (Correct!)

7. Ternary Operator (? :)

A shorthand inline replacement for a simple if/else block that returns a value:

// Syntax: condition ? valueIfTrue : valueIfFalse
const status = age >= 18 ? "Adult" : "Minor";

8. The switch Statement

When you have a single variable that could match many exact discrete values (e.g. user role, order status, days of the week), switch provides clean syntax:

switch (orderStatus) {
  case "pending":
    console.log("Order placed.");
    break;
  case "shipped":
    console.log("Order on the way.");
    break;
  case "delivered":
    console.log("Order complete.");
    break;
  default:
    console.log("Unknown status.");
}

4. Mental Model & Analogies

🎢 Real-World Analogy: Theme Park Security Gate

Imagine you are entering a high-speed roller coaster ride at a theme park:

  • Comparison (height >= 140): The security height stick measure. You are either tall enough (true) or not (false).
  • Logical AND (height >= 140 && hasTicket): You MUST be tall enough AND have a valid ticket. If you fail height, the guard doesn't even bother checking your ticket (Short-Circuit evaluation!).
  • Logical OR (isVIP || hasFastPass): You get priority entry if you are either a VIP guest OR holding a fast pass. If you show a VIP card, the guard stops checking fast pass immediately!
  • Switch Statement: A multi-lane ticket gate (Lane 1: Standard, Lane 2: VIP, Lane 3: Staff). Depending on your ticket type, you walk directly into your assigned lane.

5. Visual Flowcharts & Tables

Start: Evaluate if (age >= 18) Is age >= 18? FALSE (Minor) TRUE (Adult) Show "Access Denied" Show "Welcome In!"
Figure 1: Visual execution flow of an if / else decision branch in JavaScript memory.

Comparison: Loose Equality (==) vs Strict Equality (===)

Expression Loose Equality == Strict Equality === Why the difference occurs
5 == "5" true false == coerces string "5" to number 5. === sees Number vs String.
0 == false true false == coerces boolean false to number 0.
"" == false true false == coerces empty string to number 0 and false to 0.
null == undefined true false Spec rule ECMA-262 7.2.14: null and undefined loosely equal only each other.

6. Code Examples: Basic to Industry Level

Example 1: Basic if / else if / else

function calculateDiscount(cartTotal) {
  // Line 1: Check if total qualifies for top-tier 20% discount
  if (cartTotal >= 100) {
    return cartTotal * 0.20;
  } 
  // Line 2: Check if total qualifies for mid-tier 10% discount
  else if (cartTotal >= 50) {
    return cartTotal * 0.10;
  } 
  // Line 3: Fallback for purchases below $50
  else {
    return 0;
  }
}

console.log(calculateDiscount(120)); // Output: 24 (20%)
console.log(calculateDiscount(75));  // Output: 7.5 (10%)
console.log(calculateDiscount(30));  // Output: 0

Example 2: Modern Early Return Pattern (Guard Clauses)

Instead of deeply nested if/else blocks, professional software engineers write clean Guard Clauses:

function processUserPayment(user, amount) {
  // Guard Clause 1: Validate input existence
  if (!user) {
    return { success: false, reason: "No user provided" };
  }

  // Guard Clause 2: Check active status
  if (!user.isActive) {
    return { success: false, reason: "Account inactive" };
  }

  // Guard Clause 3: Verify funds
  if (user.balance < amount) {
    return { success: false, reason: "Insufficient balance" };
  }

  // Main Happy Path (un-nested!)
  user.balance -= amount;
  return { success: true, newBalance: user.balance };
}

7. Visual Execution & JS Engine Mechanics

⚙️ What Happens Inside the V8 Engine During if (a && b)

  1. Step 1 (Parse Expression): The engine creates an Execution Context and evaluates identifier a in the current Environment Record (Scope).
  2. Step 2 (ToBoolean Abstract Operation): V8 invokes ECMAScript internal spec operation ToBoolean(a).
  3. Step 3 (Short-Circuit Check):
    • If ToBoolean(a) returns false, V8 halts evaluation of the line immediately! b is never read or executed. The expression returns a.
    • If ToBoolean(a) returns true, V8 evaluates identifier b and returns b.
  4. Step 4 (Branch Jump): The Bytecode Compiler issues a conditional jump instruction (JumpIfFalse) to skip the if block body if the result was falsy.

8. Common Mistakes & How to Fix Them

❌ Mistake 1: Accidental Assignment in Condition (= instead of ===)

// WRONG: Assigns 5 to x, which evaluates to 5 (truthy!), so block ALWAYS runs!
let x = 0;
if (x = 5) {
  console.log("x is 5!"); // Always executes!
}

// CORRECT: Use strict equality comparison
if (x === 5) {
  console.log("x is 5!");
}

❌ Mistake 2: Using || for Defaults when Zero or Empty String is Valid

// WRONG: If user set custom padding to 0, 0 is falsy, so it resets to 20!
const userPadding = 0;
const padding = userPadding || 20; // padding becomes 20!

// CORRECT: Use Nullish Coalescing (??) which respects 0 and ""
const safePadding = userPadding ?? 20; // safePadding is 0!

❌ Mistake 3: Forgetting break in Switch Statements (Fall-Through Bug)

// WRONG: Missing break causes execution to fall through to next case!
switch (role) {
  case "admin":
    enableAdminTools();
    // Missing break!
  case "user":
    enableUserTools(); // Admin gets this too accidentally!
    break;
}

9. Interview Perspective & Tricky Questions

🔥 Top Interview Questions & Coding Traps

Q1: What does [] == ![] evaluate to and WHY?

Answer: It evaluates to true! Here is the step-by-step ECMAScript coercion sequence:

  1. ![] is evaluated first. [] is an object, which is truthy. So ![] becomes false.
  2. Expression is now [] == false.
  3. Spec rule: Comparing Object to Boolean coerces boolean to number. false becomes 0. Expression: [] == 0.
  4. Spec rule: Comparing Object to Number invokes ToPrimitive([]), which yields empty string "". Expression: "" == 0.
  5. Spec rule: Comparing String to Number coerces "" to number 0. Expression: 0 == 0.
  6. Result: true! (This is why strict === is mandatory in modern software engineering).

Q2: What is the difference between || and ???

Answer: || checks for falsy values (8 values including 0, "", false). ?? checks strictly for nullish values (only null and undefined).

10. Industry Best Practices

11. Real-World Use Cases in Modern Stacks

1. React & Next.js Conditional Rendering

// In React JSX: Short-circuiting with &&
function DashboardHeader({ user }) {
  return (
    <header>
      <h1>Welcome back, {user.name}</h1>
      {/* Renders badge ONLY if user is admin */}
      {user.isAdmin && <span className="admin-badge">Admin</span>}
      
      {/* Ternary for state-based UI */}
      {user.isPro ? <ProFeatures /> : <UpgradeBanner />}
    </header>
  );
}

2. Node.js & Express Authentication Middleware

// Express API route auth guard
function requireAuth(req, res, next) {
  const authHeader = req.headers.authorization;

  // Guard Clause: missing token
  if (!authHeader) {
    return res.status(401).json({ error: "Access denied. No token provided." });
  }

  // Guard Clause: invalid token syntax
  if (!authHeader.startsWith("Bearer ")) {
    return res.status(400).json({ error: "Invalid token format." });
  }

  next(); // Token OK -> proceed to controller
}

Interactive JS Playground: Test Conditionals Live

12. Practice Questions & Exercises

Test your knowledge with these 10 practice questions (Answers at the end of the session!):

  1. What is the boolean evaluation of Boolean("0")?
  2. What does 5 > 3 && 2 < 1 evaluate to?
  3. What is the difference between 5 == "5" and 5 === "5"?
  4. What are the 8 falsy values in JavaScript?
  5. What will const x = null ?? "default"; store in x?
  6. What will const y = "" || "fallback"; store in y?
  7. Convert this if/else statement into a ternary expression:
    let msg; if (score >= 50) msg = "Pass"; else msg = "Fail";
  8. Why does if ([]) console.log("Hi"); print "Hi"?
  9. What happens if you omit the break statement inside a switch case?
  10. What does !true evaluate to? What about !!100?

13. Mini Project: Interactive E-Commerce Discount & Eligibility Calculator

Use the live interactive tool below to test how real-world nested decision rules calculate customer totals:

🛍️ Smart Discount Engine

Click button above to evaluate business logic rules...

Interactive Self-Assessment

Concept Quiz

Fill-in-the-Blank Retrieval Practice

14. Lesson Summary

15. Quick 5-Minute Revision Notes

  • === checks Value + Type. == coerces types (Avoid!).
  • A && B returns A if A is falsy, else returns B.
  • A || B returns A if A is truthy, else returns B.
  • A ?? B returns A if A is NOT null/undefined, else returns B.
  • cond ? x : y is shorthand for inline if/else.

16. Cumulative Challenge

🏆 Challenge: Building an Automated Grade & Scholarship Evaluator

Combine Lesson 9 (Variables), Lesson 10 (Functions & Events), and Lesson 11 (Conditionals) to build a function evaluateStudent(score, attendance, hasDisciplinaryAction):

  • If hasDisciplinaryAction is true, return "Disqualified due to conduct" immediately (Guard clause!).
  • If attendance is less than 75%, return "Failed due to low attendance".
  • If score is >= 90 AND attendance >= 90, return "Passed with High Honors & Scholarship".
  • If score is >= 70, return "Passed".
  • Else, return "Failed".