An object is an iterator when it knows how to access items from a collection one at a time, while keeping track of its current position within that sequence.
In JavaScript an iterator is an object that provides a next() method which returns the next item in the sequence. This method returns an object with two properties: done
and `value.
function makeIterator(array){
var nextIndex = 0;
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
}
}
var it = makeIterator(['yo', 'ya']);
console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true
An object is iterable if it defines its iteration behavior, such as what values are looped over in a for..of
construct. Some built-in types, such as Array
or Map
, have a default iteration behavior, while other types (such as Object
) do not.
In order to be iterable, an object must implement the @@iterator
method, meaning that the object (or one of the objects up its prototype chain) must have a property with a Symbol.iterator
key
### Built-in iterables
String
, Array
, TypedArray
, Map
and Set
are all built-in iterables, because the prototype objects of them all have a Symbol.iterator
method.
### Syntaxes expecting iterables
Some statements and expressions are expecting iterables, for example the for-of
loops, spread operator, yield*, and destructuring assignment.
> function logIterator( iterator ) {
var current;
while( true ) {
current = iterator.next();
if ( current.done ) {
break;
}
console.log( current.value );
}
}
>logIterator( ["a","b", "c", "d"].entries() );
[0, "a"]
[1, "b"]
[2, "c"]
[3, "d"]
> logIterator( ["a","b", "c", "d"].keys() );
0
1
2
3
> var map = new Map();
> map.set(0, "a");
> map.set(1, "b");
> map.set(2, "c");
> map.set(3, "d");
> logIterator(map.entries());
[0, "a"]
[1, "b"]
[2, "c"]
[3, "d"]
> logIterator(map.keys());
0
1
2
3
> logIterator(map.values());
a
b
c
d
> var map = new Map();
> map.set(0, "a");
> map.set(1, "b");
> map.set(2, "c");
> map.set(3, "d");
> for (data of map.entries()) {
console.log(data);
}
[0, "a"]
[1, "b"]
[2, "c"]
[3, "d"]
// w/ Laziness
table[Symbol.iterator] = function () {
var keys = Object.keys(this).sort();
var index = 0;
return {
next: function () {
return {
value: keys[index], done: index++ >= keys.length
};
}
}
}
// w/ Laziness => sort is only calculates when first next()
table[Symbol.iterator] = function () {
var _this = this;
var keys = null;
var index = 0;
return {
next: function () {
if (keys === null) {
keys = Object.keys(_this).sort();
}
return {
value: keys[index], done: index++ >= keys.length
};
}
}
}