Iterables and Iterators
Iterators
The iterator pattern is when you consume the values of a data source (could be a database, could be an array) one by one.
- You get the next value by calling
.next()
- Iterables must have a property with a
@@iterator
key, which is available with constantSymbol.iterator
[Symbol.iterator]
is a zero arguments function that returns an object conforming to the iterator protocol- An iterator result is an object with two properties on it:
value
anddone
. When the result becomes{ value: undefined, done: true }
, you have iterated over every value in the iterable. There’s nothing left to iterate over at this point.
Iterables
- An iterable is something that can be iterated over
- Built-in iterables are:
String
,Array
,TypedArray
,Map
,Set
and array-like objects (arguments
orNodeList
). But NOTObject
. But you can create your own iterable object by implementing a.next()
method for it
for…of
the for...of
statement creates a loop iterating over built-in and user-defined iterable objects.
for (variable of iterable) {
// do something
}
You can use declare the variable with either var
, let
or const
const iterable = [10, 20, 30];
for (let value of iterable) {
value += 1;
console.log(value);
}
// 11
// 21
// 31
Creating custom iterators
The Object
is not iterable, which is unfortunate because that’s the one we use the most, we build our own objects.
// Objects are not iterable..
var myObj = {
a: 1,
b: 2,
c: 3
}
for (let i of myObj) {
console.log(i) // TypeError: myObj is not iterable
}
But, we can define our own iterators by implementing the iterator protocol, i.e. implementing a next()
method that returns at least the following two properties: value
and done
var mySecondObj = {
a: 1,
b: 2,
c: 3,
[Symbol.iterator]: function(){ // the @@iterator property saved as the constant [Symbol.iterator]
let keys = Object.keys(this)
let index = 0
return {
next: () => (index < keys.length) ? // defining our own 'next' function to implement 'iterator protocol'
{ done: false, value: this[keys[index++]]} :
{ done: true, value: undefined}
}
}
}
console.log([...mySecondObj]) // [ 1, 2, 3 ]