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 ... ofloop 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:
6
The
.forEacharray method is similar. We pass a callback function toforEach, and it's called once for each array element. In the example below, the callback function isn => { ... }.>
const numbers = [1, 2, 3];let sum = 0;numbers.forEach(n => {sum = sum + n;});sum;Result:
6
>
const people = [{name: 'Cindy'},{name: 'Dalili'},];const names = [];people.forEach(person => {names.push(person.name);});names;Result:
['Cindy', 'Dalili']
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.forEachloops.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'
The callback function passed to
.forEachtakes 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'
This is one reason that
.forEachis useful. It can give us the array indexes, like a normalforloop does. And it can give us the array values, like afor ... ofloop does. But unlike either of those loops,.forEachcan 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.forEachloop, then pass it in.>
let sum = 0;function addToSum(n) {sum += n;}[1, 2, 3, 4].forEach(addToSum);sum;Result:
10
The same thing works with an arrow function.
>
let sum = 0;const addToSum = n => sum += n;[1, 2, 3, 4].forEach(addToSum);sum;Result:
10
It's tempting to think of
.forEachlike a regularfororfor ... ofloop, but that will lead to mistakes. When we write afororfor ... ofloop, there's no callback function. If wereturnin 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:
true
We can convert
hasTheLetterBto use.forEach, which requires us to add a callback function. Now thereturn trueis 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 returnsfalse, 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:
false
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
sumearlier.>
function hasTheLetterB(letters) {let sawLetterB = false;letters.forEach(letter => {if (letter === 'b') {sawLetterB = true;}});return sawLetterB;}hasTheLetterB(['o', 'r', 'b']);Result:
true
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 toreturn trueinside the.forEachcallback 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
sawPositiveNumbervariable 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]
Here's a code problem:
Write a function
countthat takes an array and a callback function, then returns the number of elements wherecallbackreturnstrue. Use.forEachto iterate through the array.A hint: you'll need a variable outside the
.forEachloop 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]