Iterator.prototype.map()
Transform each value of an iterator lazily, producing a new iterator of the callback's results.
map(callbackFn)- Added in JavaScript ES2025 (Baseline March 2025)
Parameters
| Parameter | Type | Description |
|---|---|---|
$callbackFn | Function | Called for each element as callbackFn(element, index); its return value is what the helper yields. element is the current value and index is its zero-based position in the iteration. |
Return value
Iterator HelperA new iterator helper object. Each next() call pulls one value from the underlying iterator, passes it through callbackFn, and yields the result; once the underlying iterator is done it produces { value: undefined, done: true }.
Errors
Throws a TypeError if callbackFn is not callable, or if the method is called on a value that is not an object.
This is Array.prototype.map() without the array. Nothing is computed when you call it — you get a helper object, and each value is transformed only when someone pulls it, whether that is a for...of loop, a spread, toArray(), or a bare next().
When to reach for it
Reach for it whenever the source is not already an array: a generator, map.entries(), set.values(), a regex's matchAll(), or anything infinite. It is also the right tool when the source is an array but you plan to stop early — arr.values().map(expensive).take(3) calls expensive three times, while arr.map(expensive).slice(0, 3) calls it for every element.
What trips people up
Laziness means side effects inside the callback are deferred. If the callback logs, mutates, or throws, none of that happens until the chain is consumed; a helper that is built and never iterated does nothing at all.
The helper is also single-use. Once it is exhausted it stays done, and it shares state with the source iterator, so consuming the helper consumes the source. Build the chain again from a fresh iterator if you need a second pass.
Example
When to use it
- Reshape entries from a Map into display strings without materialising an array
- Apply an expensive transform to only the first few results of a long sequence
- Convert values from an infinite generator before taking a window of them
Frequently asked questions
How is this different from Array.prototype.map()?
It is lazy and returns an iterator rather than an array. The array version transforms every element immediately and allocates a new array; the iterator version transforms one element per next() call and allocates nothing, so it works on infinite sequences and skips work you never consume. The callback also receives only (element, index) — there is no third array argument and no thisArg parameter.
Can I use map() on an infinite generator?
Yes, that is a main reason it exists. Because it only transforms values on demand, mapping an endless generator returns instantly; just make sure something downstream bounds it — take(n), a break in a for...of loop, or find/some — before you call toArray(), which would otherwise loop forever.
Why does my mapped iterator return nothing the second time?
Iterator helpers are single-use: once exhausted they permanently report done, and they consume the underlying iterator too. Rebuild the chain from a fresh source — call the generator function again or take a new values() iterator — or collect the results once with toArray() and reuse that array.
More examples
Proving the laziness
The two 'transforming' lines appear only after next() is called, and the third element is never touched because it is never pulled. With Array.prototype.map() all three would have run before the first log.
const chain = [1, 2, 3].values().map((n) => {
console.log("transforming", n);
return n * 2;
});
console.log("chain built, nothing logged yet");
console.log(chain.next().value); // 2
console.log(chain.next().value); // 4
console.log("stopping early");The index argument, and single use
The callback's second argument counts positions in the iteration. The second toArray() returns an empty array: an exhausted helper stays done, and it drained the underlying array iterator along with it.
const rows = ["ann", "bo", "cy"].values();
const numbered = rows.map((name, i) => `${i + 1}. ${name}`);
console.log(numbered.toArray()); // ["1. ann", "2. bo", "3. cy"]
// The helper and its source are both exhausted now.
console.log(numbered.toArray()); // []
console.log(rows.next()); // { value: undefined, done: true }
Discussion