The ECMAScript 6 added iterators and < in> generators to the hard core of the language, but today (late 2015) there are still limitations support in browsers . I will explain how it works / will work, so that we are already prepared for the future:)
Iterators
An iterator in ES6 is simply an object that implements a next
method, responsible for returning the next item in the sequence - an object with the properties done
and value
. There is no new syntax, what was created is simply a protocol. MDN :
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
link
In PHP, an iterator can be enumerated by a foreach
, because it is also Enumerable
. In ES6 there is for..of
, but it does not enumerate iterators , but rather iterables , which are objects that implement @@ iterator - that is, they have a method with the key Symbol.iterator
. This method returns an iterator :
function makeIterable(array){
var nextIndex = 0;
var it = {};
it[Symbol.iterator] = function() {
return {
next: function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
}
};
};
return it;
}
for(let val of makeIterable(['yo', 'ya'])) console.log(val);
link
The most practical way to create an iterable is to use a generating function (which we'll discuss later):
var myIterable = {}
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for(let val of myIterable) {
console.log(val)
}
link
An iterator can also be iterable , which is closer to what happens in PHP:
function makeIterableIterator(array){
var nextIndex = 0;
var it = {};
it[Symbol.iterator] = function() {
return this;
};
it.next = function(){
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{done: true};
};
return it;
}
for(let val of makeIterableIterator(['yo', 'ya'])) console.log(val);
link
This is more or less what the iterables do as part of the language's core, such as Array
, Map
, Set
etc.
To learn more about iterables , I recommend reading Iterables and iterators in ECMAScript 6 , where there are many examples.
Generators
Generating functions make it easy to create iterables . They are basically functions with the ability to suspend their execution, and still maintain the state for the next execution. ES6 introduced a new syntax for this, function*
. Simple example of MDN:
function* idMaker(){
var index = 0;
while(true)
yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
link
The generator created by idMaker
is both iterator and iterable . The "magic" is due to yield
, which is who suspends execution. Each time the next
is executed, the function resumes from where it stopped, with its local scope intact.
Basically, generators allow the creation of computed sequences in a "lazy" way, one value at a time, as values are needed. They can even be combined with promises so that it is possible to treat asynchronous operations in a similar way, can be chained recursively, and can be exchanged between them, allowing the implementation of co-routines.