πŸ”΄ HardWhat's Wrong?πŸ› Debug Challenge

Symbol.iterator not returning a fresh iterator

Buggy Code β€” Can you spot the issue?

const myIterable = {
  data: [1, 2, 3, 4, 5],
  index: 0, // shared state β€” BUG!
  [Symbol.iterator]() {
    return {
      next: () => {
        if (this.index < this.data.length) {
          return { value: this.data[this.index++], done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for (const n of myIterable) console.log(n); // 1 2 3 4 5
for (const n of myIterable) console.log(n); // nothing! index is already 5

Fixed Code

const myIterable = {
  data: [1, 2, 3, 4, 5],
  [Symbol.iterator]() {
    let index = 0; // fresh state per call β€” captured in closure
    const data = this.data;
    return {
      next() {
        if (index < data.length) {
          return { value: data[index++], done: false };
        }
        return { value: undefined, done: true };
      }
    };
  }
};

for (const n of myIterable) console.log(n); // 1 2 3 4 5
for (const n of myIterable) console.log(n); // 1 2 3 4 5 βœ“

Bug Explained

Bug: index is stored on the iterable itself β€” shared across all iterations. After first loop finishes, index = 5. Second loop starts with index = 5 β€” immediately returns done.

Explanation: Each call to [Symbol.iterator]() must return a FRESH iterator with its own state. Storing index on the iterable object makes all iterations share state. Closure keeps index local per iterator.

Key Insight: An iterable is reusable; an iterator is single-use. [Symbol.iterator]() must create a new state (closure or object) each time β€” never shared state on the iterable itself.

More What's Wrong? Debug Challenges

🟒 EasyAccidental global variableβ†’πŸŸ‘ MediumWrong comparison with NaNβ†’πŸ”΄ HardInfinite re-render in React useEffectβ†’πŸŸ‘ MediumArray sort mutates originalβ†’

Practice spotting bugs live β†’

38 debug challenges with AI hints

πŸ› Try Debug Lab