JavaScript Loops

In programming, Loops allow you to repeat a block of code multiple times. Instead of writing the same line ten times, you write it once and tell the computer to “loop” it.

    These loops are strictly controlled by a condition (true/false) or a manual counter. They are the foundation of logic in almost every programming language.

    1. The Standard for Loop

    The for loop is best used when you know exactly how many times you want to repeat a task. It is self-contained, managing its own counter variable inside the parentheses.

    Structure: for (initialization; condition; update) { ... }

    Basic Counter Most commonly, this loop starts at 0 and counts up by 1 until a limit is reached.

    // Start at 0; stop when i is 5; increase by 1 each time
    for (let i = 0; i < 5; i++) {
      console.log("Iteration number: " + i);
    }
    // Output: 0, 1, 2, 3, 4
    
    // You can customize the update section to count down or change the step size (e.g., skip by 2s).
    
    // Start at 10; keep going while i > 0; decrease by 2
    for (let i = 10; i > 0; i -= 2) {
      console.log(i);
    }
    // Output: 10, 8, 6, 4, 2
    JavaScript

    Note: you can use let but you cannot use const as the iterator variable in a traditional for loop (e.g., for (const i = 0; i < 5; i++)) because the iterator (i) needs to be reassigned a new value in each iteration, which violates the const declaration rule. This will cause a TypeError: Assignment to constant variable

    2. The while Loop

    The while loop is ideal when you don’t know how many iterations are needed. It simply keeps running while a condition remains true.

    Note: You must manually update variables inside the loop. If you forget, the condition will never become false, causing an Infinite Loop that crashes the browser.

    // Counting Down
    let count = 3; // const wouldn't work here, because of reassignment in the loop.
    while (count > 0) {
      console.log(count);
      count--; // Vital: decrease count so the loop ends
    }
    // Output: 3, 2, 1
    
    
    // Logic Based Looping
    let number = 2;
    while (number < 100) {
    	console.log(number);
    	number = number * 2;
    }
    // Output: 2, 4, 8, 16, 32, 64
    // Note: the order of execution in logic based looping matters.
    // If the console.log were after the number variable assignment then 128 would show in the console because the while condition wouldn't have been met yet.
    JavaScript

    3. The do...while Loop

    This is a variation of the while loop with one key difference: the condition is checked after the code runs. This guarantees that the block runs at least once, even if the condition is initially false.

    Guaranteed Execution Even though x (0) is not greater than 10, the message prints once.

    let x = 0;
    do {
        console.log("I run once regardless of the condition!");
    } while (x > 10);
    // Output: I run once regardless of the condition!
    
    
    // "Roll the Dice" Logic, keep rolling if number less than three is rolled.
    let dice;
    do {
    	dice = Math.floor(Math.random() * 6) + 1;
    	console.log(`Rolled a ${dice}`);
    } while (dice < 3); // Keep rerolling if we get a 1 or 2
    
    // Refresher on built-in Math object methods:
    console.log(Math.random()); // Number between 0 and 1
    console.log(Math.floor(Math.random() * 6)); // Whole number but includes 0.
    console.log(Math.floor(Math.random() * 6) + 1); // Integer from 1 to 6
    
    
    // Note: using a While Loop for the "Roll the Dice" logic would not be as efficient because the integer would need to be set before the loop (initial roll) and inside the loop (Re-roll).
    // The loop also would NOT run if the count was less than 3.
    let diceTwo = Math.floor(Math.random() * 6) + 1; // 1. Initial roll
    while (diceTwo < 3) {
       console.log(`Rolled a ${diceTwo}`);
       diceTwo = Math.floor(Math.random() * 6) + 1; // 2. Re-roll
    }
    JavaScript

    Modern JavaScript introduced loops designed to read data directly from Collections (like Arrays or Objects) without needing to manage index numbers manually.

    4. The for...of Loop

    Introduced in ES6, this is the preferred loop for iterating over Values in an iterable (Arrays, Strings, Sets, Maps). It is cleaner and easier to read than the standard for loop.

    // Iterating through an Array with for...of
    const fruits = ["Apple", "Banana", "Mango"];
    for (const fruit of fruits) {
        console.log(`Fruit of the day: ${fruit}`);
    }
    // Output: Fruit of the day: (Apple, Banana, Mango on new lines)
    
    
    // Iterating through a String with for...of
    const word = "testing";
    for (const char of word) {
        console.log(char);
    }
    // Output: t, e, s, t, i, n, g (on new lines)
    
    
    // Totaling item amounts in a shopping cart:
    const shoppingCart = [12.99, 5.50, 24.00, 3.25];
    let total = 0;
    for (const price of shoppingCart) {
    	total += price;
    }
    console.log(`The total price is: $${total.toFixed(2)}`);
    // Output: The total price is: $45.74
    
    
    // Geting the index and value of an Array with destructuring:
    const items = ['apple', 'banana', 'mango'];
    for (const [index, item] of items.entries()) {
      console.log(`Item at index ${index} is: ${item}`);
    }
    /* Output:
    Item at index 0 is: apple
    Item at index 1 is: banana
    Item at index 2 is: mango
    */
    
    // Array for...of destructuring with array of arrays:
    const fruitColors = [['apple','red'], ['banana','yellow'], ['orange','orange']];
    for (const [fruit, color] of fruitColors) {
      console.log(`The ${fruit} is ${color}.`);
    }
    /* Output:
    The apple is red.
    The banana is yellow.
    The orange is orange.
    */
    JavaScript

    5. The for...in Loop

    This loop iterates over the Enumerable Properties (Keys) of an object. It is rarely used for Arrays because it returns the index numbers (0, 1, 2) instead of the actual items. Use for...of for arrays instead.

    const user = { name: "Rodney", age: 25, role: "Driver" };
    for (const key in user) {
        // 'key' is the label (name), user[key] is the value (Rodney)
        console.log(`${key}: ${user[key]}`);	 
    }
    /* Output: 
    name: Rodney
    age: 25
    role: Driver */
    JavaScript

    6. The .forEach() Method

    This is technically not a loop statement, but a method built directly into Arrays. It executes a function you provide once for every item in the list. Unlike standard loops, you cannot stop it early using break.

    const cities = ["London", "Paris", "Rio", "New York"];
    cities.forEach(function(city) {
    	console.log(`${city} - ${city.length} characters`);
    });
    /* Output: 
    London - 6 characters
    Paris - 5 characters
    Rio - 3 characters
    New York - 8 characters */
    
    
    // Adding the Array Index via a second argument:
    const racers = ["Mario", "Luigi"];
    racers.forEach((racer, index) => {
        console.log(`#${index + 1} is ${racer}`);
    });
    /* Output: 
    #1 is Mario
    #2 is Luigi
    */
    
    
    // Nested Array Example:
    const homeDetails = [
    	["1 Bedroom", "1 Bath"],
    	["2 Bedrooms", "1 Bath"],
    	["3 Bedrooms", "2 Baths"]
    ];
    // Array Destructuring with [rooms, baths]
    homeDetails.forEach(([rooms, baths]) => {
       console.log(`Unit Info: ${rooms} and ${baths}`);
    });
    /* Output:
    Unit Info: 1 Bedroom and 1 Bath
    Unit Info: 2 Bedrooms and 1 Bath
    Unit Info: 3 Bedrooms and 2 Baths */
    JavaScript

    7. The for await...of Loop

    This is an advanced loop used for Asynchronous operations. If you have a list of Promises (tasks that finish in the future, like fetching data from an API), this loop waits for each one to complete before moving to the next iteration.

    // An array of Promises that resolve (fulfill) immediately with string values.
    const promises = [
        Promise.resolve("Data A"),
        Promise.resolve("Data B")
    ];
    // An IIFE (Immediately Invoked Function Expression) marked as 'async' 
    // to allow the use of the 'await' keyword inside.
    (async () => {
        // for await...of pauses the loop at each iteration until the 
        // current Promise resolves, then assigns the result to 'data'.
        for await (const data of promises) {
            console.log(data); // Output "Data A", then "Data B"
        }
    })();
    JavaScript
    /**
     * ASYNC GENERATOR FUNCTION
     * async: Allows the use of 'await' (waiting for timers/data).
     * *: The asterisk makes it a Generator, allowing it to 'yield' (pause/resume).
     */
    async function* streamAsyncData() { 
      console.log("Stream started: awaiting first piece of data...");
      
      // 1. Simulates a 1-second delay (like a slow network request)
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // 2. PAUSE point: The value is "shipped" to the loop's 'data' variable.
      // Execution stops here until the loop asks for the next item.
      yield "First piece of data";
    
      console.log("Awaiting second piece of data...");
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // 3. Second PAUSE point.
      yield "Second piece of data";
    
      console.log("Awaiting third piece of data...");
      await new Promise(resolve => setTimeout(resolve, 1000));
      
      // 4. Final PAUSE point.
      yield "Third piece of data";
    }
    
    // The consumer function that "listens" to the stream
    async function processStream() {
      console.log("Processing the data stream...");
    
      /**
       * FOR AWAIT...OF LOOP
       * 'data': This variable captures whatever value was 'yielded'.
       * 'streamAsyncData()': The iterable source.
       * Logic: The loop waits for each 'yield' to happen before running its console.log.
       */
      for await (const data of streamAsyncData()) { 
        // This code block runs EVERY time the generator reaches a 'yield'
        console.log("Received:", data);
      }
    
      // This line only runs once the Generator has no more yields left (it finishes).
      console.log("Stream processing complete.");
    }
    
    processStream();
    JavaScript

    The break keyword stops the loop entirely and immediately exits the block. The break keyword also applies to switch statements as seen in the conditional logic lesson.

    const maxGuests = 5;
    for (let i = 1; i < 10; i++) {
    	console.log(i);
    	if (i === maxGuests) {
    		console.log("Maximum guests reached!");
    		break; 
    	}
    }
    // Output: 1, 2, 3, 4, 5, Maximum guests reached!
    JavaScript

    The continue keyword skips the current iteration only and jumps ahead to the next one.

    // Skip even numbers with "continue":
    // IF i = 0 with % remainder operator (i % 2).
    // OR IF i is equal to 5.
    for (let i = 0; i < 10; i++) {
    	if (i % 2 === 0 || i === 5) continue; 
    	console.log(i);
    }
    // Output: 1, 3, 7, 9
    JavaScript

    An Infinite Loop occurs when the condition of your loop never becomes false. The computer will continue repeating the code forever (or until your browser crashes and freezes). If you run your code and the web page suddenly becomes unresponsive, you likely have an infinite loop.

    This most commonly happens with while loops when you forget to update the variable that controls the condition.

    Infinite Loop Example (Don’t Run This):

    let count = 10;
    
    // Condition: Loop while count is greater than 5
    while (count > 5) {
        console.log(count);
        // PROBLEM: We never change 'count'.
        // It stays 10 forever. 10 is always > 5.
        // Result: Infinite Loop.
    }
    JavaScript

    Prevent Infinite Loops by making sure your loop has a clear exit strategy:

    • Check your Update Step: Ensure your variable changes in a way that moves towards the condition becoming false.
      • If checking i < 10, make sure i increases (i++).
      • If checking count > 0, make sure count decreases (count--).
    • Use a Safety Counter (for testing): If you are unsure about complex logic, add a temporary “emergency brake.”

    Adding a Safety Counter:

    let count = 10;
    let safetyValve = 0; // 1. Create a safety counter
    
    while (count > 5) {
    	console.log(count);
    	
    	// 2. The proper update
    	count--; // Remove to see the safety condition prevent infinite looping
    	
    	// 3. The Emergency Brake
    	// If we loop 1000 times, force it to stop no matter what.
    	safetyValve++;
    	if (safetyValve > 1000) { break; } 
    }
    JavaScript

    Tip: When using tools like Live Server in VS Code, temporarily disable “Auto Save” in your text editor settings before writing while loops. This prevents the browser from reloading on unfinished code and crashing your tab with an infinite loop while you are still typing.

    Loop / KeywordDescription / FunctionBest Use Case
    for LoopRuns code a specific number of times using a manual counter.Standard counting (0 to 10), counting backwards, or when you need the index number i.
    while LoopRuns code as long as a condition is true. Checked before running.When you don’t know how many loops are needed (e.g., “until the user types ‘stop'”).
    do...while LoopRuns code as long as a condition is true. Checked after running.When the code must run at least once (e.g., generating a random number before checking it).
    for...of LoopIterates over the values of an iterable object.The Modern Standard. Best for reading items from Arrays, Strings, Maps, and Sets.
    for...in LoopIterates over the enumerable properties (keys) of an object.Best for inspecting Objects to see what properties (keys) they contain.
    .forEach() Array Iterator MethodExecutes a provided function once for each array element.Functional programming style for Arrays. Note: You cannot use break or continue.
    for await...of LoopIterates over asynchronous iterables (Promises).When looping through data that arrives over time (like streaming data or API requests).
    yield KeywordPauses a generator function and exports a value to the for await...of async loop.Used inside Generator functions to produce a sequence of values one at a time (lazy evaluation).
    break KeywordImmediately stops the loop and exits the block.When you find what you are looking for (e.g., “Found the User ID”) and want to stop searching.
    continue KeywordSkips the current iteration and jumps to the next one.When you want to skip specific items (e.g., “Skip all odd numbers”) but keep the loop going.

    While the classic for loop is the most widely known and often the fastest in performance benchmarks, modern JavaScript developers tend to favor the for…of loop and array methods like .forEach() for their improved readability and cleaner syntax. The choice often depends on the specific use case and a balance between performance and code clarity.