With an iterator / generator in javascript?

6

In PHP we have the Iterators and the Generator .

Example Iterator:

$f = new FileSystemIterator(__DIR__);

foreach($f as $file) {
    echo $file->getFilename();
}

Example Generator:

function sequence($start, $end) {
    for ($i = $start; $i <= $end; ++$i) {
       yield $i;
    }
}

foreach(sequence(1, 10) as $value) {
     echo $value;
}

// Imprime: 12345678910

I find it very interesting to use both, especially when it comes to Iterator iterating over a list of objects.

Is there any way to create a Iterator or Generator in Javascript? And if not, is there any way to simulate them?

    
asked by anonymous 08.10.2015 / 17:06

1 answer

6

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.

    
09.10.2015 / 16:30