What is Iterable?
An iterable is any object that can be iterated over using a for...of loop. In JavaScript, an object is considered iterable if it implements the iterable protocol.
In JavaScript, a value is iterable only if its prototype (or the object itself) has a [Symbol.iterator] method. That method returns an iterator—an object that defines a next() function, producing the sequence of values until done. This method is always found either on built‑ins like Array.prototype or on user‑defined prototype chains.
What Makes an Object Iterable?
- Has a
[Symbol.iterator]method (found typically on its prototype, e.g.Array.prototype,String.prototype, etc.) – without this method,for...ofthrows aTypeError. - Invoking
obj[Symbol.iterator]()returns an iterator object with anext()method that returns a result of the form{ value, done }. - Can be consumed by any syntax that expects iterables: such as
for...of, spread[...iterable]or function calls likefn(...iterable). - Supports array‑style destructuring:
const [x, y] = iterablewill invoke the iterator to get those values. - Built‑in iterables include:
Array, String, Map, Set, TypedArray, arguments, NodeList, and generators – all have their ownSymbol.iteratorimplemented. Plain objects like{}(Object Literal) don’t have it unless you add it manually.
Basic Example:
// Arrays are iterable
const numbers = [1, 2, 3, 4, 5];
// Using for...of loop
for (const num of numbers) {
console.log(num); // 1, 2, 3, 4, 5
}
// Using spread operator
const spreadNumbers = [...numbers]; // [1, 2, 3, 4, 5]
// Using destructuring
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]Built-in Iterables
JavaScript provides several built-in iterable objects that you can use directly.
1. Arrays
const fruits = ['apple', 'banana', 'orange'];
for (const fruit of fruits) {
console.log(fruit);
}
// apple
// banana
// orange2. Strings
const message = "Hello";
for (const char of message) {
console.log(char);
}
// H
// e
// l
// l
// o
// Using spread operator
const chars = [...message]; // ['H', 'e', 'l', 'l', 'o']3. Sets
const uniqueNumbers = new Set([1, 2, 2, 3, 3, 4]);
for (const num of uniqueNumbers) {
console.log(num);
}
// 1
// 2
// 3
// 4
// Using spread operator
const arrayFromSet = [...uniqueNumbers]; // [1, 2, 3, 4]4. Maps
const userMap = new Map([
['name', 'John'],
['age', 30],
['city', 'New York']
]);
// Iterating over Map entries (default)
for (const [key, value] of userMap) {
console.log(`${key}: ${value}`);
}
// name: John
// age: 30
// city: New York
// Iterating over keys only
for (const key of userMap.keys()) {
console.log(key);
}
// name
// age
// city
// Iterating over values only
for (const value of userMap.values()) {
console.log(value);
}
// John
// 30
// New YorkWhat is Iterator?
An iterator is an object that knows how to access items from a collection one at a time, while keeping track of its current position within that sequence.
Iterator Object Structure:
// An iterator object has this structure:
{
next: function() {
return {
value: any, // The current value
done: boolean // true if iteration is complete
}
}
}Manual Iterator Usage:
const numbers = [1, 2, 3, 4, 5];
const iterator = numbers[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: 4, done: false }
console.log(iterator.next()); // { value: 5, done: false }
console.log(iterator.next()); // { value: undefined, done: true }
// After done: true, all subsequent calls return the same
console.log(iterator.next()); // { value: undefined, done: true }Iterator Protocol
The iterator protocol defines a standard way to produce a sequence of values. An object is an iterator when it implements a next() method with the following semantics.
Iterator Protocol Requirements:
- Must have a
next()method next()must return an object with two properties:value: The current value in the sequencedone: Boolean indicating if iteration is complete- When
doneistrue,valuecan be omitted - After
done: true, subsequent calls should return{ done: true }
Simple Iterator Example:
// Creating a simple iterator
function createSimpleIterator(array) {
let index = 0;
return {
next() {
if (index < array.length) {
return {
value: array[index++],
done: false
};
} else {
return {
done: true
};
}
}
};
}
// Using our custom iterator
const fruits = ['apple', 'banana', 'orange'];
const fruitIterator = createSimpleIterator(fruits);
console.log(fruitIterator.next()); // { value: 'apple', done: false }
console.log(fruitIterator.next()); // { value: 'banana', done: false }
console.log(fruitIterator.next()); // { value: 'orange', done: false }
console.log(fruitIterator.next()); // { done: true }Creating Custom Iterables
You can create your own iterable objects by implementing the Symbol.iterator method.
Basic Custom Iterable:
// Creating a custom iterable object
const customIterable = {
data: [10, 20, 30, 40, 50],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return {
value: data[index++],
done: false
};
} else {
return { done: true };
}
}
};
}
};
// Using our custom iterable
for (const value of customIterable) {
console.log(value);
}
// 10
// 20
// 30
// 40
// 50
// Can also use spread operator
const spreadValues = [...customIterable]; // [10, 20, 30, 40, 50]Range Iterable:
// Creating a range iterable
class Range {
constructor(start, end, step = 1) {
this.start = start;
this.end = end;
this.step = step;
}
[Symbol.iterator]() {
let current = this.start;
const end = this.end;
const step = this.step;
return {
next() {
if (step > 0 && current < end || step < 0 && current > end) {
const value = current;
current += step;
return { value, done: false };
} else {
return { done: true };
}
}
};
}
}
// Using the range iterable
const range1 = new Range(1, 5);
for (const num of range1) {
console.log(num);
}
// 1
// 2
// 3
// 4
const range2 = new Range(10, 0, -2);
for (const num of range2) {
console.log(num);
}
// 10
// 8
// 6
// 4
// 2Iterable vs Iterator
Understanding the difference between iterable and iterator is crucial.
Key Differences:
- Iterable: An object that can be iterated over (has
Symbol.iterator) - Iterator: An object that knows how to access items one at a time (has
next()) - Every time you call
[Symbol.iterator]()on an iterable, you get a new iterator - An iterator can only be used once, but an iterable can create multiple iterators
Demonstrating the Difference:
const numbers = [1, 2, 3, 4, 5];
// The array is ITERABLE
console.log(typeof numbers[Symbol.iterator]); // 'function'
// Getting an ITERATOR from the iterable
const iterator1 = numbers[Symbol.iterator]();
const iterator2 = numbers[Symbol.iterator]();
// Each iterator is independent
console.log(iterator1.next()); // { value: 1, done: false }
console.log(iterator1.next()); // { value: 2, done: false }
console.log(iterator2.next()); // { value: 1, done: false } (starts from beginning)
// iterator1 continues from where it left off
console.log(iterator1.next()); // { value: 3, done: false }
// iterator2 continues independently
console.log(iterator2.next()); // { value: 2, done: false }Common Use Cases
Iterables and iterators are used in many scenarios in modern JavaScript.
1. Data Processing:
// Processing large datasets efficiently
function* generateNumbers(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
// Process numbers one by one without loading all into memory
const numberGenerator = generateNumbers(1, 1000000);
let sum = 0;
for (const num of numberGenerator) {
sum += num;
if (sum > 1000) break; // Early termination
}
console.log(sum); // Sum of numbers until exceeding 10002. Custom Data Structures:
// Custom linked list with iteration
class LinkedList {
constructor() {
this.head = null;
}
add(value) {
const node = { value, next: null };
if (!this.head) {
this.head = node;
} else {
let current = this.head;
while (current.next) {
current = current.next;
}
current.next = node;
}
}
[Symbol.iterator]() {
let current = this.head;
return {
next() {
if (current) {
const value = current.value;
current = current.next;
return { value, done: false };
} else {
return { done: true };
}
}
};
}
}
// Using the linked list
const list = new LinkedList();
list.add(1);
list.add(2);
list.add(3);
for (const value of list) {
console.log(value);
}
// 1
// 2
// 3Advanced Concepts
Let's explore some advanced concepts related to iterables and iterators.
1. Generator Functions:
// Generator functions create iterators
function* numberGenerator(start, end) {
for (let i = start; i <= end; i++) {
yield i;
}
}
const generator = numberGenerator(1, 5);
// Manual iteration
console.log(generator.next()); // { value: 1, done: false }
console.log(generator.next()); // { value: 2, done: false }
console.log(generator.next()); // { value: 3, done: false }
console.log(generator.next()); // { value: 4, done: false }
console.log(generator.next()); // { value: 5, done: false }
console.log(generator.next()); // { done: true }
// Or use for...of
const generator2 = numberGenerator(1, 3);
for (const num of generator2) {
console.log(num);
}
// 1
// 2
// 32. Checking if Object is Iterable:
// Utility function to check if object is iterable
function isIterable(obj) {
return obj != null && typeof obj[Symbol.iterator] === 'function';
}
// Testing various objects
console.log(isIterable([])); // true
console.log(isIterable('hello')); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new Map())); // true
console.log(isIterable({})); // false
console.log(isIterable(null)); // false
console.log(isIterable(undefined)); // false
console.log(isIterable(42)); // false
// Safe iteration
function safeIterate(obj) {
if (isIterable(obj)) {
for (const item of obj) {
console.log(item);
}
} else {
console.log('Object is not iterable');
}
}
safeIterate([1, 2, 3]); // 1, 2, 3
safeIterate({}); // Object is not iterableSummary
Iterables and iterators are fundamental concepts in modern JavaScript that enable powerful data processing capabilities:
- Iterables are objects that can be iterated over using
for...ofloops - Iterators are objects that know how to access items one at a time
- Built-in iterables include Arrays, Strings, Sets, Maps, and more
- You can create custom iterables by implementing
Symbol.iterator - Generator functions provide a convenient way to create iterators
- Iterables enable lazy evaluation and memory-efficient processing
- Understanding the difference between iterable and iterator is crucial for advanced JavaScript development