Iterator.prototype.toArray()

Collect every remaining value of an iterator into a new array.

Signature
toArray()
  • Added in JavaScript ES2025 (Baseline March 2025)

Return value

ArrayA new Array instance containing the elements produced by the iterator, in the order they were produced.

Errors

Throws a TypeError if called on a value that is not an object; it does not terminate at all on an infinite iterator.

toArray() is how a lazy chain becomes a concrete value. It is equivalent to Array.from(iterator) and to [...iterator], but it reads as the last link in a chain instead of wrapping the whole expression in brackets — which is the real reason it exists.

When to reach for it

  • Ending a pipeline of helpers when you need indexing, length, or a second pass.
  • Snapshotting an iterator so it can be iterated more than once.
  • Handing results to an API that expects an array.

What trips people up

Put it last. src.take(10).toArray().filter(pred) works, but it materialises ten elements and then discards some; src.take(10).filter(pred).toArray() filters lazily and allocates one array of exactly the survivors. Every helper you move after toArray() loses its laziness.

It is also unbounded. On an infinite generator it never returns and freezes the thread — always bound with take() first. And it collects only what remains: if you have already pulled two values with next(), those two are not in the array.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Turn a bounded generator into an array for indexing or length checks
  • Snapshot a Set or Map iterator so it can be traversed twice
  • Finish a map/filter chain before passing the result to a function expecting an array

Frequently asked questions

What is the difference between toArray() and the spread operator?

None in result — toArray(), [...iterator] and Array.from(iterator) all produce the same array. toArray() just reads better at the end of a helper chain, since spreading would require wrapping the entire expression in brackets. All three hang identically on an infinite iterator.

Should toArray() come before or after filter()?

After. Keeping filter() and map() on the lazy side means work is skipped for elements you never keep, and only one array is allocated. Moving them after toArray() forces every element through both the array allocation and the callback.

Why is my array missing the first few values?

Because those values were already pulled from the iterator before you called toArray(), which collects only what remains. Any earlier next() call, for...of loop that broke early, or partial destructuring consumes elements permanently. Start from a fresh iterator if you need all of them.

More examples

Placement changes how much work happens

Filtering before toArray() stops as soon as take(1) is satisfied, testing two elements. Collecting first forces the predicate to run on all four.

Example · javascript
let calls = 0;
const pred = (n) => {
  calls++;
  return n % 2 === 0;
};

[1, 2, 3, 4].values().filter(pred).take(1).toArray();
console.log("lazy calls:", calls); // 2

calls = 0;
[1, 2, 3, 4].values().toArray().filter(pred).slice(0, 1);
console.log("eager calls:", calls); // 4

Snapshotting for a second pass

An iterator is single-use, so the second toArray() on the same iterator is empty. Storing the array gives you length, at(), and as many passes as you want.

Example · javascript
function* ids() {
  yield* ["a1", "a2", "a3"];
}

const it = ids();
console.log(it.toArray()); // ["a1", "a2", "a3"]
console.log(it.toArray()); // [] — exhausted

const snapshot = ids().toArray();
console.log(snapshot.length, snapshot.at(-1)); // 3 "a3"

Discussion

  • Be the first to comment on this lesson.