---
description: extending built-in iterable iterators with methods map(), filter() ...
---

# Iterator

[JS](../..)⟩ [iteration](..) ⟩ [iterator]() ⟩ Iterator (extension)

{% hint style="warning" %}
(<mark style="color:red;">deprecated</mark> , use [iterable+ext](../iterable+ext "mention") instead)

extending <mark style="color:yellow;">**built-in**</mark> [**iterable iterators**](iterable) with methods <mark style="color:blue;">`map()`</mark>, <mark style="color:blue;">`filter()`</mark> ...
{% endhint %}

<img src="https://2527454625-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MfvEFZnSBhKT6fJmus0%2Fuploads%2F30ZWtMWzEaoGZTCvC6hg%2Fiterator.class.svg?alt=media&#x26;token=09701dc7-5d3b-433d-ac14-0b2edb998b9a" alt="prototype chain of (built-in) iterators" class="gitbook-drawing">

{% tabs %}
{% tab title="💾 程式" %}
* replit ⟩ [Iterator](https://replit.com/@pegasusroe/Iterator#index.js) (old), [Iterator.prototype](https://replit.com/@pegasusroe/Iteratorprototype#ext/Iterator.js) (new)

```javascript
// --------------------
//     ⭐ 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;
```
{% endtab %}

{% tab title="💈範例" %}
* :floppy\_disk: replit ⟩ [Iterator](https://replit.com/@pegasusroe/Iterator#index.js),  require： [integers](../generator/examples/integers "mention")

```javascript
// ⭐ 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) });
```
{% endtab %}

{% tab title="⬇️ 應用" %}
* <mark style="color:yellow;">**extended by**</mark>**&#x20;**<mark style="color:purple;">**Iterator**</mark>
  * [integers](../generator/examples/integers "mention")
  * [fibonacci](../generator/examples/fibonacci "mention")
  * [zip](../generator/examples/zip "mention") - zip a list of [iterable](../iterable "mention")s into a single [func](../generator/func "mention").
  * [seq](../generator/examples/seq "mention")
  * [interleave](../generator/examples/interleave "mention")
* <mark style="color:yellow;">**require**</mark> [iteratorprototype](iteratorprototype "mention")
  * [print](../../val/obj/proto/chain/print "mention") - print prototype chain of an object.
{% endtab %}

{% tab title="👥 相關" %}
* [class](../../val/class "mention") ⟩ [🧨 雷區](../../../val/class#lei-ou) - can't overwrite class's prototype.
{% endtab %}

{% tab title="📗 參考" %}
* [ ] 2ality ⟩ [introducing a superclass for iterators](https://2ality.com/2021/08/iteration-helpers.html#approach%3A-introducing-a-superclass-for-iterators)
* [ ] [javascript-the-definitive-guide](../../../master/ref/javascript-the-definitive-guide "mention") ⟩ 12.2 Implementing Iterable Objects&#x20;
{% endtab %}

{% tab title="📘 手冊" %}
* [Set.prototype.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) - returns an [](<> "mention").
* [Object.values()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values) - returns an <mark style="color:yellow;">**array**</mark>❗️
{% endtab %}

{% tab title="🗣 討論" %}
* [Javascript: Overwriting function's prototype - bad practice?](https://stackoverflow.com/questions/12260375/javascript-overwriting-functions-prototype-bad-practice)
{% endtab %}
{% endtabs %}
