📜 ⬆️ ⬇️

Introduction to JavaScript Iterators on ES6

EcmaScript 2015 (also known as ES6) introduces a completely new iterator concept that allows you to specify sequences (limited and others) at the language level.

Let's talk about this in more detail. We are all familiar with the for loop operator, and many even know his less popular for-in brother. The latter can be used to help us explain the basic principles of working with iterators.
for (var key in table) { console.log(key + ' = ' + table[key]); } 

There are many problems with the for-in loop operator, but the biggest one, perhaps, is that it does not give any guarantees of consistency. We will try to solve this problem with the help of iterators. More information under the cut!

For-of loop

for-of is a new syntax introduced in ES6, designed to work with iterators.
 for (var key of table) { console.log(key + ' = ' + table[key]); } 

In this example, we want to see an iterator application that guarantees a sequence of keys. In order for an object to become iterable, it must use an iterative protocol, that is, an object (or one of the objects up the prototype chain) must have the property with the Symbol.iterator key. This is what uses for-of, and in this particular example, it will be a table [Symbol.iterator].
')
Symbol.iterator is another addition to ES6, which we will discuss in detail, but some other time. For now, consider that Symbol.iterator is a way to set special keys that will not conflict with ordinary object keys.

The element of the table [Symbol.iterator] object must be a function that conforms to the iterator protocol, that is, it must return an object as follows: {next: function () {}}.
 table[Symbol.iterator] = function () { return { next: function () {} } } 

Every time the next function is called for-of, it must return an object that looks like this: {value: ..., done: [true / false]}. The full implementation of our iterator is as follows:
 table[Symbol.iterator] = function () { var keys = Object.keys(this).sort(); var index = 0; return { next: function () { return { value: keys[index], done: index++ >= keys.length }; } } } 

Laziness

Iterators allow us to delay the execution of a function until the first call to next. In the example above, as soon as we call the iterator, the process of getting and sorting keys begins. However, what happens if the next is not called? Just spend time in vain. So let's optimize the code:
 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 }; } } } 

Difference between for-of and for-in

It is important to understand the difference between for-of and for-in. We give a simple but illustrative example of why this is so.
 var list = [3, 5, 7]; list.foo = 'bar'; for (var key in list) { console.log(key); // 0, 1, 2, foo } for (var value of list) { console.log(value); // 3, 5, 7 } 

As you can see, for-of gives only the values ​​that are in the array, and omits all other properties. This happens because the array iterator only returns the expected parameters.

Built-in iterators

String , Array , TypedArray , Map , Set contain built-in iterators, because their prototype objects contain the Symbol.iterator method.
 var string = "hello"; for (var chr of string) { console.log(chr); // h, e, l, l, o } 

Spread construct

The Spread operator can also take iterators. You can use it like this:
 var hello = 'world'; var [first, second, ...rest] = [...hello]; console.log(first, second, rest); // wo ["r","l","d"] 

Infinite iterator

Using an infinite iterator is as easy as never returning done: true. Of course, you need to make sure that there is no infinite loop anywhere.
 var ids = { *[Symbol.iterator]: function () { var index = 0; return { next: function () { return { value: 'id-' + index++, done: false }; } }; } }; var counter = 0; for (var value of ids) { console.log(value); if (counter++ > 1000) { // let's make sure we get out! break; } } 

Generators

If you are not familiar with generators in ES6, then it's time to read the documentation . In a nutshell, generators are functions that you can pause and then resume. Recently, generators are the most talked about functionality in ES6. The context is saved between restarts. Generators contain both protocols, Iterable and Iterator. Let's look at a simple example:
 function* list(value) { for (var item of value) { yield item; } } for (var value of list([1, 2, 3])) { console.log(value); } var iterator = list([1, 2, 3]); console.log(typeof iterator.next); // function console.log(typeof iterator[Symbol.iterator]); // function console.log(iterator.next().value); // 1 for (var value of iterator) { console.log(value); // 2, 3 } 

Taking into account the code above, we can rewrite the iterator code that sorts the keys using generators:
 table[Symbol.iterator] = function* () { var keys = Object.keys(this).sort(); for (var item of keys) { yield item; } } 

Total

Iterators open up a whole new dimension to working with cycles, generators, and variable sets. They can be transferred, set as a class, describes a list of parameters, create “lazy” or endless lists, etc. etc.

ES6 today

How can I take advantage of ES6 today? The use of transpilers has become the norm in the last few years. Neither simple developers nor large companies feel free to use them. Babel is a transpiler from ES6 to ES5 that supports all the innovations of ES6.

If you use Browserify , you can add Babel in just a couple of minutes . Of course, there is support for almost any build with Node.js. For example: Gulp, Grunt and many others.

What about browsers?

Most browsers are gradually adding new features , but no one has yet got full support. What now to wait? It depends. It makes sense to start using language features that will become universal in a year or two. This will allow you to comfortably move to a new stage. However, if you need 100% control over the source code, then for now it's better to wait and use ES5.

Translation prepared by: greebn9k (Sergey Gribnyak), silmarilion (Andrey Khakharev)

Source: https://habr.com/ru/post/264345/


All Articles