SYP Start Your Path

Module 1: Iterators, Generators & Collections

Iterators

An iterator is an object that knows how to produce a sequence of values, one at a time. It's what makes for...of work — arrays, strings, Maps, and Sets are all "iterable" because they implement this pattern internally.

let arr = [10, 20, 30];
let iterator = arr[Symbol.iterator]();

iterator.next(); // { value: 10, done: false }
iterator.next(); // { value: 20, done: false }
iterator.next(); // { value: 30, done: false }
iterator.next(); // { value: undefined, done: true }

// This is what for...of does automatically, behind the scenes
for (let value of arr) {
  console.log(value);
}

Generators

A generator function can pause and resume itself, producing a sequence of values on demand instead of computing them all at once — useful for large or even infinite sequences.

function* countTo3() { // note the * — marks this as a generator
  yield 1;
  yield 2;
  yield 3;
}

let gen = countTo3();
gen.next(); // { value: 1, done: false }
gen.next(); // { value: 2, done: false }
gen.next(); // { value: 3, done: false }
gen.next(); // { value: undefined, done: true }

// Generators are iterable, so for...of works directly
for (let n of countTo3()) {
  console.log(n); // 1, 2, 3
}

// An infinite generator — only computes values as they're requested
function* naturalNumbers() {
  let n = 1;
  while (true) {
    yield n++;
  }
}

Symbols

A Symbol is a guaranteed-unique value, most often used as an object key that won't accidentally collide with any other key:

let id1 = Symbol("id");
let id2 = Symbol("id");
console.log(id1 === id2); // false — always unique, even with the same description

let user = {
  name: "Chiru",
  [id1]: "12345" // symbol used as a property key
};

Map & Set

Map is like an object, but keys can be ANY type (not just strings), and it keeps insertion order reliably:

let map = new Map();
map.set("name", "Chiru");
map.set(1, "one");
map.set(true, "yes");

map.get("name");   // "Chiru"
map.has(1);          // true
map.delete(1);
map.size;              // 2

for (let [key, value] of map) {
  console.log(key, value);
}

Set stores only unique values — duplicates are automatically ignored:

let set = new Set([1, 2, 2, 3, 3, 3]);
console.log(set); // Set(3) {1, 2, 3} — duplicates removed

set.add(4);
set.has(2);   // true
set.delete(1);
set.size;       // 3

// Common real use: de-duplicating an array
let unique = [...new Set([1, 1, 2, 2, 3])]; // [1, 2, 3]

WeakMap & WeakSet

WeakMap and WeakSet work like Map and Set, but their keys must be objects, and those keys are held "weakly" — meaning if nothing else in the program references that object anymore, it can be automatically garbage-collected, along with its entry in the WeakMap. This makes them useful for attaching extra data to objects (like caching or private metadata) without causing memory leaks by accidentally keeping objects alive forever.

let wm = new WeakMap();
let obj = { name: "Chiru" };
wm.set(obj, "some metadata");
wm.get(obj); // "some metadata"

// Unlike Map/Set, WeakMap/WeakSet are NOT iterable and have no .size —
// this is intentional, since their contents can disappear at any time