JavaScript Iterables

What Are Iterables?

Iterables are objects that implement the @@iterator method, making their data accessible in a sequential manner. These objects conform to the Iterable Protocol, which defines how elements within the object can be accessed and iterated over.

Common examples of iterable objects in JavaScript:

  1. Arrays
  2. Strings
  3. Maps
  4. Sets
  5. Typed arrays (e.g., Int32Array)
  6. Custom objects implementing the iterable protocol

How Iterables Work

Iterables use an internal method called Symbol.iterator to produce an iterator object. The iterator object has a next() method that returns each element of the iterable, wrapped in an object with two properties:

  • value: The current element.
  • done: A boolean indicating whether the iteration is complete (true) or not (false).

Example of Iteration

Here’s how iteration works under the hood:

const iterable = [10, 20, 30];

// Retrieve the iterator
const iterator = iterable[Symbol.iterator]();

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

Explanation:

  • The Symbol.iterator method returns an iterator for the array.
  • The next() method fetches the next element until done becomes true.

Using Iterables with for…of

The for…of loop provides a convenient way to iterate over all elements of an iterable object.

const numbers = [1, 2, 3, 4, 5];

for (const num of numbers) {
console.log(num);
}
// Output:
// 1
// 2
// 3
// 4
// 5

Why use for…of?

  • It is simpler and more readable than manually calling next().
  • It works with any iterable object.

Iterables in Strings

Strings are also iterable, meaning you can loop through their characters one by one.

const word = "Hello";

for (const char of word) {
console.log(char);
}
// Output:
// H
// e
// l
// l
// o

Iterables in Maps and Sets

Maps and Sets, introduced in ES6, are also iterable objects.

Example: Iterating Through a Map

const map = new Map([
['a', 1],
['b', 2],
['c', 3]
]);

for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// Output:
// a: 1
// b: 2
// c: 3

Example: Iterating Through a Set

const set = new Set([10, 20, 30, 40]);

for (const value of set) {
console.log(value);
}
// Output:
// 10
// 20
// 30
// 40

Custom Iterables

You can create your own iterable objects by implementing the Symbol.iterator method.

Example: Custom Iterable Object

const customIterable = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
} else {
return { value: undefined, done: true };
}
}
};
}
};

for (const value of customIterable) {
console.log(value);
}
// Output:
// 1
// 2
// 3

Explanation:

  • The Symbol.iterator method creates an iterator for the object.
  • The next() method specifies how to retrieve the next element.

Practical Use Cases

  1. Processing Data: Iterate through arrays, maps, or sets to process data.
  2. String Manipulation: Loop through strings for operations like character counting.
  3. Custom Data Structures: Create custom iterable objects to represent data structures.
  4. Asynchronous Iteration: Use iterables with asynchronous generators for handling promises.

Best Practices

  1. Use Built-In Iterables: Leverage arrays, maps and sets for most tasks.
  2. Simplify Loops with for…of: Avoid manual iteration unless necessary.
  3. Define Meaningful Iterators: When creating custom iterables, ensure next() behaves logically.

Common Mistakes

Using for…in Instead of for…of:

  • for…in iterates over object properties, not elements of an iterable.

const arr = [10, 20, 30];
for (const key in arr) {
console.log(key); // Outputs: 0, 1, 2 (indexes)
}

Skipping Symbol.iterator: Custom objects must explicitly implement Symbol.iterator to be iterable.

Leave a Comment