Docs

Module-04-Control-Flow

4.1 If/Else Statements

Overview

Conditional statements are fundamental building blocks of programming that allow your code to make decisions. The if/else statement executes different code blocks based on whether a condition is true or false.


Table of Contents

  1. Basic Syntax
  2. The if Statement
  3. The else Statement
  4. The else if Statement
  5. Nested Conditionals
  6. Truthy and Falsy Values
  7. Comparison Operators in Conditions
  8. Logical Operators in Conditions
  9. Best Practices
  10. Common Patterns

Basic Syntax

if (condition) {
  // code to execute if condition is true
}

if (condition) {
  // code if true
} else {
  // code if false
}

if (condition1) {
  // code if condition1 is true
} else if (condition2) {
  // code if condition2 is true
} else {
  // code if all conditions are false
}

The if Statement

The simplest form of conditional execution.

const age = 18;

if (age >= 18) {
  console.log('You are an adult');
}

// With a single statement, braces are optional (but recommended)
if (age >= 18) console.log('You are an adult');

// Multiple statements require braces
if (age >= 18) {
  console.log('You are an adult');
  console.log('You can vote');
}

How It Works

        ┌──────────────┐
        │  Condition   │
        └──────┬───────┘
               │
       ┌───────┴───────┐
       ▼               ▼
    [true]          [false]
       │               │
       ▼               │
  ┌────────────┐       │
  │ Execute    │       │
  │ if block   │       │
  └────────────┘       │
       │               │
       └───────┬───────┘
               ▼
         Continue...

The else Statement

Provides an alternative when the condition is false.

const temperature = 25;

if (temperature > 30) {
  console.log("It's hot outside");
} else {
  console.log('The weather is pleasant');
}

// Only one branch will execute
const loggedIn = false;

if (loggedIn) {
  console.log('Welcome back!');
} else {
  console.log('Please log in');
}

Execution Flow

        ┌──────────────┐
        │  Condition   │
        └──────┬───────┘
               │
       ┌───────┴───────┐
       ▼               ▼
    [true]          [false]
       │               │
       ▼               ▼
  ┌────────┐     ┌────────┐
  │ if     │     │ else   │
  │ block  │     │ block  │
  └────────┘     └────────┘
       │               │
       └───────┬───────┘
               ▼
         Continue...

The else if Statement

Chain multiple conditions together.

const score = 85;

if (score >= 90) {
  console.log('Grade: A');
} else if (score >= 80) {
  console.log('Grade: B');
} else if (score >= 70) {
  console.log('Grade: C');
} else if (score >= 60) {
  console.log('Grade: D');
} else {
  console.log('Grade: F');
}
// Output: "Grade: B"

Key Points

AspectDescription
Order MattersConditions are checked top to bottom
First Match WinsOnly the first true condition's block runs
else is OptionalYou can have only if and else if
Mutual ExclusivityOnly one block ever executes
// Order matters - this is wrong!
const num = 95;

if (num >= 60) {
  console.log('Pass'); // This runs first!
} else if (num >= 90) {
  console.log('Excellent'); // Never reached for 95
}

// Correct order - most specific first
if (num >= 90) {
  console.log('Excellent');
} else if (num >= 60) {
  console.log('Pass');
}

Nested Conditionals

Conditionals inside other conditionals.

const age = 25;
const hasLicense = true;

if (age >= 18) {
  if (hasLicense) {
    console.log('You can drive');
  } else {
    console.log('You need a license to drive');
  }
} else {
  console.log("You're too young to drive");
}

Flattening with Logical Operators

Often nested conditionals can be simplified:

// Nested (harder to read)
if (age >= 18) {
  if (hasLicense) {
    console.log('You can drive');
  }
}

// Flattened (easier to read)
if (age >= 18 && hasLicense) {
  console.log('You can drive');
}

Deep Nesting Warning

// ❌ Bad: Too deeply nested
if (condition1) {
  if (condition2) {
    if (condition3) {
      if (condition4) {
        // Do something
      }
    }
  }
}

// ✅ Better: Use early returns or logical operators
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;
if (!condition4) return;
// Do something

Truthy and Falsy Values

JavaScript conditions don't require actual booleans.

Falsy Values

if (false) {
} // boolean false
if (0) {
} // zero
if (-0) {
} // negative zero
if (0n) {
} // BigInt zero
if ('') {
} // empty string
if (null) {
} // null
if (undefined) {
} // undefined
if (NaN) {
} // NaN

// None of the above will execute

Truthy Values

if (true) {
} // boolean true
if (1) {
} // non-zero number
if (-1) {
} // negative number
if ('hello') {
} // non-empty string
if ('0') {
} // string with zero (truthy!)
if ([]) {
} // empty array (truthy!)
if ({}) {
} // empty object (truthy!)
if (function () {}) {
} // function

// All of the above will execute

Practical Examples

const username = '';

if (username) {
  console.log(`Hello, ${username}`);
} else {
  console.log('No username provided');
}
// Output: "No username provided"

const items = [];

if (items.length) {
  console.log('Processing items...');
} else {
  console.log('No items to process');
}
// Output: "No items to process"

Comparison Operators in Conditions

OperatorDescriptionExample
==Equal (type coercion)5 == "5" → true
===Strict equal5 === "5" → false
!=Not equal (type coercion)5 != "5" → false
!==Strict not equal5 !== "5" → true
>Greater than10 > 5 → true
<Less than10 < 5 → false
>=Greater or equal10 >= 10 → true
<=Less or equal10 <= 5 → false
const value = 10;

if (value === 10) {
  console.log('Exactly 10');
}

if (value >= 5 && value <= 15) {
  console.log('Between 5 and 15');
}

// Always prefer === over ==
if ('5' == 5) console.log('Coerced equal'); // Runs
if ('5' === 5) console.log('Strictly equal'); // Doesn't run

Logical Operators in Conditions

AND (&&)

All conditions must be true.

const age = 25;
const hasTicket = true;
const notBanned = true;

if (age >= 18 && hasTicket && notBanned) {
  console.log('You may enter');
}

OR (||)

At least one condition must be true.

const isAdmin = false;
const isModerator = true;

if (isAdmin || isModerator) {
  console.log('You have special privileges');
}

NOT (!)

Inverts the boolean value.

const isLoggedIn = false;

if (!isLoggedIn) {
  console.log('Please log in');
}

// Double negation for boolean conversion
const value = 'hello';
if (!!value) {
  console.log('Value exists');
}

Complex Conditions

const user = { role: 'admin', active: true, verified: false };

// Combine operators with parentheses for clarity
if ((user.role === 'admin' || user.role === 'moderator') && user.active) {
  console.log('User has management access');
}

// Checking multiple values
const status = 'pending';
if (status === 'pending' || status === 'processing' || status === 'queued') {
  console.log('Request in progress');
}

// Better: Use includes for multiple checks
if (['pending', 'processing', 'queued'].includes(status)) {
  console.log('Request in progress');
}

Best Practices

1. Always Use Braces

// ❌ Bad: Can lead to bugs
if (condition) doSomething();
doSomethingElse(); // This ALWAYS runs!

// ✅ Good: Always use braces
if (condition) {
  doSomething();
  doSomethingElse();
}

2. Use Strict Equality

// ❌ Bad: Type coercion can cause bugs
if (value == null) {
}

// ✅ Good: Be explicit
if (value === null || value === undefined) {
}
// Or even better:
if (value == null) {
} // This is the ONE exception - checks null/undefined

3. Avoid Negative Conditions When Possible

// ❌ Harder to read
if (!isNotValid) {
  // do something
}

// ✅ Easier to read
if (isValid) {
  // do something
}

4. Use Early Returns

// ❌ Deep nesting
function process(user) {
  if (user) {
    if (user.isActive) {
      if (user.hasPermission) {
        // actual logic here
      }
    }
  }
}

// ✅ Guard clauses
function process(user) {
  if (!user) return;
  if (!user.isActive) return;
  if (!user.hasPermission) return;

  // actual logic here
}

5. Keep Conditions Simple

// ❌ Complex inline condition
if (
  user.age >= 18 &&
  user.country === 'US' &&
  user.hasLicense &&
  !user.isSuspended &&
  user.accountType !== 'trial'
) {
  // ...
}

// ✅ Extract to meaningful variable
const canDrive =
  user.age >= 18 &&
  user.country === 'US' &&
  user.hasLicense &&
  !user.isSuspended &&
  user.accountType !== 'trial';

if (canDrive) {
  // ...
}

// ✅ Or use a function
function canUserDrive(user) {
  if (user.age < 18) return false;
  if (user.country !== 'US') return false;
  if (!user.hasLicense) return false;
  if (user.isSuspended) return false;
  if (user.accountType === 'trial') return false;
  return true;
}

if (canUserDrive(user)) {
  // ...
}

Common Patterns

Null/Undefined Checking

// Check if variable exists
if (variable !== null && variable !== undefined) {
  // use variable
}

// Shorter (checks both null and undefined)
if (variable != null) {
  // use variable
}

// Using optional chaining (modern)
if (user?.address?.city) {
  console.log(user.address.city);
}

Default Values

// Traditional way
let name;
if (userName) {
  name = userName;
} else {
  name = 'Guest';
}

// Modern way with ||
const name = userName || 'Guest';

// With ?? for null/undefined only
const name = userName ?? 'Guest';

Toggle Pattern

let isVisible = false;

function toggle() {
  if (isVisible) {
    isVisible = false;
  } else {
    isVisible = true;
  }
}

// Simpler
function toggle() {
  isVisible = !isVisible;
}

Range Checking

const value = 50;

// Check if in range
if (value >= 0 && value <= 100) {
  console.log('Value is in valid range');
}

// Helper function
function inRange(value, min, max) {
  return value >= min && value <= max;
}

if (inRange(value, 0, 100)) {
  console.log('Value is in valid range');
}

Summary

StatementUse Case
ifExecute code when condition is true
elseExecute code when condition is false
else ifCheck additional conditions
NestedHandle complex multi-level logic

Key Points

  1. Conditions are evaluated as truthy/falsy
  2. Only one branch executes in an if/else if/else chain
  3. Order matters in else if chains
  4. Use === for strict equality
  5. Keep conditions simple and readable
  6. Use early returns to reduce nesting

Next Steps

  • Practice with the examples in examples.js
  • Complete the exercises in exercises.js
  • Learn about switch statements for multiple conditions
  • Explore the ternary operator for simple conditionals
Module 04 Control Flow - JavaScript Tutorial | DeepML