🔄 Iterators & Generators in JavaScript

Iterators and Generators are powerful JavaScript features that allow you to control how data is produced and consumed. They are especially useful for handling large datasets, creating custom loops, and implementing lazy evaluation.

📖 What is an Iterator?

An Iterator is an object that lets you traverse through a collection one item at a time. It exposes a method called next().

Each call to next() returns an object with two properties:

  • value → The current value.
  • donetrue when iteration is complete.

🧠 Iterator Example

Basic Iterator

const arr = [10, 20, 30];

const iterator = arr[Symbol.iterator]();

console.log(iterator.next());
// { value: 10, done: false }

console.log(iterator.next());
// { value: 20, done: false }

console.log(iterator.next());
// { value: 30, done: false }

console.log(iterator.next());
// { value: undefined, done: true }

Note

Every array, string, map, and set in JavaScript is already iterable because they implement Symbol.iterator.

⚙️ Creating a Custom Iterator

Custom Iterator

const numbers = {
  start: 1,
  end: 3,

  [Symbol.iterator]() {
    let current = this.start;
    let last = this.end;

    return {
      next() {
        if (current <= last) {
          return {
            value: current++,
            done: false
          };
        }

        return {
          done: true
        };
      }
    };
  }
};

for (const num of numbers) {
  console.log(num);
}

Output:

Output

1
2
3

🚀 What are Generators?

A Generator is a special type of function that can pause and resume execution. Instead of returning one value, it can produce multiple values over time.

Generator functions are declared using function* and use theyield keyword.

✨ Basic Generator

Generator Example

function* numbers() {
  yield 1;
  yield 2;
  yield 3;
}

const gen = numbers();

console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

Output:

Output

{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: undefined, done: true }

🎯 Using Generators with for...of

Generator Loop

function* fruits() {
  yield "Apple";
  yield "Orange";
  yield "Banana";
}

for (const fruit of fruits()) {
  console.log(fruit);
}

🔁 Infinite Generator

Infinite Sequence

function* counter() {
  let i = 1;

  while (true) {
    yield i++;
  }
}

const gen = counter();

console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);

Note

⚠️ Infinite generators never stop by themselves. Always consume them carefully.

📤 Passing Values Back to a Generator

Passing Values

function* greet() {
  const name = yield "What's your name?";
  yield "Hello " + name;
}

const gen = greet();

console.log(gen.next().value);
console.log(gen.next("John").value);

Output:

Output

What's your name?
Hello John

⏹ Returning from a Generator

Return Statement

function* demo() {
  yield 1;
  yield 2;
  return 3;
}

const gen = demo();

console.log(gen.next());
console.log(gen.next());
console.log(gen.next());
console.log(gen.next());

Output:

Output

{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: true }
{ value: undefined, done: true }

⚖️ Iterator vs Generator

FeatureIteratorGenerator
CreationManualAutomatic with function*
State ManagementManualHandled automatically
SyntaxVerboseSimple
Uses yield
ReadabilityModerateExcellent

💼 Real-World Use Cases

  • 📄 Reading large files efficiently.
  • 🌐 Processing paginated API responses.
  • 📊 Lazy-loading huge datasets.
  • 🎮 Game loops and animations.
  • 🔄 Custom iterable objects.
  • ⚡ Memory-efficient data streams.

🔥 Best Practices

  • Use generators for sequences produced on demand.
  • Avoid storing huge arrays when a generator can generate values lazily.
  • Use for...of to consume iterables cleanly.
  • Implement Symbol.iterator for custom iterable objects.
  • Be cautious with infinite generators to avoid endless loops.

❌ Common Mistakes

  • Calling next() after completion and expecting more values.
  • Using yield outside a generator function.
  • Forgetting the * in function*.
  • Assuming generators execute immediately—they start only when next() is called.

📝 Summary

>>"Iterators define how to traverse data, while Generators provide an elegant way to produce values lazily with minimal code."

Key Takeaways:

  • ✅ Iterators expose the next() method.
  • ✅ Iterables implement Symbol.iterator.
  • ✅ Generators are iterator-producing functions.
  • yield pauses execution and resumes later.
  • ✅ Generators simplify complex iteration logic.
  • ✅ They are ideal for lazy evaluation and memory-efficient processing.