> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/web/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/web/js/iteration/iterable/custom/sequence.md).

# Sequence

finite/infinite iterable of numbers

[JS](/web/js.md)⟩ [iteration](/web/js/iteration.md) ⟩ [iterable](/web/js/iteration/iterable.md) ⟩ [custom](/web/js/iteration/iterable/custom.md) ⟩ Sequence

{% hint style="success" %}

* sequence of numbers
* an [iterable](/web/js/iteration/iterable.md) (i.e. [iterator](/web/js/iteration/iterator.md) maker, can make iterators), its <mark style="color:yellow;">**iterators**</mark> have：
  * the [return()](/web/js/iteration/iterator/return.md) method to  <mark style="color:yellow;">**clean up**</mark> things when [iteration](/web/js/iteration.md) <mark style="color:red;">**stops prematurely**</mark>.
  * use [arrow function as method❗️](/web/js/val/func/arrow/as-method.md)(both [return()](/web/js/iteration/iterator/return.md) and [next()](/web/js/iteration/iterator/next.md))❗
    {% endhint %}

{% tabs %}
{% tab title="💾 程式" %}
:floppy\_disk:replit：[(iterable) Sequence](https://replit.com/@pegasusroe/iterable-Sequence#index.js)

```javascript
// ⭐️ Sequence (iterable class)
//
// use cases:
//     new Sequence()    // 0, 1, 2, 3 ... (infinite)
// -------------------------------------------------------
class Sequence {

    // 🔸 custom class type name
    get [Symbol.toStringTag]() { return 'Sequence' }
    
    // init
    constructor({
        start = 0,
        step  = 1,             // step between numbers
        end   = undefined,     // end of sequence
        terms = undefined,     // how many terms the sequence has
    }={}) {
        
        this.start = start;
        this.step  = step;
        this.end   = end;      // ⭐️ ignored if `this.terms` is explicitly defined.
        this.terms = terms;    // ⭐️ `this.terms` has higher priority than `this.end`
        
        // finite or infnite sequence
        this.isInfinite = (this.end === undefined) && (this.terms === undefined);
        this.isFinite = !this.isInfinite;

        // ⭐️ if finite, calculate the correct number of terms,
        //    hence, `this.terms` is always defined in this case.
        if (this.isFinite) {
            // - if `this.terms` is defined, `this.end` is ignored.
            //   (the only use of `end` is to calculate the nubmer of terms, if it's not already defined)
            // - if `this.terms` is not defined, `this.end` MUST be defined.
            //   (we calculate the number of terms from `start, end, step`.)
            if (this.terms === undefined) {
                this.terms = Math.max(0, Math.floor((this.end - this.start) / this.step + 1));
            }
        }
    }
    
    // 🔸 "make-iterator" method
    [Symbol.iterator]() {
    
        let counter = 0;
        let currentValue = this.start;
    
        // ⭐️ return the iterator
        return  {                    // new "iterator" object

            // -------------------------------------------------
            //     ⭐️⭐️⭐️ arrow function as method ⭐️⭐️⭐️
            // -------------------------------------------------
            //
            // ⭐️ in the body of following next(), return() methods:
            // ❗ `this` does NOT refer to the new "iterator" object itself❗
            // ❗ `this` === the `Sequence` object in the outer context❗
            
            // 🔸 next iteration result (❗arrow function as method❗)
            next: () => {
                
                // if finite, check `this.terms` (because it's always properly defined)
                // otherwise, always return the iteration result. 
                if (this.isFinite ? counter < this.terms : true) {
                    const result = { value: currentValue };
                    currentValue += this.step;
                    counter += 1;
                    return result;    // return iteration result
                }
                
                // the iteration is done
                return { done: true };
            },
            
            // 🔸 clean up when iteration stops prematurely
            return: () => {
                console.log(`${this}: cleaning up...`);
                return { done: true }; // ⭐️ can't omit this result object although it's ignored.
            }
            
        } // end: return iterator
    
    } // end: "make-iterator" method

} // end: class Sequence
```

{% endtab %}

{% tab title="💈範例" %}

```javascript
// odd numbers: 1, 3, 5, 7, 9 ... (infinite)
for (const n of new Sequence({start: 1, step: 2})) {
    if ( n > 7 ) break;             // ⭐️ iteration stops prematurely
    console.log(n);                 // ⭐️ 1, 3, 5, 7 (stops at 9)
}                                   // ⭐️ [object Sequence]: cleaning up...
                                    
// destructuring sequence: 0, 1, 2, 3 ... (infinite)
const [a, b, c] = new Sequence();   // ⭐️ iteration stops prematurely
                                    // ⭐️ [object Sequence]: cleaning up...
// log
a, b, c,                        // 0, 1, 2

// by default: start = 0, step = 1
[...new Sequence({terms: 5})],  // [ 0, 1, 2, 3, 4 ]
[...new Sequence({end: 5})],    // [ 0, 1, 2, 3, 4, 5 ]

[...new Sequence({terms: 5, start: 1})],  // [ 1, 2, 3, 4, 5 ]
[...new Sequence({terms: 5, step: -1})],  // [ 0, -1, -2, -3, -4 ]
[...new Sequence({terms: 5, end: 1})],    // [ 0, 1, 2, 3, 4 ] (⭐️ `terms` defined, `end` ignored❗)
[...new Sequence({start: 5, end: 1})],    // [ ] (⭐️ `terms` undefined, `end` respected❗)

[...new Sequence({start: 5, end: 1, step: -1})],    // [ 5, 4, 3, 2, 1 ]
```

{% endtab %}

{% tab title="📗 參考" %}

* [ ] JavaScript Tutorial ⟩ [The Essential Guide to JavaScript Iterators](https://www.javascripttutorial.net/es6/javascript-iterator/) ⭐️
  {% endtab %}

{% tab title="👥 相關" %}

* its [iterator](/web/js/iteration/iterator.md)：
  * has the [return()](/web/js/iteration/iterator/return.md) method to <mark style="color:yellow;">**clean up**</mark> things.
  * uses [arrow function as method❗️](/web/js/val/func/arrow/as-method.md)❗
* similar objects：
  * [ClosedRange](/web/js/iteration/iterable/custom/closedrange.md)
  * [\*closedRange()](/web/js/iteration/generator/examples/closedrange.md)
  * [\*list()](/web/js/iteration/generator/examples/list.md)
  * [\*integers()](/web/js/iteration/generator/examples/integers.md) - non-negative integers. ([Broken mention](broken://pages/wdsR1aBto2o3YMiF3HsH))
    {% endtab %}
    {% endtabs %}
