JavaScript Generators, Symbols, Iterables, and Iterators

Advanced JavaScript features for managing iteration and data flow

By Hank Kim

JavaScript Generators, Symbols, Iterables, and Iterators

Advanced JavaScript features for managing iteration and data flow

JavaScript Generators, Symbols, Iterables, and Iterators

1. Symbols

  • Definition: A new primitive type introduced in ES6 that creates unique, immutable values.

    const s1 = Symbol("id");
    const s2 = Symbol("id");
    console.log(s1 === s2); // false
    
  • Symbols are often used as “hidden keys” for object properties to avoid collisions.

Well-Known Symbols

JavaScript defines several built-in symbols with special purposes:

  • Symbol.iterator: Marks an object as iterable.
  • Symbol.toStringTag: Customizes the result of Object.prototype.toString.
  • Symbol.hasInstance: Controls behavior of instanceof.

2. Iterables

  • Definition: An object is iterable if it implements a method at key Symbol.iterator.
  • This method must return an iterator.
  • Iterables work with:

    • for...of loops
    • Spread syntax (...)
    • Array.from
  • Example:

    const arr = [1, 2, 3];
    console.log(typeof arr[Symbol.iterator]); // "function"
    for (const n of arr) console.log(n); // 1, 2, 3
    

3. Iterators

  • Definition: An iterator is an object with a next() method that returns:

    { value: <any>, done: <boolean> }
    
  • Example:

    const arr = [10, 20];
    const it = arr[Symbol.iterator]();
    
    console.log(it.next()); // { value: 10, done: false }
    console.log(it.next()); // { value: 20, done: false }
    console.log(it.next()); // { value: undefined, done: true }
    

4. Iterable ↔ Iterator Relationship

  • Iterable: An object that can produce an iterator (obj[Symbol.iterator]).
  • Iterator: The actual object that retrieves values sequentially via next().

Analogy:

  • Iterable → “You can loop over me; call my Symbol.iterator.”
  • Iterator → “I’ll hand out values one by one with next().”

5. Custom Iterable Example

const myIterable = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    let current = this.from;
    let last = this.to;

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

for (const num of myIterable) {
  console.log(num); // 1, 2, 3
}
  • myIterable is an iterable because it implements [Symbol.iterator].
  • The returned object is an iterator because it has next().

6. Generators

  • Definition: A special type of function that simplifies creation of iterables and iterators.
  • Declared with function* and uses the yield keyword.
  • Calling a generator returns an iterator that is also iterable.
  • Example:

    function* genNumbers() {
      yield 1;
      yield 2;
      yield 3;
    }
    
    const it = genNumbers();
    console.log(it.next()); // { value: 1, done: false }
    console.log(it.next()); // { value: 2, done: false }
    console.log(it.next()); // { value: 3, done: false }
    console.log(it.next()); // { value: undefined, done: true }
    
    for (const n of genNumbers()) {
      console.log(n); // 1, 2, 3
    }
    
  • Key property: Generators can pause at yield and resume execution later, producing values lazily.

7. Summary

  • Symbol: A primitive for unique values. Includes well-known symbols like Symbol.iterator.
  • Iterable: Any object implementing [Symbol.iterator], usable in for...of, spread, etc.
  • Iterator: An object with next() that produces { value, done }.
  • Generator: A special function (function*) that produces iterators and iterables, supporting lazy evaluation via yield.

Tags: JavaScript