# Control Flow in JavaScript: If, Else, and Switch Explained

## TL;DR

Control flow determines which parts of your program run and when. Use `if`, `if-else`, and `else if` to make boolean decisions. Use `switch` when you have many exact-match branches (like checking specific values). This article explains each structure, shows clear examples, visualizes the flow with diagrams, and gives practice assignments.

# Introduction - Why control flow matters

Computers follow instructions. Control flow is the mechanism that lets your program choose between multiple paths — essentially *decision-making* inside code.

Real life: if it’s raining, take an umbrella; otherwise don’t. Programs need the same kind of branching logic to react differently based on input, state, or user actions.

What you'll learn:

*   `if` / `if-else` / `else if` syntax and when to use them
    
*   `switch` syntax and the role of `break`
    
*   How to pick between `if-else` and `switch`
    
*   Common beginner mistakes and best practices
    
*   Small exercises with solutions
    

# The `if` statement

### Purpose

Use `if` when you want to run a block of code only when a condition is true.

### Syntax

```typescript
if (condition) {
  // runs when condition is truthy
}
```

### Simple example

```typescript
const isRaining = true;
if (isRaining) {
  console.log("Take an umbrella");
}
```

### What to explain while writing this section

*   `condition` is any expression that evaluates to a boolean (or to a value that coerces to boolean).
    
*   Parentheses around the condition are required. Curly braces for the block are required for multi-line blocks (single statements can omit braces but avoid that for readability).
    
*   Truthy vs falsy (brief): `0`, `""`, `null`, `undefined`, `NaN`, and `false` are falsy; everything else is truthy.
    

### Step-by-step trace example

```typescript
const temp = 30;
if (temp > 25) {
  console.log("It's warm");
}
```

1.  Evaluate `temp > 25` → `30 > 25` → `true`.
    
2.  Enter the `if` block and run `console.log("It's warm")`.
    

### Common beginner mistakes

*   Using assignment `=` instead of comparison `==`/`===`.
    
*   Forgetting braces when adding more statements later.
    
*   Relying on implicit coercion without understanding truthy/falsy.
    

# The `if-else` statement

### Purpose

Use `if-else` when you need one behavior for `true` and a different behavior for `false`.

### Syntax

```typescript
if (condition) {
  // runs when condition is true
} else {
  // runs when condition is false
}
```

### Example

```typescript
const age = 17;
if (age >= 18) {
  console.log("You can vote");
} else {
  console.log("You are not eligible to vote yet");
}
```

### Step-by-step execution (trace)

1.  Evaluate `age >= 18` → `17 >= 18` → `false`.
    
2.  Skip `if` block; execute `else` block.
    

### Pitfalls

*   Putting return or break in one branch and not the other without intention.
    
*   Overly long `else` blocks; sometimes better to `return` early and keep code flatter.
    

# The `else if` ladder

### Purpose

Use `else if` when you have more than two mutually exclusive branches — e.g., multiple ranges or categories.

### Syntax

```typescript
if (cond1) {
  // ...
} else if (cond2) {
  // ...
} else if (cond3) {
  // ...
} else {
  // fallback
}
```

### Example: grading

```typescript
const score = 76;
if (score >= 90) {
  console.log("A");
} else if (score >= 75) {
  console.log("B");
} else if (score >= 60) {
  console.log("C");
} else {
  console.log("F");
}
```

### Execution order note

JavaScript evaluates conditions top-to-bottom and stops at the first true condition. That’s why the most specific (or highest priority) checks should come first.

### Step-by-step trace for `score = 76`

1.  `score >= 90` → `false`.
    
2.  `score >= 75` → `true` → print `"B"` → skip rest.
    

### Common beginner mistakes

*   Ordering conditions wrongly (e.g., checking `x > 10` before `x > 20`).
    
*   Using many `else if`s where a `switch` (or map) would be cleaner.
    

# The `switch` statement

### Purpose

Use `switch` for multiple branches based on exact matches of a single expression (often better than a long `else if` ladder when checking the same variable for equality against many possible values).

### Syntax

```typescript
switch (expression) {
  case value1:
    // code
    break;
  case value2:
    // code
    break;
  default:
    // fallback
}
```

### Example: day of week

```typescript
const day = 3;
switch (day) {
  case 1:
    console.log("Monday");
    break;
  case 2:
    console.log("Tuesday");
    break;
  case 3:
    console.log("Wednesday");
    break;
  default:
    console.log("Invalid day");
}
```

### Key points about `break`

*   `break` exits the `switch` block. Without `break`, execution *falls through* to the next case.
    
*   Fall-through can be useful intentionally (see consolidated cases below), but it’s a common source of bugs when accidental.
    

### Intentional fall-through example

```typescript
const v = "banana";
switch (v) {
  case "apple":
  case "banana":
  case "pear":
    console.log("This is a common fruit");
    break;
  default:
    console.log("Other");
}
```

Here, `apple`, `banana`, and `pear` share the same outcome.

### Common beginner mistakes

*   Forgetting `break`, causing unexpected fall-through.
    
*   Using complex expressions in `case` labels — they are matched with strict equality (`===`\-like).
    
*   Expecting `switch` to work with ranges — it doesn't (unless you use tricks like `true` in switch).
    

### Trick: `switch(true)` for ranges (advanced)

Not recommended for beginners, but useful to know:

```typescript
const score = 85;
switch (true) {
  case score >= 90:
    console.log("A");
    break;
  case score >= 75:
    console.log("B");
    break;
  default:
    console.log("F");
}
```

This works because `switch` compares the `expression` (here `true`) to each `case` expression using strict equality.

# When to use `switch` vs `if-else`

### Quick heuristics

*   Use `if`/`if-else`/`else if` when:
    
    *   Conditions are ranges or complex boolean expressions (e.g., `x > 10 && y < 5`).
        
    *   You need to evaluate different variables or mixed conditions.
        
*   Use `switch` when:
    
    *   You have one expression/variable and many exact-value checks (e.g., menu choices, status codes).
        
    *   Branches are simple and based on equality.
        
    *   You prefer clearer visual grouping of all possible values.
        

### Examples

*   HTTP status code handling: `switch (statusCode) { case 200: ... }`
    
*   Small set of commands (e.g., CLI): `switch (command) { ... }`
    
*   Ranges like grades or thresholds: prefer `if-else`.
    

### Readability and maintainability

If your `else if` ladder is long and each branch checks the same variable for equality, `switch` is clearer. Conversely, prefer `if-else` for flexible conditions.

# Common pitfalls and best practices

### Pitfalls

*   Using `=` instead of `===` or `==`. Always use `===` unless you have a specific reason to coerce.
    
*   Forgetting `break` in `switch`.
    
*   Over-nesting conditionals — deeply nested `if`s are hard to read.
    
*   Long `else if` ladders that check different variables — refactor into separate functions or use a `Map`.
    

### Best practices

*   Prefer explicit comparisons (`age >= 18`) over relying on truthy/falsy for user-facing logic.
    
*   Return early to keep code flat:
    
    ```javascript
    function handle(x) {
      if (!x) return;
      // rest of logic
    }
    ```
    
*   Use `switch` for many exact-value checks; use `if` for boolean expressions and ranges.
    
*   Comment intentional fall-through in switches clearly:
    
    ```javascript
    case 1:
      // fall-through intentional
    case 2:
      doSomething();
      break;
    ```
    

# Quick reference (cheat-sheet)

*   `if (cond) {...}` — run block when `cond` truthy.
    
*   `if (cond) {...} else {...}` — choose between two branches.
    
*   `if (a) {...} else if (b) {...} else {...}` — chain multiple checks.
    
*   `switch (expr) { case v: ... break; default: ... }` — best for many exact matches.
    
*   Use `===` for equality. Use `break` to avoid fall-through. Comment intentional fall-through.
    

# Conclusion and next steps

Control flow is foundational. Once you're comfortable with `if`/`else` and `switch`, practice by:

*   Adding input validation (bad inputs → show friendly messages)
    
*   Rewriting `switch` logic as a `Map` lookup when values map to functions or text
    
*   Avoiding deep nesting: refactor with functions or early returns
    
*   Try small projects like a CLI menu, form validation, or a simple rule-based game
    

# Appendix — Extra examples & refactor ideas

### Using a `Map` instead of switch (refactor)

```javascript
const dayMap = new Map([
  [0, "Sunday"],
  [1, "Monday"],
  [2, "Tuesday"],
  [3, "Wednesday"],
  [4, "Thursday"],
  [5, "Friday"],
  [6, "Saturday"]
]);

function dayName(dayNumber) {
  return dayMap.get(dayNumber) ?? "Invalid day number";
}
```

This scales better when you need to store extra metadata or functions per case.

### Early-return pattern to reduce nesting

```javascript
function process(user) {
  if (!user) return "No user";
  if (!user.active) return "Inactive user";
  // continue with core logic
}
```
