💾Iterator
extending built-in iterable iterators with methods map(), filter() ...
Last updated
extending built-in iterable iterators with methods map(), filter() ...
Last updated
JS⟩ iteration ⟩ iterator ⟩ Iterator (extension)
(deprecated , use Iterable+ext instead)
extending built-in iterable iterators with methods map()
, filter()
...
replit ⟩ Iterator (old), Iterator.prototype (new)
// --------------------
// ⭐ Iterator
// --------------------
// 🧨 雷區:
// • must use function declaration. (can't use class declaration)
// • the prototype of a class is unwritable❗
function Iterator() {} // function declaration
// ⭐ reassign/overwrite prototype❗️
// • prototype of all built-in (iterable) iterators
Iterator.prototype = Object.getPrototypeOf( // IteratorPrototype
Object.getPrototypeOf( // ArrayIteratorPrototype
[][Symbol.iterator]() // Array iterator
)
);
// ⭐ extending `Iterator.prototype`
// ---------------------------------
// - 🔸 .filter() -> generator
// - 🔸 .map() -> generator
// - 🔸 .take() -> generator
//
// - 🔸 .every() -> boolean
// - 🔸 .some() -> boolean
// - 🔸 .toArray() -> array
// - 🔸 .forEach() -> (returns `undefined`)
// 🔸 .filter()
Iterator.prototype.filter = function*(condition) {
for (const value of this) {
if (condition(value)) yield value;
}
};
// 🔸 .map()
Iterator.prototype.map = function*(f) {
for (const value of this) { yield f(value) }
};
// 🔸 .take()
// turn "infinite" iterator into "finite"
Iterator.prototype.take = function*(n) {
for (const value of this) {
if (n > 0) {
n -= 1;
yield value;
} else { return }
}
};
// 🔸 .forEach()
Iterator.prototype.forEach = function(handle) {
for (const value of this) { handle(value) }
};
// 🔸 .every()
Iterator.prototype.every = function(condition) {
for (const value of this) { if (!condition(value)) return false }
return true;
};
// 🔸 .some()
Iterator.prototype.some = function(condition) {
for (const value of this) { if (condition(value)) return true }
return false;
};
// 🔸 .toArray()
Iterator.prototype.toArray = function() {
return [...this];
};
// ⭐️ export
module.exports = Iterator;
💾 replit ⟩ Iterator, require: *integers()
// ⭐ import
const Iterator = require('./Iterator.js'); // extend iterators
const integers = require('./integers.js'); // infinite generator
// ✅ test method chaining:
// Note:
// - each method returns a different generator
// (except for .forEach, which returns `undefined`)
integers() // 👔 generator: 0, 1, 2, ...
.filter(x => x > 0) // 👔 generator: 1, 2, 3, ...
.map(x => x * 2) // 👔 generator: 2, 4, 6, ...
.take(4) // 👔 generator: 2, 4, 6, 8
.forEach(x => console.log(x)) // 👔 console: 2, 4, 6, 8
;
// ⭐ prototype chain (of a String iterator)
let it = 'abc'[Symbol.iterator](); // iterator of String
let proto1 = Object.getPrototypeOf(it); // StringIteratorPrototype
let proto2 = Object.getPrototypeOf(proto1); // IteratorPrototype
let proto3 = Object.getPrototypeOf(proto2); // Object.prototype
let proto4 = Object.getPrototypeOf(proto3); // null
// log
[
// ⭐ iterator only iterates once❗
it.toArray(), // [ 'a', 'b', 'c' ]
it.toArray(), // [] ⭐ `it` is "exhausted"❗
// ✅ test prototype chain
it, // String iterator
it instanceof Iterator, // true
proto1, // StringIteratorPrototype
proto2 === Iterator.prototype, // true
proto3 === Object.prototype, // true
proto4 === null, // true
// ✅ test .take()
integers().take(5).toArray(), // [ 0, 1, 2, 3, 4 ]
// ✅ test .every(), .some()
integers() // 0, 1, 2, ...
.take(5) // 0, 1, 2, 3, 4
.every(x => x >= 0), // true
integers()
.take(5)
.every(x => x < 3), // false
integers()
.take(5)
.some(x => x < 3), // true
].forEach(x => { console.log(x) });
extended by Iterator
*zip() - zip a list of iterables into a single generator function.
require IteratorPrototype
printPrototypeChain() - print prototype chain of an object.
Set.prototype.values() - returns an iterator.
Object.values() - returns an array❗️