← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Symbol & the Iterator Protocol

javascript ES2015 Advanced
debt(d5/e3/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). TypeScript and ESLint can detect when a custom collection class lacks Symbol.iterator implementation, but the detection is not automatic—it requires a rule specifically configured to check that custom data structures are iterable. The common mistakes (stateful iterator bugs, infinite loops, async mismatches) are not caught by default linting; they require runtime testing or careful code review to surface.

e3 Effort Remediation debt — work required to fix once spotted

Closest to 'simple parameterised fix' (e3). The quick_fix states 'implement Symbol.iterator on custom objects'—this is a straightforward pattern to add to a single class. However, if the error involves resetting state or switching to Symbol.asyncIterator for async sources, the fix touches the iterator pattern in multiple places within that class, pushing slightly toward e5 in some cases. Typical fix is localised to one component.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The Iterator Protocol is pervasive across JavaScript iteration syntax (for...of, spread operator, destructuring). If a codebase adopts this pattern inconsistently—some custom data structures iterable, others not—maintainers must remember which structures support iteration and which require manual loops. The protocol's reach is broad (it integrates with language syntax), and deciding how to implement it shapes how future data structures are designed.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field directly states the trap: 'Symbol.iterator is only for arrays.' Beyond that, the common mistakes reveal deep gotchas: returning a new iterator on each call breaks for...of reuse; forgetting done: true causes infinite loops; confusing Symbol.iterator with Symbol.asyncIterator contradicts async iteration expectations. These traps contradict what developers may assume from experience with arrays or generators, making them serious cognitive pitfalls.

About DEBT scoring →

Also Known As

Symbol.iterator iterator protocol iterable generator

TL;DR

Symbol.iterator makes objects iterable with for...of — implementing the iterator protocol enables custom data structures to participate in all iteration contexts.

Explanation

The iterator protocol: an object is iterable if it has a [Symbol.iterator]() method returning an iterator (an object with a next() method returning {value, done}). Implementing this makes custom objects work with: for...of, spread operator, destructuring, Array.from(), and yield*. Generator functions automatically produce iterables. Use cases: paginated API responses (each iteration fetches next page), infinite sequences, lazy transformations, and custom collection classes.

Common Misconception

Symbol.iterator is only for arrays — any object can be made iterable; custom data structures, API paginators, and lazy sequences all benefit from implementing the protocol.

Why It Matters

Implementing Symbol.iterator makes custom data structures first-class citizens in JavaScript — they work with all built-in iteration syntax without special handling.

Common Mistakes

  • Returning a new iterator on each call to [Symbol.iterator] without resetting state — broken for...of after first use.
  • Forgetting to set done: true — infinite iterator without termination.
  • Using a generator function where a manual iterator would be clearer.
  • Not implementing Symbol.asyncIterator for async data sources — for await...of requires this.

Code Examples

✗ Vulnerable
// Custom range — no iterator, cannot use for...of:
class Range {
    constructor(start, end) { this.start = start; this.end = end; }
    // Cannot do: for (const n of new Range(1, 5)) {}
    // Cannot do: [...new Range(1, 5)]
}
✓ Fixed
// Range with Symbol.iterator:
class Range {
    constructor(start, end) { this.start = start; this.end = end; }
    [Symbol.iterator]() {
        let current = this.start;
        const end = this.end;
        return {
            next() {
                return current <= end
                    ? { value: current++, done: false }
                    : { value: undefined, done: true };
            }
        };
    }
}
// Now works everywhere:
for (const n of new Range(1, 5)) console.log(n); // 1 2 3 4 5
const arr = [...new Range(1, 5)]; // [1,2,3,4,5]
const [a, b, c] = new Range(10, 20); // 10, 11, 12

Added 16 Mar 2026
Edited 22 Mar 2026
Views 33
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 1 ping W 1 ping T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 2 pings S 1 ping M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 10 Google 8 Perplexity 4 Unknown AI 2 Ahrefs 2 SEMrush 2 Majestic 1
crawler 27 crawler_json 1 pre-tracking 1
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: Medium
⚡ Quick Fix
Implement Symbol.iterator on custom objects to make them iterable with for...of — this is how Map, Set, and generators work; use Symbol.asyncIterator for async iteration
📦 Applies To
javascript ES2015 web cli
🔗 Prerequisites
🔍 Detection Hints
Custom collection class not iterable with for...of; manual index loop on custom data structure when Symbol.iterator would enable for...of
Auto-detectable: ✗ No typescript eslint
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: Class Tests: Update

✓ schema.org compliant