PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, 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 minuteiTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Choose map() when every visited array element should become a value in a new array. Choose forEach() when you need an action for each present element and no result collection. Choose a classic for loop when index control, break, continue, or ordered asynchronous work matters.
These constructs are different contracts, not interchangeable spellings. The useful question is what your code must return, whether it must stop early, and whether each operation has to wait for the previous one.
Quick decision: for, forEach(), or map()?
| What your code needs | Best fit | Why | What it returns |
|---|---|---|---|
| Build a transformed array | map() |
Each callback result is placed at the corresponding position in a new array. | A new array |
| Perform an action for every present element | forEach() |
The callback is for side effects; its return value is discarded. | undefined |
Use an index explicitly, stop with break, or skip with continue |
for |
Loop statements expose normal control flow and index management. | Whatever you return from the surrounding function, or no value if you do not return |
| Await each operation before starting the next | An await-capable loop, such as for...of or a classic for inside an async function |
The loop can pause at await. |
A promise from the surrounding async function |
| Stop when a condition is met | some(), find(), or findIndex() |
These array methods have short-circuit behavior; a loop also works when you need more control. | Method-specific result, such as a boolean, element, or index |
Use the construct whose contract matches the outcome. Do not use map() merely because it is concise if you will throw away its returned array, and do not use forEach() when the operation must stop or wait.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →How map() works
map() is a transformation operation. It calls its callback for each assigned array index and stores the callback’s result in a new array at the corresponding index. The original array is not replaced by that operation.
#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 returned array is the point of using map(). If you need to retain the transformed values, assign the result, return it from a function, or pass it to another operation:
function addTax(prices, rate) {
return prices.map((price) => price * (1 + rate));
}
const totals = addTax([10, 20, 30], 0.1);
MDN describes calling map() without using its returned array as an anti-pattern and recommends forEach() or for...of for side effects. A callback can return any value, including an object, string, boolean, or promise; that value becomes an element in the new array.
Returning objects from map()
When an arrow function returns an object literal, wrap the object in parentheses so JavaScript parses it as an expression:
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Repair Windows errors before they cause bigger problems3Scan for outdated or missing drivers - takes under a minuteconst users = [
{ id: 1, name: 'Ada' },
{ id: 2, name: 'Lin' }
];
const labels = users.map((user) => ({
id: user.id,
label: user.name.toUpperCase()
}));
The result is a separate array of new objects. If your callback mutates an object from the original array, the object itself is still shared; map() does not deep-clone values.
When map() is the wrong tool
This code computes an array and then discards it:
prices.map((price) => console.log(price));
It works mechanically, but it communicates the wrong intent and allocates a result that is not needed. Use:
prices.forEach((price) => console.log(price));
or use a loop when you also need control statements.
How forEach() works
forEach() visits each assigned array index in order and calls your callback. It is designed for side effects such as logging, updating an external accumulator, rendering, or sending a notification. The method itself returns undefined, and whatever the callback returns is discarded.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
const prices = [10, 20, 30];
prices.forEach((price, index) => {
console.log(`Item ${index}: $${price}`);
});
There is no output array to capture:
const result = prices.forEach((price) => price * 1.1);
console.log(result); // undefined
If you need an accumulated result, use map() for one output per input, a reducer for a single aggregate, or an explicit loop with an accumulator. Do not expect a value returned from the callback to escape through forEach().
Rank #2
Use forEach() for clear side effects
const messages = ['Saved', 'Queued', 'Sent'];
messages.forEach((message) => {
analytics.track('status_seen', { message });
});
This reads as “perform this action for every present element.” Keep the callback focused; if it becomes responsible for filtering, accumulating, error recovery, and multiple control branches, a loop or a chain of purpose-built array methods may be easier to verify.
How a classic for loop works
A classic for statement gives you explicit initialization, a condition, and an update expression:
for (let i = 0; i < prices.length; i += 1) {
console.log(prices[i]);
}
That extra ceremony is useful when the index itself matters, when you must compare neighboring elements, when you need to mutate a counter by more than one step, or when control flow can end the loop early.
break exits immediately
for (let i = 0; i < prices.length; i += 1) {
if (prices[i] > 20) {
break;
}
console.log(prices[i]);
}
The loop logs 10, then encounters 20? No: with the condition shown, it logs 10 and 20, then stops before logging 30 because 30 is greater than 20. The important property is that no later iteration runs after break.
continue skips the current iteration
for (let i = 0; i < prices.length; i += 1) {
if (prices[i] <= 10) {
continue;
}
console.log(prices[i]);
}
Here the update expression still runs, and the next index is tested. This makes continue useful for excluding known cases while retaining the rest of the loop.
When the index is part of the algorithm
Some algorithms need two positions or need to move the index conditionally:
const values = [3, 8, 2, 9];
let firstPairOverTen = null;
for (let i = 0; i < values.length - 1; i += 1) {
if (values[i] + values[i + 1] > 10) {
firstPairOverTen = [i, i + 1];
break;
}
}
You can express many such tasks with array methods, but a loop makes the index movement and early exit explicit.
Return values: the distinction that prevents bugs
| Construct | Callback result | Method result | Typical use |
|---|---|---|---|
map() |
Becomes an element in the new array | New array with the same length as the visited array shape | Transform each input |
forEach() |
Discarded | undefined |
Perform an action |
for |
There is no callback | No method result; use variables, return, or break in surrounding code |
Custom control flow |
A common mistake is expecting this function to return a transformed array:
function double(values) {
values.forEach((value) => value * 2);
}
console.log(double([1, 2, 3])); // undefined
Use map() when the function’s contract is “return one doubled value for each input”:
function double(values) {
return values.map((value) => value * 2);
}
Alternatively, use an explicit accumulator when the output is not one-to-one:
function sum(values) {
let total = 0;
for (let i = 0; i < values.length; i += 1) {
total += values[i];
}
return total;
}
Early exit: why forEach() cannot be broken normally
break and continue belong to loop statements. They cannot be used to leave a forEach() callback in the same way:
// Syntax error: break is not inside a loop statement.
values.forEach((value) => {
if (value > 20) break;
});
Do not throw an exception merely to simulate normal loop control. Choose an operation whose contract includes short-circuiting.
Use some() for “does any element match?”
const hasLargeValue = values.some((value) => value > 20);
some() stops when its predicate succeeds and returns a boolean.
Use find() for the matching element
const firstLargeValue = values.find((value) => value > 20);
find() stops at the first match and returns that element, or undefined when no element matches.
Use findIndex() for the matching position
const firstLargeIndex = values.findIndex((value) => value > 20);
findIndex() returns the first matching index or -1. If you need several conditions, cleanup, or multiple statements around the exit, use a for loop.
Asynchronous callbacks: the forEach() trap
An async callback does not make forEach() wait. The method invokes the callbacks and returns undefined without awaiting the promises they create.
Rank #4
async function saveAll(records) {
records.forEach(async (record) => {
await save(record);
});
console.log('done');
}
In this example, “done” can be logged before any save has finished. Rejections also are not collected by forEach() for the caller to await. The problem is not that the callback cannot be asynchronous; it is that forEach() has no promise-aggregation contract.
Run asynchronous work sequentially
Use an await-capable loop when each operation must finish before the next starts, or when order and rate limits matter:
async function saveInOrder(records) {
for (const record of records) {
await save(record);
}
}
A classic index loop works when you need numeric index control:
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →async function saveInOrder(records) {
for (let i = 0; i < records.length; i += 1) {
await save(records[i]);
}
}
These functions resolve after every awaited operation completes. They also make it straightforward to stop on an error or add a conditional continue.
Run asynchronous work concurrently
If operations are independent and concurrent execution is appropriate, create the promises and await their aggregate:
async function saveConcurrently(records) {
await Promise.all(records.map((record) => save(record)));
}
Here map() is useful because its result is the array of promises consumed by Promise.all(). Do not use this pattern when the server, database, API quota, ordering requirement, or resource limit requires sequential work. If one promise rejects, Promise.all() rejects; design error handling for that behavior.
Sparse arrays and empty slots
map() and forEach() do not call their callbacks for empty slots in a sparse array. An empty slot is different from an element whose value is explicitly undefined.
Free tools Windows power users keep installed
One-click scans. No signup required.
const sparse = [];
sparse[2] = 'third';
sparse.forEach((value, index) => {
console.log(index, value);
});
// Logs only: 2 'third'
const mapped = sparse.map((value) => value.toUpperCase());
console.log(mapped.length); // 3
// The result retains an empty slot at indexes 0 and 1.
A classic indexed for loop evaluates every numeric index you request, so reading a missing position produces undefined. If your algorithm must distinguish holes, test with care rather than assuming all three constructs visit the same set of positions.
Best Value
Common scenarios and the right choice
Convert API records into display rows
const rows = records.map((record) => ({
id: record.id,
title: record.name.trim()
}));
Each input record produces one output row, so map() documents the one-to-one transformation.
Write each item to a logger
records.forEach((record) => {
logger.info('record_seen', { id: record.id });
});
No collection is needed, so forEach() is clearer than creating and discarding an array.
Stop scanning after a threshold
for (let i = 0; i < readings.length; i += 1) {
if (readings[i] > LIMIT) {
alert(readings[i]);
break;
}
}
A loop expresses the required exit directly. If you only need to know whether a threshold exists, readings.some((reading) => reading > LIMIT) is more declarative.
Skip invalid records and process the rest
for (const record of records) {
if (!record.id) {
continue;
}
process(record);
}
continue keeps the valid-record path uncluttered. A filter() followed by forEach() can also work when creating an intermediate collection is acceptable.
Build request promises, then await all of them
const requests = endpoints.map((endpoint) => fetch(endpoint));
const responses = await Promise.all(requests);
The array returned by map() is used, so this is a meaningful transformation rather than a side-effect loop.
Is one faster: for, forEach(), or map()?
There is no universal speed winner established by the cited documentation. Runtime depends on the JavaScript engine, version, array shape, callback work, allocation, input size, and surrounding program. A statement such as “for is always fastest” is too broad without a benchmark that specifies those conditions.
Start with the clearest correct contract. If performance is genuinely important, measure representative code in the target engine and workload:
Recommended Free Tools
- Use the same input sizes and data shapes your application sees.
- Include the real callback work, not an empty operation that exaggerates loop overhead.
- Warm up the code when the engine’s optimization behavior affects the measurement.
- Measure enough iterations to reduce noise, and compare the complete operation, including allocations.
- Confirm that an apparent improvement does not change behavior, ordering, error handling, or memory use.
Optimize after profiling identifies a real bottleneck. Choosing map() for a transformation and forEach() for a side effect usually improves maintainability regardless of tiny loop-overhead differences.
Failure modes and fixes
- “My
forEach()result is undefined.” The method always returnsundefined. Replace it withmap()for an output array or return an accumulator from a surrounding function. - “My
map()code does not change anything.” You may be ignoring the returned array. Assign, return, or consume it. - “
breakwill not compile insideforEach().” Use aforloop, or usesome(),find(), orfindIndex()for their built-in short-circuit behavior. - “The function logs completion before async work finishes.” An async
forEach()callback is not awaited. Use a sequential await-capable loop orPromise.all(items.map(work))when concurrency is safe. - “A sparse array produced fewer callbacks than expected.” Empty slots are skipped by
map()andforEach(). Decide whether holes should be preserved, filled, or handled by an indexed loop. - “The code is hard to read despite using a short method.” Switch to the construct that states the algorithm’s real contract. Brevity is not a substitute for explicit control flow.
A practical selection checklist
- Ask whether the operation must produce a new array. If yes, use
map()and use its return value. - If there is no result collection, ask whether the callback is simply performing an action. If yes, use
forEach(). - If you need
break,continue, a mutable index, multiple counters, or conditional index movement, use aforloop. - If every asynchronous operation must finish in sequence, put
awaitin an await-capable loop. - If independent asynchronous operations may run together, build promises with
map()and explicitly awaitPromise.all()or another deliberate aggregation strategy. - If the task ends at the first match, prefer
some(),find(), orfindIndex()unless the loop needs additional control. - Check sparse-array behavior when inputs may contain empty slots.
- Benchmark only after correctness and clarity are established, and only in the environment that matters.
Further reading
For broader JavaScript coverage, O’Reilly lists JavaScript: The Definitive Guide, 7th Edition by David Flanagan, published in May 2020. Its coverage includes arrays, iterators, Promises, and async/await; it is general reference material rather than a dedicated comparison of these three loop forms.
Technical references
The behavior described here follows the current MDN Web Docs references for Array.prototype.forEach(), Array.prototype.map(), and the for statement, plus MDN’s indexed-collections guide, accessed October 7, 2026.
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.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.

