Execute Program

JavaScript Arrays: For Each

Welcome to the For Each lesson!

JavaScript arrays' `.forEach` method loops over arrays, like a "for" loop. It's often simpler and less error-prone than a "for" loop.

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • A regular for ... of loop gives us each element of the array, one by one.

  • >
    const numbers = [1, 2, 3];
    let sum = 0;
    for (const n of numbers) {
    sum = sum + n;
    }
    sum;
    Result:
    6Pass Icon
  • The .forEach array method is similar. We pass a callback function to forEach, and it's called once for each array element. In the example below, the callback function is n => { ... }.

  • >
    const numbers = [1, 2, 3];
    let sum = 0;
    numbers.forEach(n => {
    sum = sum + n;
    });
    sum;
    Result:
    6Pass Icon
  • >
    const people = [
    {name: 'Cindy'},
    {name: 'Dalili'},
    ];

    const names = [];
    people.forEach(person => {
    names.push(person.name);
    });
    names;
    Result:
    ['Cindy', 'Dalili']Pass Icon
  • Note that in the last two examples, the callback modified a variable defined outside the .forEach. JavaScript functions can always modify variables defined in outer scopes, so this is nothing special. But it's a common pattern with .forEach loops.

  • We can also modify the array's elements during the .forEach.

  • >
    const people = [
    {name: 'Ebony'},
    {name: 'Fang'},
    ];
    people.forEach(person => {
    person.name = person.name.toUpperCase();
    });
    people[0].name;
    Result:
    'EBONY'Pass Icon
  • The callback function passed to .forEach takes a second, optional argument: the element's index.

  • >
    const names = ['Amir', 'Betty'];
    const userIDs = [10, 11];
    let result = '';
    names.forEach((name, index) => {
    result += name + userIDs[index];
    });
    result;
    Result:
    'Amir10Betty11'Pass Icon
  • This is one reason that .forEach is useful. It can give us the array indexes, like a normal for loop does. And it can give us the array values, like a for ... of loop does. But unlike either of those loops, .forEach can give us the index and value at the same time.

  • So far, we defined the callback function inline, right at the point where we called .forEach. Because functions are values in JavaScript, we can also define the callback outside the .forEach loop, then pass it in.

  • >
    let sum = 0;
    function addToSum(n) {
    sum += n;
    }
    [1, 2, 3, 4].forEach(addToSum);
    sum;
    Result:
    10Pass Icon
  • The same thing works with an arrow function.

  • >
    let sum = 0;
    const addToSum = n => sum += n;
    [1, 2, 3, 4].forEach(addToSum);
    sum;
    Result:
    10Pass Icon
  • It's tempting to think of .forEach like a regular for or for ... of loop, but that will lead to mistakes. When we write a for or for ... of loop, there's no callback function. If we return in the loop, that returns from the outer function that contains the loop.

  • >
    function hasTheLetterB(letters) {
    for (const letter of letters) {
    if (letter === 'b') {
    return true;
    }
    }

    return false;
    }

    hasTheLetterB(['o', 'r', 'b']);
    Result:
    truePass Icon
  • We can convert hasTheLetterB to use .forEach, which requires us to add a callback function. Now the return true is inside of the callback function. But that return value is thrown away on every iteration of the loop, so it has no effect. That's a problem! Our function always returns false, even when the array contains a 'b'.

  • >
    function hasTheLetterB(letters) {
    letters.forEach(letter => {
    if (letter === 'b') {
    return true;
    }
    });

    return false;
    }

    hasTheLetterB(['o', 'r', 'b']);
    Result:
    falsePass Icon
  • We can fix this by declaring a variable outside the loop to keep track of whether we encountered the letter 'b'. Then we return this variable at the end of the function, like we did with sum earlier.

  • >
    function hasTheLetterB(letters) {
    let sawLetterB = false;

    letters.forEach(letter => {
    if (letter === 'b') {
    sawLetterB = true;
    }
    });

    return sawLetterB;
    }

    hasTheLetterB(['o', 'r', 'b']);
    Result:
    truePass Icon
  • Here's a code problem:

    The function below decides whether any number in the array is positive. Currently it's broken: it always returns false. That's because we tried to return true inside the .forEach callback function. But the callback's return value is ignored, so that doesn't work.

    Modify the function so it works as intended. We declared a sawPositiveNumber variable for you outside the loop, which you can use to track whether the loop has seen a positive number or not. Remember to return it at the end!

    function hasPositiveNumbers(numbers) {
    let sawPositiveNumber = false;
    numbers.forEach(n => {
    if (n > 0) {
    sawPositiveNumber = true;
    }
    });
    return sawPositiveNumber;
    }
    [
    hasPositiveNumbers([]),
    hasPositiveNumbers([-2, -1, 0]),
    hasPositiveNumbers([-1, 0, 100]),
    hasPositiveNumbers([50]),
    ];
    Goal:
    [false, false, true, true]
    Yours:
    [false, false, true, true]Pass Icon
  • Here's a code problem:

    Write a function count that takes an array and a callback function, then returns the number of elements where callback returns true. Use .forEach to iterate through the array.

    A hint: you'll need a variable outside the .forEach loop to keep track of the element count. Remember to return it at the end!

    function count(arr, callback) {
    let elementCount = 0;
    arr.forEach(e => {
    if (callback(e)) {
    elementCount += 1;
    }
    });
    return elementCount;
    }
    [
    count([1, 2, 3, 4], e => e === 3),
    count([1, 2, 3, 4], e => e > 1),
    count([2, 1, 4, 5, 2, 8], e => e === 2),
    count(['a', 'b'], e => e === 'd'),
    count([], e => e === 'd'),
    ];
    Goal:
    [1, 3, 2, 0, 0]
    Yours:
    [1, 3, 2, 0, 0]Pass Icon