JavaScript Iterators

Objects that define how to access elements sequentially

⚙️ What are Iterators?

An iterator is an object that implements the iterator protocol by having a next() method that returns an object with 'value' and 'done' properties.


// Getting an iterator from an array
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

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

Output:

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

Iterator Protocol

🔧

next() Method

Returns the next value

iterator.next()
// Returns: {value: any, done: boolean}
📦

Value Property

The current item

const result = iterator.next();
console.log(result.value);

Done Property

True when finished

const result = iterator.next();
console.log(result.done);
🔄

State Management

Remembers position

// Each call advances position
iterator.next(); // position 0
iterator.next(); // position 1

🔹 Manual Iterator Usage

You can manually control iteration with iterators:

const colors = ['red', 'green', 'blue'];
const colorIterator = colors[Symbol.iterator]();

// Manual iteration
let result = colorIterator.next();
while (!result.done) {
    console.log(`Color: ${result.value}`);
    result = colorIterator.next();
}

console.log('Iteration complete!');

Output:

Color: red
Color: green
Color: blue
Iteration complete!

🔹 Creating Custom Iterators

Build your own iterator objects:

// Custom iterator for even numbers
function createEvenNumberIterator(max) {
    let current = 0;
    
    return {
        next() {
            if (current <= max) {
                const value = current;
                current += 2;
                return { value, done: false };
            }
            return { done: true };
        }
    };
}

// Use the custom iterator
const evenIterator = createEvenNumberIterator(10);

let result = evenIterator.next();
while (!result.done) {
    console.log(result.value);
    result = evenIterator.next();
}

Output:

0
2
4
6
8
10

🔹 Iterator with Return Value

Iterators can return a final value when done:

function createSumIterator(numbers) {
    let index = 0;
    let sum = 0;
    
    return {
        next() {
            if (index < numbers.length) {
                const value = numbers[index];
                sum += value;
                index++;
                return { value, done: false };
            }
            // Return final sum when done
            return { value: sum, done: true };
        }
    };
}

const numbers = [1, 2, 3, 4, 5];
const sumIterator = createSumIterator(numbers);

let result = sumIterator.next();
while (!result.done) {
    console.log(`Current: ${result.value}`);
    result = sumIterator.next();
}

console.log(`Final sum: ${result.value}`);

Output:

Current: 1
Current: 2
Current: 3
Current: 4
Current: 5
Final sum: 15

🔹 Iterator vs Iterable

Understanding the difference:

Iterable:

  • Has a Symbol.iterator method
  • Can be used with for...of
  • Examples: Array, String, Set, Map

Iterator:

  • Has a next() method
  • Returns {value, done} objects
  • Maintains state between calls
const arr = [1, 2, 3];  // This is an ITERABLE

// Get an ITERATOR from the iterable
const iterator = arr[Symbol.iterator]();

// The iterator has the next() method
console.log(typeof iterator.next); // "function"

// The original array is still iterable
for (const num of arr) {
    console.log(num); // Works fine
}

🔹 Practical Example: Pagination Iterator

Create an iterator for paginated data:

function createPaginationIterator(data, pageSize) {
    let currentPage = 0;
    const totalPages = Math.ceil(data.length / pageSize);
    
    return {
        next() {
            if (currentPage < totalPages) {
                const start = currentPage * pageSize;
                const end = start + pageSize;
                const page = data.slice(start, end);
                
                currentPage++;
                
                return {
                    value: {
                        page: currentPage,
                        data: page,
                        hasMore: currentPage < totalPages
                    },
                    done: false
                };
            }
            
            return { done: true };
        }
    };
}

// Use pagination iterator
const users = ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Grace'];
const pageIterator = createPaginationIterator(users, 3);

let result = pageIterator.next();
while (!result.done) {
    const { page, data, hasMore } = result.value;
    console.log(`Page ${page}: ${data.join(', ')}`);
    console.log(`Has more: ${hasMore}`);
    result = pageIterator.next();
}

Output:

Page 1: Alice, Bob, Charlie
Has more: true
Page 2: David, Eve, Frank
Has more: true
Page 3: Grace
Has more: false

🧠 Test Your Knowledge

What does the next() method of an iterator return?