Build a small object with a next method.

manual-iterator An iterator returns one result at a time. Each call to `next` gives a value and a `done` flag.

Manual Iterators

limit
manual_iterator.js
Replay: real traced execution (multi-file project)
const limit = 3;
let current = 1;
const values = [];
let value = null;
let done = false;

const iterator = {
  next() {
    if (current <= limit) {
      const value = current;
      current = current + 1;
      return { value, done: false };
    }
    return { value: null, done: true };
  },
};

({ value, done } = iterator.next());
while (!done) {
  values.push(value);
  ({ value, done } = iterator.next());
}

console.log("limit=" + limit);
console.log("values=" + values.join(","));
const limit = 2;
let current = 1;
const values = [];
let value = null;
let done = false;

const iterator = {
  next() {
    if (current <= limit) {
      const value = current;
      current = current + 1;
      return { value, done: false };
    }
    return { value: null, done: true };
  },
};

({ value, done } = iterator.next());
while (!done) {
  values.push(value);
  ({ value, done } = iterator.next());
}

console.log("limit=" + limit);
console.log("values=" + values.join(","));
const limit = 4;
let current = 1;
const values = [];
let value = null;
let done = false;

const iterator = {
  next() {
    if (current <= limit) {
      const value = current;
      current = current + 1;
      return { value, done: false };
    }
    return { value: null, done: true };
  },
};

({ value, done } = iterator.next());
while (!done) {
  values.push(value);
  ({ value, done } = iterator.next());
}

console.log("limit=" + limit);
console.log("values=" + values.join(","));
  1. limit ← 3, current ← 1, values ← (empty), value ← null, done ← false

    1const limit→ 3 = 3; //@limit=2, 42let current→ 1 = 1;3const values→ (empty) = [];4let value→ null = null;5let done→ false = false;67const iterator→ [object Object] = {8  next() {9    if (current <= limit) {10      const value = current;11      current = current + 1;12      return { value, done: false };13    }14    return { value: null, done: true };15  },16};1718({ value, done } = iterator[object Object].next());19while (!done) {
  2. values ← 1

    pass 1 of 3
    18({ value, done } = iterator.next());19while (!donefalse) {20  values.push(value1);21  ({ value, done } = iterator[object Object].next());22}
    values this step(empty) 1values
    All 3 passes — pass 1 is the card above
    passvaluevalues
    11(empty) 1
    221 1,2
    331,2 1,2,3
  3. console.log("limit=" + limit);

    21  ({ value, done } = iterator.next());22}2324console.log("limit=" + limit3);25console.log("values=" + values1,2,3.join(","));
    outputlimit=3
    values=1,2,3
  1. limit ← 2, current ← 1, values ← (empty), value ← null, done ← false

    1const limit→ 2 = 2;2let current→ 1 = 1;3const values→ (empty) = [];4let value→ null = null;5let done→ false = false;67const iterator→ [object Object] = {8  next() {9    if (current <= limit) {10      const value = current;11      current = current + 1;12      return { value, done: false };13    }14    return { value: null, done: true };15  },16};1718({ value, done } = iterator[object Object].next());19while (!done) {
  2. values ← 1

    pass 1 of 2
    18({ value, done } = iterator.next());19while (!donefalse) {20  values.push(value1);21  ({ value, done } = iterator[object Object].next());22}
    values this step(empty) 1values
  3. values ← 1,2

    pass 2 of 2
    18({ value, done } = iterator.next());19while (!donefalse) {20  values.push(value2);21  ({ value, done } = iterator[object Object].next());22}
    values this step1 1,2values
  4. console.log("limit=" + limit);

    21  ({ value, done } = iterator.next());22}2324console.log("limit=" + limit2);25console.log("values=" + values1,2.join(","));
    outputlimit=2
    values=1,2
  1. limit ← 4, current ← 1, values ← (empty), value ← null, done ← false

    1const limit→ 4 = 4;2let current→ 1 = 1;3const values→ (empty) = [];4let value→ null = null;5let done→ false = false;67const iterator→ [object Object] = {8  next() {9    if (current <= limit) {10      const value = current;11      current = current + 1;12      return { value, done: false };13    }14    return { value: null, done: true };15  },16};1718({ value, done } = iterator[object Object].next());19while (!done) {
  2. values ← 1

    pass 1 of 4
    18({ value, done } = iterator.next());19while (!donefalse) {20  values.push(value1);21  ({ value, done } = iterator[object Object].next());22}
    values this step(empty) 1values
    All 4 passes — pass 1 is the card above
    passvaluevalues
    11(empty) 1
    221 1,2
    331,2 1,2,3
    441,2,3 1,2,3,4
  3. console.log("limit=" + limit);

    21  ({ value, done } = iterator.next());22}2324console.log("limit=" + limit4);25console.log("values=" + values1,2,3,4.join(","));
    outputlimit=4
    values=1,2,3,4

Follow the Calls

  1. limit starts at 3, and current starts at 1.
  2. Each iterator.next() call returns an object with value and done.
  3. The loop pushes each value while done is false.
  4. When current becomes 4, the next call returns value: null and done: true.
  5. The loop stops and prints values=1,2,3. | call | returned value | returned done | loop action | | ---: | --- | --- | --- | | 1 | 1 | false | push 1 | | 2 | 2 | false | push 2 | | 3 | 3 | false | push 3 | | 4 | null | true | stop |

Exercise: manual_iterator.js

Reproduce limit=3 and values=1,2,3, then use the pinned limits 2 and 4 to predict values=1,2 and values=1,2,3,4.