Do these 3 things before closing this tab:
1Scan for outdated or missing drivers - takes under a minute2Clear out junk files and repair common Windows errors3Fix the driver behind crashes, sound loss and screen glitchesUse map() when every visited element should become a value in a new array, forEach() when you need an action for each present element but no result collection, and a for loop when you need explicit indexes or control flow such as break and continue. These constructs have different contracts. Choosing among them is primarily a question of the result you need and whether the iteration must stop, wait, or run in a particular order.
The short decision guide
Start with the outcome rather than the syntax. Ask what the loop is supposed to produce, whether it may stop early, and whether each operation must be awaited before the next one starts.
As an Amazon Associate I earn from qualifying purchases.
| What your code needs | Best fit | Reason |
|---|---|---|
| Create a transformed array | map() |
Each callback result is placed in a new array. |
| Perform an action for every present element | forEach() |
The callback is called for side effects; its return value is discarded and the method returns undefined. |
Use an index, stop with break, or skip with continue |
for |
Loop statements expose those control-flow operations directly. |
| Await each asynchronous task in sequence | for...of or another await-capable for loop |
An await in the loop body controls when the next iteration begins. |
| Stop when a condition is met | some(), find(), or findIndex() |
These array methods short-circuit; forEach() does not. |
If you choose map(), keep the returned array. If you choose forEach(), do not expect a returned collection. If you need to leave the iteration early, use a loop statement or an array method designed to short-circuit.
What each construct promises
map() is a transformation
map() calls a callback for each assigned array index and builds a new array from the values returned by that callback. The original array is not the output; the value returned by map() is.
#1 Best Overall
const prices = [10, 20, 30];
const withTax = prices.map((price) => price * 1.1);
console.log(withTax); // [11, 22, 33]
console.log(prices); // [10, 20, 30]
The callback can return a number, string, object, array, or any other value. The important contract is one callback result per visited element, collected into a new array. A common mistake is to call map() only for its callback side effect and then ignore the returned array. MDN describes that pattern as an anti-pattern: when no transformed array is needed, use forEach() or for...of instead.
forEach() is an action over elements
forEach() invokes a callback for each present element and always returns undefined. Returning a value from the callback does not add anything to a result array.
const prices = [10, 20, 30];
const returnValue = prices.forEach((price) => {
console.log(`Price: ${price}`);
return price * 1.1;
});
console.log(returnValue); // undefined
The returned value in the callback is discarded. Use this form when the useful result is an observable action such as logging, updating an existing object, sending a notification, or adding a DOM node. If the useful result is a new collection, map() communicates that intent more accurately.
A for loop is explicit control flow
A traditional for loop gives you an index and places the loop body under normal statement control. That makes it the direct choice when an iteration may end early, skip selected items, move by a custom increment, or coordinate several indexes.
const prices = [10, 20, 30];
for (let i = 0; i < prices.length; i++) {
if (prices[i] > 20) {
break;
}
console.log(prices[i]);
}
This prints 10 and 20, then exits before processing 30. A continue statement skips the remainder of the current body and advances to the next iteration.
for (let i = 0; i < prices.length; i++) {
if (prices[i] <= 10) {
continue;
}
console.log(`Higher price: ${prices[i]}`);
}
When you do not need the numeric index, for...of can retain loop control while making the element value explicit:
Rank #2
for (const price of prices) {
if (price > 20) break;
console.log(price);
}
Return values: the difference that prevents many bugs
| Construct | What the callback returns | What the construct returns | When that return is useful |
|---|---|---|---|
map() |
One value for each visited element | A new array containing those values | Use it as the transformed data for another operation or assignment. |
forEach() |
Ignored | undefined |
There is no collection result; the callback performs the work. |
for |
Not applicable to the loop itself | No automatic array result | Assign, accumulate, return, or break explicitly in the body. |
For example, this code does not populate doubled:
const doubled = [];
[1, 2, 3].forEach((number) => {
number * 2;
});
console.log(doubled); // []
Use map() for the direct transformation:
const doubled = [1, 2, 3].map((number) => number * 2);
Or, if a side effect is intentional, make it visible in the loop body:
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →const doubled = [];
[1, 2, 3].forEach((number) => {
doubled.push(number * 2);
});
The second version works, but map() states the one-to-one transformation more clearly and avoids managing an output array yourself.
Early exit: why forEach() cannot be broken
break and continue are statements for loop constructs. They cannot be used to leave a forEach() callback in the normal way. A return inside that callback returns from the callback invocation, not from the surrounding forEach(), so later elements are still visited.
const numbers = [1, 2, 3, 4];
numbers.forEach((number) => {
if (number === 2) return;
console.log(number);
});
// Logs 1, 3, and 4
If the operation must stop at a particular element, choose the construct that expresses that requirement.
Use a loop when the stopping logic is procedural
for (const number of numbers) {
if (number === 2) break;
console.log(number);
}
This stops immediately after processing 1. It also lets you combine several conditions, update external state, or use continue for selective processing.
Use a short-circuiting array method for a predicate
If the question is “does any element satisfy this condition?”, some() stops when the predicate succeeds. If you need the matching value, find() returns it; if you need its position, findIndex() returns the index.
const hasLargeOrder = orders.some((order) => order.total > 1000);
const firstLargeOrder = orders.find((order) => order.total > 1000);
const firstLargeIndex = orders.findIndex((order) => order.total > 1000);
These methods communicate a search or test better than trying to force an early exit from forEach().
Asynchronous callbacks: the forEach() trap
Marking a forEach() callback as async does not make forEach() wait for the promises it produces. The method invokes the callbacks and then returns undefined; there is no promise from forEach() for you to await.
await items.forEach(async (item) => {
await saveItem(item);
});
console.log('This can run before saveItem finishes');
The outer await has nothing useful to wait for in this example. Depending on the surrounding code, errors from the asynchronous callbacks may also escape the expected error-handling path.
Sequential asynchronous work
Use an await-capable loop when each task must finish before the next starts, or when order and rate control matter.
async function saveInOrder(items) {
for (const item of items) {
await saveItem(item);
}
}
The next iteration begins only after saveItem(item) fulfills. This is suitable when later work depends on earlier work, the remote service requires ordered requests, or you deliberately want to limit concurrency.
Concurrent asynchronous work
When operations are independent and concurrent execution is appropriate, create the promises and await their aggregate:
Rank #4
async function saveConcurrently(items) {
await Promise.all(items.map((item) => saveItem(item)));
}
Here map() is being used to build the array of promises, and Promise.all() waits for that array. This is different from asking forEach() to handle promises: the promises are explicitly collected and awaited. Confirm that the service, browser, memory budget, and error policy can handle concurrent work before using this pattern.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Sparse arrays and empty slots
JavaScript arrays can have a length greater than their number of assigned elements. An empty slot is not the same thing as an element whose value is explicitly undefined. Both map() and forEach() skip empty slots: their callbacks run only for assigned indexes.
const sparse = [];
sparse[1] = 7;
let mapCalls = 0;
const mapped = sparse.map((value) => {
mapCalls++;
return value * 2;
});
let forEachCalls = 0;
sparse.forEach(() => {
forEachCalls++;
});
console.log(sparse.length); // 2
console.log(mapCalls); // 1
console.log(forEachCalls); // 1
console.log(0 in mapped); // false: the hole remains a hole
If your algorithm must inspect every numeric position, including holes, an indexed for loop makes that behavior explicit. Reading an unassigned position produces undefined, so you can decide whether to treat it as missing data, skip it, or replace it.
for (let i = 0; i < sparse.length; i++) {
const value = sparse[i];
console.log(i, value); // logs index 0 with undefined and index 1 with 7
}
Choosing by intent: practical examples
Convert records to display labels
Each record produces one string, so map() is the natural contract.
const labels = users.map((user) => `${user.lastName}, ${user.firstName}`);
The resulting labels array can be passed to another function, rendered, filtered, or stored. No manual push() is needed.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallCrashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWrite audit messages
Logging does not require an output array. Use forEach() when every present record should trigger the action.
Best Value
events.forEach((event) => {
console.info(event.timestamp, event.type);
});
Stop processing after a threshold
A loop statement is clearer when processing should end as soon as a condition becomes true.
let total = 0;
for (const amount of payments) {
total += amount;
if (total >= target) break;
}
Skip invalid entries but continue
continue belongs naturally in a loop body.
for (const item of items) {
if (!item.isValid) continue;
process(item);
}
You can express some filtering-and-transformation pipelines with filter() followed by map(), but a loop may be easier to read when validation, logging, counters, and early exit all belong in one procedure.
Common mistakes and their fixes
- Ignoring a
map()result: If you callitems.map(transform)without using the returned array, replace it withforEach(transform)or afor...ofloop when the purpose is only a side effect. - Expecting
forEach()to return transformed data: Assigning its result givesundefined. Usemap()for a new array. - Trying to use
breakinsideforEach(): Move the operation to afororfor...ofloop, or choosesome(),find(), orfindIndex()for a short-circuiting test. - Awaiting
forEach(): Replace it with a sequential await-capable loop or explicitly create promises and pass them toPromise.all()when concurrency is intended. - Assuming callbacks run for holes: Sparse-array holes are skipped by both
map()andforEach(). Use an indexed loop if every position must be examined. - Choosing based on an assumed speed ranking: These constructs have different semantics, and there is no universal winner established by the referenced documentation. Benchmark representative code in the engine, runtime, and workload that matter to your application.
A repeatable selection process
- Define the output. If you need a new array with one derived value per visited element, start with
map(). If there is no output collection, considerforEach()or a loop. - Check for early termination. If the body needs
break,continue, an index, or a custom increment, use aforloop. For a simple existence or search test, use a short-circuiting array method. - Check asynchronous ordering. Sequential work belongs in an await-capable loop. Independent concurrent work can use
Promise.all()around an explicitly constructed promise array. - Check the data shape. If sparse arrays are possible, decide whether holes should be skipped or inspected as positions.
- Make the intent visible to the next reader. A transformation should look like a transformation; a side effect should look like a side effect; procedural control flow should use a loop statement.
- Measure only when it matters. If a hot path requires optimization, benchmark realistic inputs and operations in the target JavaScript engine instead of relying on a blanket claim that one form is faster.
Performance: what can and cannot be concluded
The referenced MDN documentation explains behavior and contracts, not a comparative benchmark that ranks for, forEach(), and map() across engines. Runtime performance varies with the JavaScript engine, version, array shape, callback work, allocation, and surrounding program. A loop that avoids creating an output array may have a different memory profile from map(), but that observation does not establish a universal speed result.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
For performance-sensitive code, measure the actual workload: use representative array sizes, realistic callback operations, warm-up behavior, and the deployment engine. Keep the clearer construct unless a measurement demonstrates a meaningful improvement and the change does not obscure correctness.
Further JavaScript reading
For a broad reference rather than a dedicated comparison of these three constructs, JavaScript: The Definitive Guide, 7th Edition by David Flanagan was published in May 2020. The publisher’s description includes arrays, iterators, Promises, and async/await, making it useful for readers who want the surrounding language concepts as well as array iteration.
Bottom line
Choose by contract: map() returns a transformed array, forEach() performs an action and returns undefined, and for gives you explicit control over indexes, stopping, skipping, and waiting. Once the desired result and control flow are clear, the appropriate construct is usually obvious.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

