# JavaScript Beginner Guide - Part 2: Control Flow, Loops, and Functions ## Table of Contents - [Introduction](#introduction) - [Control Flow](#control-flow) - [if...else Statements](#ifelse-statements) - [switch Statement](#switch-statement) - [Ternary Operator](#ternary-operator) - [Loops](#loops) - [for Loop](#for-loop) - [while Loop](#while-loop) - [do...while Loop](#dowhile-loop) - [for...of Loop](#forof-loop) - [for...in Loop](#forin-loop) - [Loop Control: break and continue](#loop-control-break-and-continue) - [Functions](#functions) - [Function Declaration](#function-declaration) - [Function Expression](#function-expression) - [Arrow Functions](#arrow-functions) - [Function Parameters](#function-parameters) - [Return Values](#return-values) - [Scope](#scope) - [Hoisting](#hoisting) - [Practice Exercises](#practice-exercises) --- ## Introduction In this part, we'll learn how to make decisions in your code (control flow), repeat actions (loops), and organize code into reusable blocks (functions). These are fundamental concepts that every programmer needs to master. --- ## Control Flow Control flow determines the order in which your code executes. Think of it like a road map - depending on conditions, you take different paths. ### if...else Statements The `if` statement is the most basic way to make decisions in JavaScript. #### Basic if Statement ```javascript let temperature = 25; if (temperature > 30) { console.log("It's hot outside!"); } ``` #### if...else ```javascript let age = 18; if (age >= 18) { console.log("You can vote!"); } else { console.log("You are too young to vote."); } ``` #### if...else if...else ```javascript let 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"); } ``` #### Nested if Statements ```javascript let age = 25; let hasLicense = true; if (age >= 18) { if (hasLicense) { console.log("You can drive!"); } else { console.log("You need to get a license first."); } } else { console.log("You are too young to drive."); } ``` #### Best Practices for if Statements ```javascript // Good: Use curly braces even for single statements if (isLoggedIn) { showDashboard(); } // Good: Put the positive case first if (isValid) { processData(); } else { showError(); } // Good: Extract complex conditions into variables let canAccess = isLoggedIn && hasPermission && !isSuspended; if (canAccess) { showContent(); } ``` ### switch Statement The `switch` statement is useful when you have many conditions to check against a single value. #### Basic switch Statement ```javascript let day = 3; let dayName; switch (day) { case 1: dayName = "Monday"; break; case 2: dayName = "Tuesday"; break; case 3: dayName = "Wednesday"; break; case 4: dayName = "Thursday"; break; case 5: dayName = "Friday"; break; case 6: dayName = "Saturday"; break; case 7: dayName = "Sunday"; break; default: dayName = "Invalid day"; } console.log(dayName); // "Wednesday" ``` #### switch with Multiple Cases ```javascript let grade = "A"; switch (grade) { case "A": case "B": case "C": console.log("You passed!"); break; case "D": case "F": console.log("You failed."); break; default: console.log("Invalid grade"); } ``` #### switch with return in Function ```javascript 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"; } } console.log(getDayType("Monday")); // "Weekday" console.log(getDayType("Saturday")); // "Weekend" ``` ### Ternary Operator The ternary operator is a shorthand for simple if...else statements. #### Basic Syntax ```javascript // condition ? valueIfTrue : valueIfFalse let age = 20; let status = age >= 18 ? "adult" : "minor"; console.log(status); // "adult" ``` #### Nested Ternary (Use Carefully) ```javascript let score = 85; let grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : score >= 60 ? "D" : "F"; console.log(grade); // "B" ``` #### Practical Examples ```javascript // Setting default value let userName = ""; let displayName = userName ? userName : "Guest"; console.log(displayName); // "Guest" // Conditional rendering (React-like) let isOnline = true; let statusColor = isOnline ? "green" : "red"; // Conditional class let isActive = true; let buttonClass = isActive ? "btn btn-primary" : "btn btn-secondary"; ``` --- ## Loops Loops allow you to repeat code multiple times. This is incredibly useful for processing lists of items, performing calculations, and automating repetitive tasks. ### for Loop The `for` loop is the most commonly used loop in JavaScript. #### Basic for Loop ```javascript // for (initialization; condition; increment) { code } for (let i = 1; i <= 5; i++) { console.log("Iteration " + i); } // Output: // Iteration 1 // Iteration 2 // Iteration 3 // Iteration 4 // Iteration 5 ``` #### Breaking Down the for Loop ```javascript // The for loop has 3 parts separated by semicolons: for ( let i = 0; // 1. Initialization: runs once at the start i < 5; // 2. Condition: checked before each iteration i++ // 3. Increment: runs after each iteration ) { console.log(i); } // Execution order: // 1. i = 0, check 0 < 5 (true), print 0, increment to 1 // 2. i = 1, check 1 < 5 (true), print 1, increment to 2 // 3. i = 2, check 2 < 5 (true), print 2, increment to 3 // 4. i = 3, check 3 < 5 (true), print 3, increment to 4 // 5. i = 4, check 4 < 5 (true), print 4, increment to 5 // 6. i = 5, check 5 < 5 (false), stop ``` #### Counting Down ```javascript for (let i = 5; i > 0; i--) { console.log(i); } console.log("Blast off!"); // Output: // 5 // 4 // 3 // 2 // 1 // Blast off! ``` #### Iterating by Different Steps ```javascript // Even numbers (0, 2, 4, 6, 8) for (let i = 0; i < 10; i += 2) { console.log(i); } // Counting by 3s (0, 3, 6, 9) for (let i = 0; i <= 12; i += 3) { console.log(i); } ``` #### Loop with Multiple Variables ```javascript for (let i = 0, j = 10; i < 5; i++, j--) { console.log("i:", i, "j:", j); } // Output: // i: 0 j: 10 // i: 1 j: 9 // i: 2 j: 8 // i: 3 j: 7 // i: 4 j: 6 ``` ### while Loop The `while` loop repeats as long as a condition is true. #### Basic while Loop ```javascript let count = 0; while (count < 5) { console.log("Count is: " + count); count++; } console.log("Done!"); ``` #### while Loop with User Input Simulation ```javascript // Simulating a game where player has 3 lives let lives = 3; while (lives > 0) { console.log("You have " + lives + " lives left"); // Imagine player loses a life here lives--; } console.log("Game Over!"); ``` #### Infinite while Loop (Danger!) ```javascript // NEVER do this - it will crash your browser/node // while (true) { // console.log("This will run forever!"); // } // Always have a way to exit let input = "yes"; while (input !== "quit") { console.log("Processing..."); // In real code, input would come from user input = "quit"; // This exits the loop } ``` ### do...while Loop The `do...while` loop always runs at least once, then checks the condition. ```javascript let count = 0; do { console.log("Count: " + count); count++; } while (count < 5); // Output: // Count: 0 // Count: 1 // Count: 2 // Count: 3 // Count: 4 ``` #### do...while vs while ```javascript // while - might not run at all let whileCount = 10; while (whileCount < 5) { console.log("while: " + whileCount); } // Nothing prints - condition false from start // do...while - runs at least once let doCount = 10; do { console.log("do...while: " + doCount); } while (doCount < 5); // Prints "do...while: 10" - runs once before checking ``` ### for...of Loop The `for...of` loop is perfect for iterating over arrays and other iterable objects. #### Iterating Over Arrays ```javascript let fruits = ["apple", "banana", "cherry"]; for (let fruit of fruits) { console.log(fruit); } // Output: // apple // banana ``` #### Iterating Over Strings ```javascript let message = "Hello"; for (let char of message) { console.log(char); } // Output: // H // e // l // l // o ``` #### Iterating Over Sets ```javascript let colors = new Set(["red", "green", "blue"]); for (let color of colors) { console.log(color); } ``` ### for...in Loop The `for...in` loop iterates over the enumerable properties of an object. #### Iterating Over Object Properties ```javascript let person = { name: "Alice", age: 25, city: "New York" }; for (let key in person) { console.log(key + ": " + person[key]); } // Output: // name: Alice // age: 25 // city: New York ``` #### for...in with Arrays (Not Recommended) ```javascript let scores = [95, 87, 92, 88]; // This works but gives you INDEXES, not values for (let index in scores) { console.log(index + ": " + scores[index]); } // Use for...of instead for arrays: for (let score of scores) { console.log(score); } ``` ### Loop Control: break and continue #### break - Exit the Loop Completely ```javascript // Find the first number divisible by 7 for (let i = 1; i <= 100; i++) { if (i % 7 === 0) { console.log("Found it: " + i); break; // Exit the loop } } // Output: Found it: 7 ``` #### continue - Skip Current Iteration ```javascript // Print only odd numbers for (let i = 1; i <= 10; i++) { if (i % 2 === 0) { continue; // Skip even numbers } console.log(i); } // Output: 1, 3, 5, 7, 9 ``` #### Practical Examples ```javascript // Skip invalid data let data = [1, 2, "invalid", 4, 5, "bad", 7]; for (let item of data) { if (typeof item !== "number") { continue; // Skip non-numbers } console.log("Valid number:", item); } // Find first match let users = [ { name: "Alice", active: false }, { name: "Bob", active: true }, { name: "Charlie", active: false } ]; let firstActiveUser; for (let user of users) { if (user.active) { firstActiveUser = user.name; break; // Found what we need, stop searching } } console.log("First active user:", firstActiveUser); // "Bob" ``` --- ## Functions Functions are reusable blocks of code. They help you organize code, avoid repetition, and make your programs easier to understand. ### Function Declaration A function declaration defines a named function. ```javascript // Function declaration function greet(name) { return "Hello, " + name + "!"; } // Calling the function let message = greet("Alice"); console.log(message); // "Hello, Alice!" // You can call the function before it's declared (hoisting) console.log(add(2, 3)); // 5 function add(a, b) { return a + b; } ``` #### Function with Multiple Parameters ```javascript function fullName(firstName, lastName) { return firstName + " " + lastName; } console.log(fullName("John", "Doe")); // "John Doe" console.log(fullName("Jane")); // "Jane undefined" ``` #### Function with Default Parameters ```javascript function greet(name = "Guest") { return "Hello, " + name + "!"; } console.log(greet("Alice")); // "Hello, Alice!" console.log(greet()); // "Hello, Guest!" ``` ### Function Expression A function expression assigns a function to a variable. ```javascript // Function expression let greet = function(name) { return "Hello, " + name + "!"; }; console.log(greet("Bob")); // "Hello, Bob!" ``` #### Difference from Declaration ```javascript // Function declaration - can be called before definition sayHello("Alice"); // Works! function sayHello(name) { console.log("Hello, " + name); } // Function expression - CANNOT be called before definition // sayGoodbye("Bob"); // Error! let sayGoodbye = function(name) { console.log("Goodbye, " + name); }; sayGoodbye("Bob"); // Works! ``` ### Arrow Functions Arrow functions are a shorter syntax introduced in ES6. #### Basic Arrow Function ```javascript // Traditional function function add(a, b) { return a + b; } // Arrow function let add = (a, b) => { return a + b; }; // Short form (implicit return) let add = (a, b) => a + b; console.log(add(2, 3)); // 5 ``` #### Arrow Function Variations ```javascript // Single parameter - no parentheses needed let square = x => x * x; console.log(square(5)); // 25 // No parameters let getRandom = () => Math.random(); console.log(getRandom()); // Multiple statements need curly braces and return let calculate = (a, b) => { let sum = a + b; let product = a * b; return { sum, product }; }; console.log(calculate(3, 4)); // { sum: 7, product: 12 } ``` #### Arrow Functions and 'this' Arrow functions don't have their own `this` binding - they inherit from the parent scope. ```javascript // Traditional function - 'this' changes let person1 = { name: "Alice", greet: function() { console.log("Hello, " + this.name); } }; // Arrow function - 'this' is lexical (inherited) let person2 = { name: "Bob", greet: () => { console.log("Hello, " + this.name); // 'this' is NOT person2 } }; person1.greet(); // "Hello, Alice" person2.greet(); // "Hello, undefined" (or error in strict mode) ``` ### Function Parameters #### Rest Parameters ```javascript // Collect multiple arguments into an array function sum(...numbers) { let total = 0; for (let num of numbers) { total += num; } return total; } console.log(sum(1, 2)); // 3 console.log(sum(1, 2, 3, 4, 5)); // 15 ``` #### Arguments Object (Old Way) ```javascript function oldSum() { let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } return total; } console.log(oldSum(1, 2, 3, 4)); // 10 ``` #### Spread Operator in Function Calls ```javascript let numbers = [1, 2, 3, 4, 5]; // Spread operator expands array into individual arguments console.log(Math.max(...numbers)); // 5 console.log(Math.min(...numbers)); // 1 function greet(greeting, ...names) { for (let name of names) { console.log(greeting + ", " + name + "!"); } } greet("Hello", "Alice", "Bob", "Charlie"); // Hello, Alice! // Hello, Bob! // Hello, Charlie! ``` ### Return Values ```javascript // Return a single value function add(a, b) { return a + b; } // Return multiple values using objects function calculate(a, b) { return { sum: a + b, difference: a - b, product: a * b, quotient: a / b }; } let result = calculate(10, 5); console.log(result.sum); // 15 console.log(result.product); // 50 // Return a function (closure) function multiplier(factor) { return function(number) { return number * factor; }; } let double = multiplier(2); let triple = multiplier(3); console.log(double(5)); // 10 console.log(triple(5)); // 15 ``` ### Scope Scope determines where variables are accessible in your code. #### Global Scope ```javascript // Variables declared outside functions are global let globalVar = "I'm global"; function accessGlobal() { console.log(globalVar); // Can access global variables } accessGlobal(); // "I'm global" console.log(globalVar); // "I'm global" ``` #### Function Scope ```javascript function myFunction() { let functionVar = "I'm inside function"; console.log(functionVar); // Works here } // console.log(functionVar); // Error! Not accessible outside function testScope() { let x = 1; function inner() { let y = 2; console.log(x); // Can access x console.log(y); // Can access y } inner(); // console.log(y); // Error! y is not accessible here } ``` #### Block Scope (let and const) ```javascript if (true) { let blockVar = "I'm in a block"; const blockConst = "Also in block"; console.log(blockVar); // Works } // console.log(blockVar); // Error! Block scoped for (let i = 0; i < 3; i++) { console.log(i); // Works } // console.log(i); // Error! ``` #### Scope Chain ```javascript let outer = "outer"; function outerFunction() { let inner = "inner"; function innerFunction() { console.log(outer); // Can access outer console.log(inner); // Can access inner } innerFunction(); } outerFunction(); ``` ### Hoisting Hoisting is JavaScript's behavior of moving declarations to the top of their scope. #### Variable Hoisting ```javascript // console.log(myVar); // undefined (not an error) var myVar = 5; // JavaScript interprets this as: // var myVar; // Declaration hoisted to top // console.log(myVar); // undefined // myVar = 5; // Assignment stays in place // let and const are hoisted but not initialized (Temporal Dead Zone) console.log(myLet); // ReferenceError let myLet = 10; ``` #### Function Hoisting ```javascript // Function declarations are fully hoisted console.log(add(2, 3)); // 5 function add(a, b) { return a + b; } // Function expressions are partially hoisted // console.log(multiply(2, 3)); // TypeError! var multiply = function(a, b) { return a * b; }; ``` #### Best Practices ```javascript // Good: Declare variables at the top of their scope function goodPractice() { let result; let data; // Use variables later result = processData(data); function processData(d) { return d * 2; } return result; } // Good: Declare functions before using them (or use function expressions) let calculate = function(a, b) { return a + b; };