Symbols: keys that cannot collide
Lesson 7-1 leaned on Symbol.iterator; time to make symbols themselves precise. A symbol is a primitive value whose entire job is to be unique: every Symbol("desc") call mints a brand-new value equal to nothing else, ever. The string is only a debugging label.
Why the language needed them: property keys used to be strings only. When a library wants to stash bookkeeping on your object, or the language wants to give objects hook methods (like the iterator hook), a string key could collide with your real data. A symbol key cannot — code that does not hold the symbol value cannot even name the property.
Symbol-keyed properties also stay out of normal enumeration: Object.keys, for...in, and JSON.stringify all skip them, so attached metadata never leaks into your loops or API payloads.
Code exercise · javascript
Run it. Two symbols with the same label are still different values. The symbol-keyed property is readable with the symbol in hand, yet invisible to JSON.stringify and Object.keys.
Well-known symbols: the language's hook points
The language defines a set of well-known symbols, stored as properties of Symbol itself, that act as hook points: put a method under one of these keys and built-in machinery will call it. Symbol.iterator (lesson 7-1) is the famous one — it is how for...of asks an object "how do I walk you?". Others you will eventually meet: Symbol.asyncIterator (drives for await...of loops) and Symbol.hasInstance (customizes instanceof).
The cleanest way to implement Symbol.iterator is a generator method: lesson 7-2's function*, written as a method by putting the * in front of the (computed) name. No hand-rolled next() needed.
Quiz
What does `Symbol("id") === Symbol("id")` evaluate to?
Code exercise · javascript
Your turn. Give `range` a generator method under `[Symbol.iterator]` that yields the numbers from `this.start` to `this.end`. The final line uses `...` to expand the iterable (Unit 8's spread) — it works on anything iterable, including yours.