iterator-helpers-polyfill
v3.0.1
Published
A polyfill for Iterator helpers proposal
Downloads
18,142
Maintainers
Readme
Iterator Helpers Polyfill
This is a dependenciless ES2018+ polyfill for Iterator Helpers Proposal.
The polyfill aims to be as specification-conformant as possible.
NOTE: By default this package is pure: to add the Iterator
and AsyncIterator
as globals please use the installIntoGlobal
function to add them into globalThis
.
NOTE By default Iterator.range
and AsyncIterator.range
are not inclusive in contrary to what was shown in the previous version of examples and this has been fixed and new inclusive
parameter is introduced to control that.
Method Documentation
Polyfilled methods
These methods were polyfilled word-to-word as specified in the iterator helpers proposal.
.map(mapper);
Transforms each this
iterator value by calling passed mapper function.
Example:
Iterator.range(1, 5, 1, true).map(x => x * 2).toArray(); // [2, 4, 6, 8, 10]
.filter(filterer);
Filters each value out from this
iterator if called filterer function returns false for this value.
Example:
Iterator.range(1, 10, 1, true).filter(x => x % 2 === 1).toArray(); // [1, 3, 5, 7, 9]
.asIndexedPairs();
Aliases: .enumerate(); .entries();
Transforn each value of this
iterator into array of value's position index in the iterator and value itself.
Example:
Iterator.range(1, 10, 1, true).map(x => Math.random() * 256 | x).asIndexedPairs().toArray() // [[0, 153], [1, 94], ...]
.drop(times: number);
Aliases: .skip();
Drops values from this
iterator passed number of times (throws error if negative).
Example:
Iterator.range(1, 10, 1, true).drop(5).toArray(); // [6, 7, 8, 9, 10]
.take(times: number);
Takes values from this
iterator passed number of times (throws error if negative).
Example:
Iterator.range(1, 10, 1, true).take(5).toArray(); // [1, 2, 3, 4, 5]
.every(fn);
Returns true if this
iterator is empty or every value of it satisfies function fn
.
Examples:
Iterator.range(2, 10, 1, true).every(x => x % 2 === 0); // false
Iterator.range(1, 10, 1, true).every(x => x > 0); // true
Iterator.from().every(() => false); // true
.find(finder);
Returns first value of this
iterator that satisfies function finder
.
Example:
Iterator.range(1, 10, 1, true).find(x => x % 2 === 0) // 2
.flatMap(mapper);
Yields values of each transformed values of this
iterator by calling mapper (throws when mapper function throws non-iterable/iterator value).
Examples:
Iterator.range(1, 4, 1, true).flatMap(x => `${ x }`.repeat(x)).toArray(); // ["1", "2", "2", "3", "3", "3", "4", "4", "4", "4"]
Iterator.range(1, 5, 1, true).flatMap(function* (x) {
yield x ** 2;
yield x * 10;
}).toArray(); // [1, 10, 4, 20, 9, 30, 16, 40, 25, 50]
.forEach(mapper);
Calles mapper function with each value of this
iterator and returns undefined
.
Example:
Iterator.range(1, 5, 1, true).forEach(console.log);
// Console output:
// 1
// 2
// 3
// 4
// 5
.reduce(reducer, initialValue?);
TLDR: basically same as Array.prototype.reduce()
.
Firstly, this method creates an accumulator variable for later use from initialValue
parameter if it's specified or gets first value of this
iterator or throws if neither of these were the case.
Then it takes following values and calls reducer
function with them and accumulator and then assigns result of the call to the accumulator variable.
Examples:
Iterator.range(1, 10, 1, true).reduce((accumulator, x) => accumulator + x); // 55
["This", "is", "interesting!"].values().reduce((accumulator, x) => `${ accumulator } ${ x }`); // "This is interesting!"
["this", "is", "also", "interesting!"].values().reduce((accumulator, x) => `${ accumulator } ${ x }`, "And also i know that"); // "And i also know that this is interesting!"
Iterator.from().reduce(() => { throw "Never happens!" }, 1); // 1
Iterator.from().reduce(() => {}); // This throws an error since iterator is empty and no `initialValue` parameter is specified.
Iterator.from().reduce(() => {}, undefined); // But this works since `initialValue` parameter is set to the undefined value; undefined
.some(filterer);
Returns true if this
iterator is empty or also returns true if some values of this
satisfy condition function filterer
or returns false otherwise.
Examples:
Iterator.range(1, 10, 1, true).some(x => x === 5); // true
Iterator.from().some(() => {}); // true
.toArray();
Returns array containing all values of this
iterator.
Example:
Iterator.range(1, 5, 1, true).toArray(); // [1, 2, 3, 4, 5]
Iterator.from(value);
Returns a iterator if value is a valid iterable (if iterator is with %Iterator.prototype% in the prototype chain) or wraps invalid iterator into %WrapForValidIteratorPrototype%.
Examples:
Iterator.from([0, 1, 2, 3, 4]); // same as [0, 1, 2, 3, 4][Symbol.iterator]();
Iterator.from({ next() { return { done: true, value: undefined } } }); // wrapped into %WrapForValidIteratorPrototype%.
Additional methods
.max();
Returns maximum number found in this
iterator.
Example:
Iterator.from([0, -9, 23, 96, 10, 92]).max(); // 96
.max();
Returns minimal number found in this
iterator.
Example:
Iterator.from([0, -9, 23, 96, 10, 92]).min(); // -9
.average();
Returns average number from all the numbers from this
iterator.
Example:
Iterator.from([10, 50, 40, 20]).average(); // 30
.chain(...iterators);
Returns an iterator which yields values sequencially of this
iterator first and then all the iterators
one by one left to right.
Example:
Iterator.range(1, 3, 1, true).chain(Iterator.range(4, 6, 1, true), Iteratior.range(7, 10, 1, true)).toArray; // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.join(separator: string = ", ");
TLDR: Same as Array.prototype.join()
but default separator is ", "
, not ","
.
Returns a string of all values of this
iterator stringified and joined by seperator
.
Example:
Iterator.range(1, 5, 1, true).join(); // "1, 2, 3, 4, 5"
.cycle(times: number = Infinity);
Aliases: .repeat()
Repeats values of this
iterator passed number of times or infinite amount of times if nothing is passed as times
argument.
Example:
Iterator.range(1, 3, 1, true).cycle(2).toArray(); // [1, 2, 3, 1, 2, 3]
(Async)Iterator.range(start: number, end: number = (_ => (start = 0, _))(start), step: number = 1, inclusive: boolean = false)
Produces range of number values from start
to end
incremented by step
until start
is greater than (inclusive == false, default) / greater than or equal to (inclusive == true) end
if step
is positive and not zero, othewrwise until start
is less than (inclusive == false) or less than or equal to (inclusive == true) end
Example:
// inclusive
Iterator.range(1, 3, 1, true).toArray(); // [1, 2, 3]
// exclusive
Iterator.range(1, 3, 1).toArray(); // [1, 2]
// inclusive reverse
Iterator.range(-1, -3, -1, true).toArray(); // [-1, -2, -3]
// exclusive
Iterator.range(-1, -3, -1).toArray(); // [-1, -2]
// edge cases
Iterator.range(1, 1, 0, false).toArray(); // []
Iterator.range(0, 1, 0, true).toArray(); // []
Iterator.range(1, 0, 0, false).take(2).toArray(); // [1, 1], .range() itetates infinitely if not in bounds by .take(2), never finishing
Iterator.range(0, 0, 0, true).take(2).toArray(); // [0, 0], .range() itetates infinitely if not in bounds by .take(2), never finisheing
Notes:
- It also implements (Async)Iterator.prototype.flatMap() behavior from issue #114 - flatMap should act like it does a
yield *
on each iterable. - Pre-checks are done BEFORE all functions start doing their stuff, INCLUDING async ones. (Yet i have unsettled thinking about async function pre-checks, maybe variations of pre-check will come out behind a flag? (in the config variable)).
- It takes globalThis by a polyfill written by Mathias Bynens from his awensome article (Lingers on fact that
__0x_6642_5d0e_72c2_4e09
preperty is writable and extensible in Object.prototype and Object.defineProperty isn't changed before the script is run). - UMD bundle is exposed into global as
__IteratorHelpersPolyfill
. - All bundles are minified.
- Additional helpers can be removed by the
config
variable from exports. - This polyfill's size is less than 5 kb (4.62 kb atm) when compressed by Brotli compression algorithm.
- Typings are made to accurately reflect behaviour of methods as much as possible.
Development:
Please propose feature by opening an issue before starting working on pull request, because i can reject your proposal and your work won't be needed at all
- Fork & Clone forked repository to your local machine.
- Open cloned directory in your favorite editor.
- Do some commits.
- Open pull request!
Build:
- Install all modules by
npm i
in the command prompt. - Build by
npm run build
if you just need the .mjs bundle ornpm run build-full
if you also need commonjs and umd bundle.
NOTE: Builds include source maps.