Labs ICT
Pro Login

If / Else

Conditional statements are fundamental to programming, allowing your code to make decisions and execute different code paths based on specific conditions. JavaScript provides several ways to implement conditional logic, from simple if statements to complex switch cases and ternary operators.

In this tutorial, we'll explore all types of conditional statements in JavaScript, including if/else chains, switch statements, ternary operators, and modern conditional patterns.

if Statements

The if statement is the most basic conditional construct, executing code only when a specified condition is true.

Basic if Statement

// Basic if syntax
if (condition) {
  // Code to execute if condition is true
}

// Simple example
let age = 18;
if (age >= 18) {
  console.log("You are eligible to vote");
}

// Multiple conditions
let score = 85;
if (score >= 90 && score <= 100) {
  console.log("Excellent grade!");
}

// Single line if (not recommended for readability)
if (temperature > 30) console.log("It's hot!");

// With function calls
if (isLoggedIn()) {
  showDashboard();
}

// With property access
if (user && user.profile) {
  console.log(user.profile.name);
}

if/else Statement

// if/else syntax
if (condition) {
  // Code if condition is true
} else {
  // Code if condition is false
}

// Example
let age = 16;
if (age >= 18) {
  console.log("You can vote");
} else {
  console.log("You cannot vote yet");
}

// With different data types
let value = "hello";
if (typeof value === "number") {
  console.log("It's a number");
} else {
  console.log("It's not a number");
}

// Practical usage
function checkAccess(user) {
  if (user.isLoggedIn) {
    return "Welcome back!";
  } else {
    return "Please log in";
  }
}

if/else if/else Chain

// Multiple conditions
let score = 75;
let grade;

if (score >= 90) {
  grade = 'A';
} else if (score >= 80) {
  grade = 'B';
} else if (score >= 70) {
  grade = 'C';
} else if (score >= 60) {
  grade = 'D';
} else {
  grade = 'F';
}

console.log(`Your grade is ${grade}`);

// Time of day example
let hour = 14;
let greeting;

if (hour < 12) {
  greeting = "Good morning";
} else if (hour < 18) {
  greeting = "Good afternoon";
} else if (hour < 22) {
  greeting = "Good evening";
} else {
  greeting = "Good night";
}

// Complex conditions
function categorizeNumber(num) {
  if (num > 0) {
    return "Positive";
  } else if (num < 0) {
    return "Negative";
  } else {
    return "Zero";
  }
}

Switch Statement

The switch statement provides a cleaner way to handle multiple conditions based on the same value.

Basic Switch

// Switch syntax
switch (expression) {
  case value1:
    // Code for value1
    break;
  case value2:
    // Code for value2
    break;
  default:
    // Code for no match
    break;
}

// Example with days
let day = "Monday";
let activity;

switch (day) {
  case "Monday":
    activity = "Work meeting";
    break;
  case "Tuesday":
    activity = "Project work";
    break;
  case "Wednesday":
    activity = "Team lunch";
    break;
  case "Thursday":
    activity = "Client call";
    break;
  case "Friday":
    activity = "Weekly review";
    break;
  default:
    activity = "Weekend!";
    break;
}

console.log(activity);

Switch with Fall-through

// Fall-through behavior (intentional)
let month = 2;
let season;

switch (month) {
  case 12:
  case 1:
  case 2:
    season = "Winter";
    break;
  case 3:
  case 4:
  case 5:
    season = "Spring";
    break;
  case 6:
  case 7:
  case 8:
    season = "Summer";
    break;
  case 9:
  case 10:
  case 11:
    season = "Fall";
    break;
  default:
    season = "Invalid month";
}

console.log(season); // "Winter"

// Grade ranges with fall-through
let score = 85;
let grade;

switch (true) {
  case score >= 90:
    grade = 'A';
    break;
  case score >= 80:
    grade = 'B';
    break;
  case score >= 70:
    grade = 'C';
    break;
  case score >= 60:
    grade = 'D';
    break;
  default:
    grade = 'F';
}

Switch with Different Data Types

// Switch with strings
let command = "start";

switch (command.toLowerCase()) {
  case "start":
    console.log("Starting process...");
    break;
  case "stop":
    console.log("Stopping process...");
    break;
  case "pause":
    console.log("Pausing process...");
    break;
  default:
    console.log("Unknown command");
}

// Switch with numbers
let statusCode = 404;

switch (statusCode) {
  case 200:
    message = "OK";
    break;
  case 404:
    message = "Not Found";
    break;
  case 500:
    message = "Internal Server Error";
    break;
  default:
    message = "Unknown Status";
}

Ternary Operator

The ternary operator provides a concise way to write simple conditional expressions.

Basic Ternary

// Ternary syntax
condition ? value_if_true : value_if_false

// Simple example
let age = 20;
let message = age >= 18 ? "Adult" : "Minor";
console.log(message); // "Adult"

// Assignment with ternary
let price = 100;
let discount = price > 50 ? 0.1 : 0.05;
let finalPrice = price * (1 - discount);

// Function return
function getFee(isMember) {
  return isMember ? "$2.00" : "$10.00";
}

// In expressions
let result = (x > y) ? x : y; // Maximum of two values

Nested Ternary

// Nested ternary (use sparingly)
let score = 85;
let grade = score >= 90 ? 'A' : 
             score >= 80 ? 'B' : 
             score >= 70 ? 'C' : 
             score >= 60 ? 'D' : 'F';

console.log(grade); // 'B'

// Multiple conditions
let age = 25;
let category = age < 13 ? 'Child' :
              age < 20 ? 'Teenager' :
              age < 65 ? 'Adult' : 'Senior';

// With function calls
let result = isValid(data) ? processData(data) : showError();

// In template literals
let status = isActive ? 'Active' : 'Inactive';
let badge = `${status}`;

Modern Conditional Patterns

Modern JavaScript provides additional patterns for writing clean conditional code.

Short-circuit Evaluation

// Logical AND for conditional execution
let user = { name: "John", isAdmin: true };

// Only execute if user exists
user && console.log(user.name);

// Conditional property access
let theme = user && user.preferences && user.preferences.theme || 'light';

// Function execution
let result = isValid(input) && processInput(input);

// Logical OR for default values
let name = userName || "Guest";
let port = config.port || 3000;

// Nullish coalescing (ES2020)
let timeout = config.timeout ?? 5000;
let retries = config.retries ?? 3;

// Combined with optional chaining
let city = user?.address?.city ?? "Unknown";

Object-based Conditionals

// Object lookup instead of switch/if
const actions = {
  start: () => console.log("Starting..."),
  stop: () => console.log("Stopping..."),
  pause: () => console.log("Pausing..."),
  reset: () => console.log("Resetting...")
};

let command = "start";
actions[command]?.(); // Executes if command exists

// Grade mapping
const gradeMap = {
  A: "Excellent",
  B: "Good",
  C: "Average",
  D: "Below Average",
  F: "Fail"
};

let letterGrade = "B";
let comment = gradeMap[letterGrade] || "Invalid grade";

// Dynamic method calls
const calculator = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
  multiply: (a, b) => a * b,
  divide: (a, b) => a / b
};

let operation = "add";
let result = calculator[operation]?.(5, 3) || "Invalid operation";

Array-based Conditionals

// Check if value exists in array
const vowels = ['a', 'e', 'i', 'o', 'u'];
let letter = 'e';
let isVowel = vowels.includes(letter);

// Multiple conditions with arrays
const adminRoles = ['admin', 'superadmin', 'moderator'];
const userRoles = ['user', 'editor'];
let canAccess = [...adminRoles, ...userRoles].includes(user.role);

// Range checking
const validAges = [18, 19, 20, 21]; // Specific ages
let canVote = validAges.includes(age);

// Pattern matching with arrays
function getSeason(month) {
  const seasons = [
    { months: [12, 1, 2], name: "Winter" },
    { months: [3, 4, 5], name: "Spring" },
    { months: [6, 7, 8], name: "Summer" },
    { months: [9, 10, 11], name: "Fall" }
  ];
  
  return seasons.find(season => season.months.includes(month))?.name || "Invalid";
}

Conditional Best Practices

Guidelines for writing clean, maintainable conditional code.

Code Organization

// Early returns for cleaner code
function processUser(user) {
  if (!user) {
    return null;
  }
  
  if (!user.isActive) {
    return { error: "User is not active" };
  }
  
  if (!user.hasPermission) {
    return { error: "Insufficient permissions" };
  }
  
  // Main logic
  return { success: true, data: user.profile };
}

// Guard clauses
function calculatePrice(item, user) {
  if (!item) return 0;
  if (!item.price) return 0;
  
  let price = item.price;
  
  if (user?.isPremium) {
    price *= 0.9; // 10% discount
  }
  
  if (item.onSale) {
    price *= 0.8; // 20% discount
  }
  
  return price;
}

// Extract complex conditions
function isEligibleForDiscount(user, item) {
  return user.isPremium && 
         item.category === "electronics" && 
         item.price > 100;
}

if (isEligibleForDiscount(user, item)) {
  applyDiscount(item);
}

Readability

// Use descriptive variable names
const hasValidEmail = user.email && user.email.includes("@");
const isAdult = user.age >= 18;
const hasPermission = user.role === "admin" || user.role === "moderator";

if (hasValidEmail && isAdult && hasPermission) {
  grantAccess(user);
}

// Break down complex conditions
const canVote = age >= 18 && isCitizen && hasRegistered;
const canDrive = age >= 16 && hasValidLicense;

// Use positive conditions when possible
// Instead of: if (!isInvalid)
if (isValid) {
  process();
}

// Group related conditions
const meetsRequirements = 
  hasValidCredentials && 
  hasCompletedProfile && 
  hasAgreedToTerms;

if (meetsRequirements) {
  enableFeatures();
}

Conditional Performance

Understanding performance implications of different conditional patterns.

Optimization Techniques

// Order conditions by likelihood
function checkUserType(user) {
  // Most common first
  if (user.role === "user") return "regular";
  if (user.role === "admin") return "administrator";
  if (user.role === "guest") return "visitor";
  return "unknown";
}

// Use switch for many discrete values
function getDayType(day) {
  switch (day) {
    case "Saturday":
    case "Sunday":
      return "weekend";
    case "Monday":
    case "Tuesday":
    case "Wednesday":
    case "Thursday":
    case "Friday":
      return "weekday";
    default:
      return "invalid";
  }
}

// Object lookup is faster than switch
const dayTypes = {
  "Saturday": "weekend",
  "Sunday": "weekend",
  "Monday": "weekday",
  "Tuesday": "weekday",
  "Wednesday": "weekday",
  "Thursday": "weekday",
  "Friday": "weekday"
};

function getDayType(day) {
  return dayTypes[day] || "invalid";
}

Avoiding Unnecessary Checks

// Cache expensive operations
const expensiveResult = calculateExpensiveValue();
if (expensiveResult > threshold) {
  process();
}

// Use short-circuiting effectively
const user = getUser();
const profile = user?.profile;
const settings = profile?.settings;

if (settings?.notifications) {
  enableNotifications();
}

// Avoid redundant checks
// Bad:
if (x > 0) {
  if (x < 100) {
    // logic
  }
}

// Good:
if (x > 0 && x < 100) {
  // logic
}

Common Pitfalls

Avoid these common mistakes when working with conditionals.

Type Coercion Issues

// Loose equality problems
if (value == "0") {
  // Matches 0, "0", false
}

// Use strict equality
if (value === "0") {
  // Only matches "0"
}

// Undefined vs null
if (value == null) {
  // Matches both null and undefined
}

if (value === null) {
  // Only matches null
}

// Boolean conversion
if (value) {
  // Falsy values: 0, "", false, null, undefined, NaN
}

// More specific checks
if (value !== null && value !== undefined) {
  // Explicit check
}

Switch Pitfalls

// Forgetting break
switch (value) {
  case 1:
    console.log("One");
    // Missing break - falls through!
  case 2:
    console.log("Two");
    break;
}

// Case matching uses strict equality
switch (value) {
  case "1": // Won't match if value is number 1
    break;
  case 1: // Matches number 1
    break;
}

// Default position matters
switch (value) {
  case 1:
    console.log("One");
    break;
  default:
    console.log("Default");
    break;
  case 2:
    console.log("Two"); // Never reached if default is before
    break;
}

Complexity Issues

// Too nested conditionals
if (condition1) {
  if (condition2) {
    if (condition3) {
      // Too deep!
    }
  }
}

// Use early returns
if (!condition1) return;
if (!condition2) return;
if (!condition3) return;
// Main logic

// Overly complex ternary chains
let result = a > b ? (c > d ? a : c) : (e > f ? b : e);

// Break into functions
function getFirstCondition() {
  return a > b ? (c > d ? a : c) : null;
}

function getSecondCondition() {
  return e > f ? b : e;
}

let result = getFirstCondition() || getSecondCondition();

Summary

Key Takeaways

  • if/else handles basic conditional logic
  • switch is cleaner for multiple discrete values
  • Ternary operator provides concise conditional expressions
  • Modern patterns offer cleaner alternatives
  • Order conditions by likelihood for performance

Best Practices

  • Use early returns to reduce nesting
  • Extract complex conditions into variables
  • Prefer object lookups over long switch statements
  • Use strict equality for comparisons
  • Write descriptive condition names

Common Pitfalls

  • Forgetting break statements in switch
  • Using loose equality unintentionally
  • Creating overly complex nested conditions
  • Not considering type coercion
  • Putting default case in wrong position