Skip to content
beginner

for Loops vs forEach vs map in JavaScript

You can loop over an array three different ways, and they all look nearly identical when you write them. So which one should you use?

Published 2026-09-06Updated 2026-09-129 min read
A vivid close-up of a single yellow sow thistle flower in bloom against a dark background.
A vivid close-up of a single yellow sow thistle flower in bloom against a dark background. Photo by Wyxina Tresse on Pexels.

You can loop over an array three different ways, and they all look nearly identical when you write them. So which one should you use?

The answer comes down to two questions: what should the operation produce, and do you need to control when iteration stops? Once you can answer those, the right choice becomes obvious.

Three Ways to Walk an Array

Let's start with a tiny array and a simple task. We want to log each number to the console.

Here's the same job done three ways:

const numbers = [1, 2, 3];

// A for loop
for (let i = 0; i < numbers.length; i++) {
  console.log(numbers[i]);
}

// forEach
numbers.forEach(function(number) {
  console.log(number);
});

// map
numbers.map(function(number) {
  console.log(number);
});

All three produce the same output:

1
2
3

See why beginners treat them as interchangeable? They all visit every element. They all run your code for each item. On the surface, they look like three names for the same thing.

But two hidden differences separate them: what each one hands back when it finishes, and whether you can stop the loop partway through. Those two details determine which tool fits each job.

What Each Tool Returns

The return value is your first clue. Once you know what each approach gives you back, half your confusion disappears.

The for loop returns nothing on its own

A for loop is just a set of instructions. It runs, and that's it. If you want results, you build them yourself with a variable you declare outside the loop:

const numbers = [1, 2, 3];
const doubled = [];

for (let i = 0; i < numbers.length; i++) {
  doubled.push(numbers[i] * 2);
}

console.log(doubled);
[2, 4, 6]

You're doing the work manually: create an empty array, push into it, and hope you didn't forget anything. It works, but it's a lot of ceremony for a simple transformation.

forEach returns undefined

forEach runs a function for each element, but it never hands anything back. No matter what you do inside that function, forEach itself returns undefined:

const numbers = [1, 2, 3];

const result = numbers.forEach(function(number) {
  return number * 2;
});

console.log(result);
undefined

The return inside the callback doesn't matter. forEach collects nothing. It's a tool for doing, not for producing.

Knowledge check

Check your understanding

Answer this question before you continue.

What does this code print?
Output Prediction

Focus: Predict the value returned by forEach when its callback returns a value.

const numbers = [1, 2, 3];
const result = numbers.forEach(function(number) {
  return number * 2;
});
console.log(result);

map returns a brand-new array

map calls your function for each element, collects whatever that function returns, and builds a new array from those results:

const numbers = [1, 2, 3];

const doubled = numbers.map(function(number) {
  return number * 2;
});

console.log(doubled);
[2, 4, 6]

The original numbers array is untouched. You get a fresh array, the same length as the original, with each element transformed by your function.

Here's the difference in one table:

ApproachReturnsCan stop early?
for loopNothing on its ownYes, with break
forEachundefinedNo
mapA new arrayNo

That's the core. Now let's see when each one is the right fit.

Side Effects: When You Just Want an Action

A side effect is code that does something observable rather than just computing a value. Logging to the console is a side effect. Updating a variable outside the loop is a side effect. Sending data to a server is a side effect.

When your goal is an action, not a result, forEach is your tool:

const students = ["Aisha", "Ben", "Cara"];

students.forEach(function(student) {
  console.log(`Sending welcome email to ${student}`);
});
Sending welcome email to Aisha
Sending welcome email to Ben
Sending welcome email to Cara

You're doing something for each item, and you don't need anything back. That's exactly what forEach is built for.

Use forEach when: you want to perform an action for each element and don't need a returned array.

Don't use forEach when: you need to build a new array. You'll end up pushing into an outside variable, which is more code and easier to get wrong than just using map.

Transformation: When You Want a New Array

When you want to take one array and turn it into another array of the same length, map is almost always the right choice.

Say you have product prices and you need them with tax added:

const prices = [10, 25, 50];

const pricesWithTax = prices.map(function(price) {
  return price * 1.2;
});

console.log(pricesWithTax);
[12, 30, 60]

One line of real logic, and you get exactly what you asked for: a new array. The original prices array is still [10, 25, 50], untouched and ready to use elsewhere.

Use map when: you want a new array of the same length, transformed from the original.

Don't use map when: you only want to perform actions. If you're not using the returned array, map is the wrong tool—you're building an array just to throw it away. That's why the earlier logging example with map works but is a poor choice for real code.

Knowledge check

Check your understanding

Answer this question before you continue.

Which tool best fits a task that transforms every price into a taxed price and stores the results in a new array?
Single Choice

Focus: Choose map when a transformation should produce a new array of the same length.

Early Exit: Where the for Loop Wins

Here's the job that forEach and map simply cannot do: stop early.

Both forEach and map visit every single element. There's no break statement inside them. Once you start, you're committed to the whole journey.

A for loop, though, can bail out whenever you want:

const numbers = [3, 7, 2, 9, 4, 8];
let firstOverFive = null;

for (let i = 0; i < numbers.length; i++) {
  if (numbers[i] > 5) {
    firstOverFive = numbers[i];
    break; // Stop right here
  }
}

console.log(firstOverFive);
7

The loop found 7, the first number over five, and stopped. It never looked at 2, 9, 4, or 8.

This matters more than you might think. Imagine searching a list of 10,000 customer records for the first one with a specific email. With forEach, you'd check all 10,000 even after finding your match. With a for loop, you stop at the first hit and move on.

One warning: a return inside a forEach callback does not stop the loop. It only exits the current callback, and forEach moves on to the next element. If you need to stop iterating entirely, reach for a for loop with break.

Use a for loop when: you need to stop early, skip ahead, or have precise control over the iteration.

Don't use a for loop when: you're doing a simple transformation or a simple action. The extra control comes with extra code, and you don't need it for straightforward jobs.

Knowledge check

Check your understanding

Answer this question before you continue.

A search should stop as soon as it finds the first number greater than 5. Which replacement correctly provides early exit?
Debugging

Focus: Select a loop that can stop iteration immediately after finding a matching element.

const numbers = [3, 7, 2, 9];
let firstOverFive = null;

// Choose the replacement for this comment.
// ...

console.log(firstOverFive);

Picking the Right Tool

A flowchart starts with the question of whether iteration must stop early. If yes, it points to a for loop with break. If no, it asks whether a new array is needed, pointing to map when yes and forEach for an action-only task when no.
Choose based on the job: use a for loop to stop early, map to create a new array, and forEach to perform an action.

Here's the decision rule you can carry into any future project:

  1. Need to stop early? Use a for loop.
  2. Need a new array? Use map.
  3. Just doing an action per item? Use forEach.

That's it. Three questions, three answers, no agonizing.

ToolReturnsCan stop early?Best for
for loopNothing on its ownYes, with breakSearching, complex control, early exit
forEachundefinedNoSide effects: logging, updating, sending
mapNew arrayNoTransforming data into a new array

None of these tools is "better" than the others. They're different tools for different jobs, and the choice is about your intent, not about which one is more modern or more impressive.

A Common Beginner Mistake to Avoid

Here's the mistake I see beginners make more than any other with these tools. They use map to change objects, but they forget to return anything:

const products = [
  { name: "Notebook", price: 5 },
  { name: "Pen", price: 2 }
];

const updatedProducts = products.map(function(product) {
  product.price = product.price * 1.2;
  // No return statement!
});

console.log(updatedProducts);
[undefined, undefined]

What happened? map builds its new array from whatever your callback returns. Your callback returned nothing, so map filled the new array with undefined.

This mistake is completely normal, and it's easy to fix once you understand the mechanism. You have two choices, depending on what you actually wanted.

If you wanted to change the original objects, use forEach:

const products = [
  { name: "Notebook", price: 5 },
  { name: "Pen", price: 2 }
];

products.forEach(function(product) {
  product.price = product.price * 1.2;
});

console.log(products);
[
  { name: "Notebook", price: 6 },
  { name: "Pen", price: 2.4 }
]

If you wanted a new array with transformed objects, return a new object from map:

const products = [
  { name: "Notebook", price: 5 },
  { name: "Pen", price: 2 }
];

const updatedProducts = products.map(function(product) {
  return {
    name: product.name,
    price: product.price * 1.2
  };
});

console.log(updatedProducts);
[
  { name: "Notebook", price: 6 },
  { name: "Pen", price: 2.4 }
]

The rule to remember: if you use map, you must return a value from the callback. Every single time.

One more distinction worth knowing: forEach and map don't change the array structure themselves. The original array keeps its length and order. But code inside the callback can change things. In the forEach example above, the callback changed a property on each product object. That's not the method mutating the array—it's your code doing it. If you want to avoid changing the original objects entirely, the map version that returns new objects is the safer path.

Knowledge check

Check your understanding

Answer this question before you continue.

Why does this code produce [undefined, undefined] for updatedProducts?
Misconception Check

Focus: Recognize that map fills its result array with callback return values, including undefined when nothing is returned.

const products = [{ price: 5 }, { price: 2 }];
const updatedProducts = products.map(function(product) {
  product.price = product.price * 1.2;
  // no return statement
});

Your Turn

Here's a small practice task to lock in the decision rule. Take this array:

const scores = [45, 82, 91, 67, 58, 73];

Now pick the right tool for each of these three jobs:

  1. Log each score to the console.
  2. Create a new array where every score is rounded up to the nearest multiple of 10.
  3. Find the first failing score (below 60) and stop as soon as you find it.

For job 1, you're performing an action—use forEach. For job 2, you want a new array—use map. For job 3, you need to stop early—use a for loop with break.

When you run your solutions, check what each approach gives you back. forEach returns undefined. map returns a new array you can inspect. The for loop stops at the first failing score—in this case 45—without checking the rest.

When you're done, you'll have internalized the one rule that matters: stop early means for, new array means map, action means forEach. That rule will serve you well in every JavaScript project you write from here on.

Knowledge check

Final check

Finish the article by checking the ideas you just learned.

You need to log every student's name and do not need a new array. Which tool best matches that intent?
Question 1 of 2Single Choice

Focus: Choose forEach for an action performed on every element when no returned array is needed.

Which choice follows the article's decision rule for finding the first failing score and stopping immediately?
Question 2 of 2Single Choice

Focus: Apply the decision rule by choosing a for loop when a search must stop at the first match.

const scores = [45, 82, 91, 67, 58, 73];

References

  1. Array.prototype.map() - JavaScript | MDNdeveloper.mozilla.org
7sources checked
5source domains
5searches run

Research updated Sep 6, 2026

Keep learning

Related tutorials

Continue with nearby JavaScript topics and beginner-friendly explanations.

A library shelf filled with colorful children's books, focused on educational topics.
beginner
9 min read

Arrays and Objects Basics

A variable can hold one value—and that value can be a collection holding many related values. JavaScript arrays and objects are how you build those…

Read tutorial
University student studies alone in a sunlit classroom, Buenos Aires, Argentina.
beginner
9 min read

Basic Operators in JavaScript

You've learned how to store values in variables. Now it's time to make those values do something. JavaScript operators are the verbs of your code—they add,…

Read tutorial