-
-
Notifications
You must be signed in to change notification settings - Fork 0
Iterators
JavaScript provides a notion of iterators and helpers to deal with them:
Modern runtimes (Node 22+, current Bun, Deno, and browsers) ship native iterator helpers
(Iterator.from(), .map(), .filter(), .take(), .drop(), .flatMap(), …).
This module doesn't reimplement them: it bridges the iterator/iterable protocols and delegates
to the native helpers when they are available. On runtimes with Iterator.from(),
normalizeIterator() is the gateway to the whole native helper family:
normalizeIterator(it).take(3).
Legend for tables
-
API
-
iterator— an iterator object. See the iterator protocol. -
callbackFn— a function used by Iterator.prototype.map() or the other corresponding methods.
-
The following utilities are available:
| Function | Return value | Description |
|---|---|---|
augmentIterator(iterator) |
iterator | Augment iterator with an iterable interface if it is not defined. |
normalizeIterator(iterator) |
iterator | Similar to augmentIterator(), but can use Iterator.from() if it is defined. |
mapIterator(iterable, callbackFn) |
iterator | Creates a lazy iterator that calls the callback function for each element and returns the result as a value. |
filterIterator(iterable, callbackFn) |
iterator | Creates a lazy iterator that emits the values for which the callback function returns truthy. |
mapIterator() and filterIterator() accept an iterable or a bare iterator and always return
a lazy, single-use iterable iterator — even for arrays (they never build an eager array).
return() is forwarded to the source, so an early exit (e.g. break in for...of) closes
the source iterator and runs its cleanup (finally blocks in generators). On modern runtimes
they delegate to the native Iterator.prototype.map()/.filter().
augmentIterator() and normalizeIterator() are here to bridge the gap between the iterable protocol
and the iterator protocol to connect to all JavaScript iteration mechanisms.
The iterator protocol defines a set of methods that can be used to iterate over
a collection of elements. The iterable protocol defines a special method Symbol.iterator that
returns an iterator. for...of and other JavaScript facilities expect iterables. The way to make an iterable
out of an iterator is to define Symbol.iterator on the iterator returning this. That is what
augmentIterator() does.
normalizeIterator() tries to use Iterator.from() if it is available and falls back to augmentIterator().
In most cases, augmentIterator() and normalizeIterator() are used by library implementors.
On runtimes without native helpers, normalizeIterator() degrades to augmentIterator()
(no helper methods) — mapIterator() and filterIterator() remain the portable
transformation helpers, modelled on
Iterator.prototype.map() and Iterator.prototype.filter() respectively.
This module deliberately wraps no further helpers — reach for the native family through
normalizeIterator() when you need take/drop/flatMap/….
import {normalizeIterator, filterIterator, mapIterator} from 'meta-toolkit/iterators.js';
class Range {
constructor(from, to) {
this.from = from;
this.to = to;
}
[Symbol.iterator]() {
let index = this.from;
return normalizeIterator({
next: () => {
if (index >= this.to) return {done: true};
return {value: index++, done: false};
}
});
}
static from(from, to) {
return new Range(from, to);
}
}
for (const x of Range.from(1, 5)) {
console.log(x); // 1, 2, 3, 4
}
const range = new Range(1, 5),
odds = filterIterator(range, x => x % 2),
squared = mapIterator(odds, x => x * x);
for (const x of squared) {
console.log(x); // 1, 9
}All functions are exported by their names. There is no default export.
API
Reference