This course won’t waste your time with long hours of video, or long pages of theory that you will never use in practice. We will instead focus on learning just enough theory to solve some exercises. Once you are done with the exercises, you can check the reference solutions, and conclude some lessons. In fact, some of the theory are sometimes placed in the reference solutions.

If you like this article, check out the course here.

In my last article, I gave you six exercises. In this article, you can check the reference solutions.

`for-of`

loop?let message = 'ok'; let messageIterator = message[Symbol.iterator](); messageIterator.next(); for ( let item of messageIterator ) { console.log( item ); }

Therefore, in the

`for-of`

loop, the remaining `k`

letter is printed out.let getCountdownIterator = // Your code comes here console.log( [ ...getCountdownIterator() ] ); > [9, 8, 7, 6, 5, 4, 3, 2, 1]

let getCountdownIterator = function *() { let i = 10; while( i > 1 ) { yield --i; } } console.log( [ ...getCountdownIterator() ] ); > [9, 8, 7, 6, 5, 4, 3, 2, 1]

The generator function yields the numbers

`9`

to `1`

. The spread (`...`

) operator consumes all values. Then the generator function returns `undefined`

, ending the iteration process.let todoList = { todoItems: [], addItem( description ) { this.todoItems.push( { description, done: false } ); return this; }, crossOutItem( index ) { if ( index < this.todoItems.length ) { this.todoItems[index].done = true; } return this; } }; todoList.addItem( 'task 1' ).addItem( 'task 2' ).crossOutItem( 0 ); let iterableTodoList = // ???; for ( let item of iterableTodoList ) { console.log( item ); } // Without your code, you get the following error: // Uncaught TypeError: todoList[Symbol.iterator] is not a function

We could use well known symbols to make *todoList* iterable. We can add a

`*[Symbol.iterator]`

generator function that yields the elements of the array. This will make the `todoList`

object iterable, yielding the elements of `todoItems`

one by one.let todoList = { todoItems: [], *[Symbol.iterator]() { yield* this.todoItems; } addItem( description ) { this.todoItems.push( { description, done: false } ); return this; }, crossOutItem( index ) { if ( index < this.todoItems.length ) { this.todoItems[index].done = true; } return this; } }; let iterableTodoList = todoList;

let todoList = { todoItems: [], addItem( description ) { this.todoItems.push( { description, done: false } ); return this; }, crossOutItem( index ) { if ( index < this.todoItems.length ) { this.todoItems[index].done = true; } return this; } }; todoList.addItem( 'task 1' ).addItem( 'task 2' ).crossOutItem( 0 ); let todoListGenerator = function *() { yield* todoList.todoItems; } let iterableTodoList = todoListGenerator();

The first solution reads a bit like a hack. The second solution looks cleaner even if you have to type more characters.

let errorDemo = function *() { yield 1; throw 'Error yielding the next result'; yield 2; } let it = errorDemo(); // Execute one statement at a time to avoid // skipping lines after the first thrown error. console.log( it.next() ); console.log( it.next() ); console.log( [...errorDemo()] ); for ( let element of errorDemo() ) { console.log( element ); }

console.log( it.next() ); > Object {value: 1, done: false} console.log( it.next() ); > Uncaught Error yielding the next result console.log( [...errorDemo()] ); > Uncaught Error yielding the next result for ( let element of errorDemo() ) { console.log( element ); } > Object {value: 1, done: false} > Uncaught Error yielding the next result

We created three iterables in total:

`it`

, one in the statement in the spread operator, and one in the `for-of`

loop.In the example with the

`next`

calls, the second call results in a thrown error.In the spread operator example, the expression cannot be evaluated, because an error is thrown.

In the

`for-of`

example, the first element is printed out, then the error stopped the execution of the loop.The Fibonacci sequence is defined as follows:

`fib( 0 ) = 0`

`fib( 1 ) = 1`

- for
`n > 1`

,`fib( n ) = fib( n - 1 ) + fib( n - 2 )`

function *fibonacci() { let a = 0, b = 1; yield a; yield b; while( true ) { [a, b] = [b, a+b]; yield b; } }

Note that you only want to get the

`next()`

element of an infinite sequence. Executing `[...fibonacci()]`

will skyrocket your CPU usage, speed up your CPU fan, and then crash your browser.`filter`

generator function. Filter the elements of the Fibonacci sequence by keeping the even values only.function *filter( iterable, filterFunction ) { // insert code here }

function *filter( iterable, filterFunction ) { for( let element of iterable ) { if ( filterFunction( element ) ) yield element; } } let evenFibonacci = filter( fibonacci(), x => x%2 === 0 );

Notice how easy it is to combine generators and lazily evaluate them.

evenFibonacci.next() > {value: 0, done: false} evenFibonacci.next() > {value: 2, done: false} evenFibonacci.next() > {value: 8, done: false} evenFibonacci.next() > {value: 34, done: false} evenFibonacci.next() > {value: 144, done: false}

Lazy evaluation is essential when we work on a large set of data. For instance, if you have 1000 accounts, chances are that you don’t want to transform all of them if you just want to render the first ten on screen. This is when lazy evaluation comes into play.

`YES`

below, and sign up.Would you like to learn ES6?

Strengthen your JavaScript knowledge with marketable skills!

YesORNo

Close
Get the Course "ES6 in Practice"!

Learn Marketable Skills.

Verify your knowledge with real world exercises.

Verify your knowledge with real world exercises.

I'm In!

Close
Thank you for your subscription.

Please check your inbox to access the first lesson.

Close