Blog-Archiv

Donnerstag, 7. Dezember 2017

ES6 Iterator and Iterable

ES6: ?

Some built-in ES6 classes use the Iterator and Iterable "protocols". These are just naming conventions, but used by several new ES6 syntax elements:

In this article I won't cover generators or yield. Iterator and Iterable are their foundation, so let's first look at these.

ES6 Iterator and Iterable Tests

Click onto one of the buttons to get an example script into the text area. Below the script you find an explanation.

  •  
  •  
  •  
  •  
  •  
  •  
  •  
Description

Resume

An Iterable can create an Iterator, having a next() function, returning an object containing a value object and done boolean. The syntax for defining an iterator function is a little cryptic due to the fact that it must be a computed symbol-property holding a function. But all in all iterators will make ES6 code shorter and more flexible.




An Iterator is an object that has a next() function, with zero parameters. This function must return an object with properties value and done, each time it is called. The value is the next sequence value to be used by the caller, done is a boolean that is always false except when the iteration is over, then it is true. When done is true, the value should not be used any more.

This example shows an Iterator that iterates over an array. Every call increments the index pointing to the current element. As soon as the next() function has been called for all array-elements, an object with done false is returned, and the index is reset to be ready for next iteration.

The example is not really useful, because an Array is an Iterable itself. It is just here to show the responsibility of an Iterator, also called protocol.

An Iterator can be infinite. The caller must know this and carefully use it in loops, because it never delivers done === true. Such makes sense for Id-generator singletons that return an unique id each time they are called.

This example shows an iterator that simply increments a counter. The iterating while-loop must check how far it wants to loop - beware of infinite loops!

An Iterable is an object that returns an Iterator when calling the function in its Symbol.iterator property, like in const iterator = testString[Symbol.iterator]().

The Symbol.iterator is a static constant used to define iterator-factory-functions in objects and classes by convention.

Several ES6 classes are Iterable, e.g. String, Array and Map, but not Object. In Java we would see all implementers of the Iterable interface in an inheritance-tree, but neither ES6 nor JavaScript have interfaces. Everything is convenience and naming-convention.

When not using the for-of loop, which implicitly uses the iterable's iterator, it is possible to retrieve the iterator by using the expression iterable[Symbol.iterator](), i.e. calling the symbol-function representing a factory for iterators.

Here is how to implement an Iterable. It shows the syntax you have to use when you want to implement an Iterable. The function that returns the Iterator is the value of a computed symbol-property. It returns an object with a next() function which delegates to the iterable given in constructor.

The next() implementation must be an arrow-function here, because only the arrow-function provides the new lexical this handling. With the traditional object-syntax you would get an error due to a wrong this pointer.

This example is not really useful, because it simply forwards to another Iterable.

Iterating the most popular iterables in for-of loops. For-of loops require an iterable behind "of", like the spread-operator requires it behind "...".

Mind the constructor capability of Map. You can build it using an array of tuple-arrays, or in a "fluent" way using set(). The for-of loop uses a destructuring-statement [ key, value ] to put key and value of each map-entry into local loop-variables.

Testing if two separate iterators can be used in parallel, i.e. whether they have state stored in the common object they iterate.

Keine Kommentare: