Key Concepts
Iterable: it is a sequence of elements that we can iterate over. In JavaScript, iterable must implement the ‘Symbol.iterator’ method.
Iterator Protocol: an object is an iterator when it implements a ‘next()’ method which returns an object with the properties:
value: next value in the iteration sequence.
done: A boolean to specify if the iteration is done.
Iterable Protocol: an object is iterable when it implements the ‘Symbol.iterator’ method.
Symbol.iterator: a built-in symbol that defines the default iterator for an object. In other words, an object that implements the ‘Symbol.iterator’ method becomes an iterator and gets the ‘next()’ method.
Built-in Iterable: JavaScript objects implementing collections such as ‘String’, ‘Array’, ‘TypedArray’, ‘Map’, and ‘Set’ are iterable because their prototype objects implement the ‘Symbol.iterator’ method.
Custom Iterable: new iterable objects can be defined by implementing the ‘Symbol.iterator’ method.
Custom Data Structure as Iterable: new data structures like stacks or queues can be created and made iterable by implementing the ‘Symbol.iterator’ method.
Generator: it is a specific type of function. The generator does not return a single value as a result like normal functions but multiple values over time. The generator can be used to implement the iterator and iterable protocol.
Iterable and Spread Syntax: a spread operator can be applied to an iterable to expand its elements.
Loop: the ‘for...of’ loop and ‘while’ loop can be used to iterate over iterators. However, only ‘for...of’ can used to loop through an iterable.
Note: it is possible to create a custom object that adheres to the protocol iterator but is not iterable. I.e, it can implement the ‘next()’ method but not the ‘Symbol.iterator’ method. This object is not iterable.
Usage Examples: Iterables
Iterable |
Code Snippet |
Code Output |
String |
let str = "Hi!"; let strIterator = str[Symbol.iterator](); console.log(strIterator.next()); console.log(strIterator.next()); console.log(strIterator.next()); console.log(strIterator.next()); |
{value: 'H', done: false} {value: 'i', done: false} {value: '!', done: false} {value: undefined, done: true} |
Array |
let numArray = [16, 27, 43]; let iterator = numArray[Symbol.iterator](); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); console.log(iterator.next()); |
{value: 16, done: false} {value: 27, done: false} {value: 43, done: false} {value: undefined, done: true} |
TypedArray |
|
{value: 10, done: false} {value: 123, done: false} {value: 45, done: false} {value: undefined, done: true} |
Set |
const fruits = new Set(["Orange", "Banana", "Strawberry"]); let fruitIter = fruits[Symbol.iterator](); console.log(fruitIter.next()); console.log(fruitIter.next()); console.log(fruitIter.next()); console.log(fruitIter.next());
|
{value: 'Orange', done: false} {value: 'Banana', done: false} {value: 'Strawberry', done: false} {value: undefined, done: true} |
Map |
const fruitPrice = new Map([ ["Orange", 3.25], ["Banana", 4.75], ["Strawberry", 6.5] ]);
let fruitPrIter = fruitPrice[Symbol.iterator](); console.log(fruitPrIter.next()); console.log(fruitPrIter.next()); console.log(fruitPrIter.next()); console.log(fruitPrIter.next());
|
{value: Array(2), done: false} {value: Array(2), done: false} {value: Array(2), done: false} {value: undefined, done: true} |
Custom Data Structure (Stack) |
class Stack { constructor() { this.items = []; } push(item) { this.items.push(item); } pop() { if (this.isEmpty()) { return "Stack is empty"; } return this.items.pop(); } peek() { if (this.isEmpty()) { return "Stack is empty"; } return this.items[this.items.length - 1]; } isEmpty() { return this.items.length === 0; } size() { return this.items.length; } print() { console.log(this.items.toString()); } // Define the iterator method [Symbol.iterator]() { let index = this.items.length - 1; let items = this.items; return { next() { if (index >= 0) { return { value: items[index--], done: false }; } else { return { value: undefined, done: true }; } } }; } }
// Create a new stack let stack = new Stack(); stack.push(15); stack.push(25); stack.push(35);
let stackIter = stack[Symbol.iterator](); console.log(stackIter.next()); console.log(stackIter.next()); console.log(stackIter.next()); console.log(stackIter.next()); |
{value: 35, done: false} {value: 25, done: false} {value: 15, done: false} {value: undefined, done: true} |
Generator |
function* numGenerator() { yield 100; yield 200; yield 300; }
let numGen = numGenerator(); console.log(numGen.next()); console.log(numGen.next()); console.log(numGen.next()); console.log(numGen.next()); |
{value: 100, done: false} {value: 200, done: false} {value: 300, done: false} {value: undefined, done: true} |
Custom Iterable |
let customIterable = { data: [10, 15, 20], [Symbol.iterator]() { let index = 0; let data = this.data; return { next() { if (index < data.length) { return { value: data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; } };
let customIter = customIterable[Symbol.iterator](); console.log(customIter.next()); console.log(customIter.next()); console.log(customIter.next()); console.log(customIter.next()); |
{value: 10, done: false} {value: 15, done: false} {value: 20, done: false} {value: undefined, done: true} |
Usage Examples: Action on Iterables
Action |
Code Snippet |
Code Output |
Iterable with Spread Syntax |
const spreadArray = [...customIterable]; console.log(spreadArray); |
[10, 15, 20] |
Usage Examples: Loop through Iterables
Loop |
Iterates over |
Code Snippet |
Code Output |
for..of |
String |
const str = "Hi!"; for (const s of str) { console.log(s); } |
H i ! |
|
Array |
const nums = [16, 27, 43]; for (const v of nums) { console.log(v); }
|
16 27 43 |
|
TypedArray |
|
10 123 45 |
|
Set |
const fruits = new Set(["Orange", "Banana", "Strawberry"]); for (const f of fruits) { console.log(f); }
|
Orange Banana Strawberry |
|
Map |
const fruitPrice = new Map([ ["Orange", 3.25], ["Banana", 4.75], ["Strawberry", 6.5] ]); for (const f of fruitPrice) { console.log(f); }
|
['Orange', 3.25] ['Banana', 4.75] ['Strawberry', 6.5] |
|
Custom Data Structure (Stack) |
for (let v of stack) { console.log(v); }
|
35 25 15 |
|
Generator |
for (let v of numGen){ console.log(v); }
|
100 200 300 |
while |
Any Iterable (Built-in, Custom or Generator) |
let iter = customIterable[Symbol.iterator](); while (true) { const result = iter.next(); console.log('value:', result.value, 'done: ', result.done); if (result.done) break; } |
value: 10 done: false value: 15 done: false value: 20 done: false value: undefined done: true |
Usage Examples: Iterators
Iterator (not Iterable) |
Code Snippet |
Code |
Custom Iterator |
function digitsIteration() { let digit = 0; return { next: function() { digit += 1;
if (digit < 10) { return { value: digit, done: false }; } else { return { value: undefined, done: true }; } } }; }
const digit = digitsIteration(); while (true) { const result = digit.next(); console.log('value:', result.value, 'done: ', result.done); if (result.done) break; } |
value: 1 done: false value: 2 done: false value: 3 done: false value: 4 done: false value: 5 done: false value: 6 done: false value: 7 done: false value: 8 done: false value: 9 done: false value: undefined done: true |
No comments:
Post a Comment