ES6 has introduced many new features to the JavaScript language. Two of these features, generators and iterators, have greatly changed the way we write specific functions in more complex front-end code.
While they work well together, their actual functions can be a bit confusing, so let's take a closer look.
Iteration is a common practice in programming, usually used to loop through a set of values, convert each value, or use or save it in some way for later use.
In JavaScript, we have always had such a for loop:
for (var i = 0; i < foo.length; i++) { // 对i执行某些操作 }
But ES6 gives us another option:
for (const i of foo) { // 对i执行某些操作 }
This is arguably more concise and easier to use, reminding me of languages like Python and Ruby. However, there is another very important thing to note about this new iteration: it allows you to interact directly with elements of the dataset.
Suppose we want to find out if each number in the array is a prime number. We can do this by creating a function that does this. It might look like this:
function isPrime(number) { if (number <= 1) { return false; } else if (number === 2) { return true; } for (var i = 2; i < number; i++) { if (number % i === 0) { return false; break; } } return true; }
Not the best in the world, but it works. The next step is to loop through our list of numbers and check if each number is prime using our shiny new function. It's very simple:
var possiblePrimes = [73, 6, 90, 19, 15]; var confirmedPrimes = []; for (var i = 0; i < possiblePrimes.length; i++) { if (isPrime(possiblePrimes[i])) { confirmedPrimes.push(possiblePrimes[i]); } } // confirmedPrimes现在是[73, 19]
Again, it works, but it's clumsy, and this clumsy depends largely on how JavaScript handles for loops. However, with ES6, we get an almost Python-like option in the new iterator. Therefore, the previous for loop can be written like this:
const possiblePrimes = [73, 6, 90, 19, 15]; const confirmedPrimes = []; for (const i of possiblePrimes){ if ( isPrime(i) ){ confirmedPrimes.push(i); } } // confirmedPrimes现在是[73, 19]
This is much cleaner, but the most striking thing is the for loop. The variable i now represents the actual item in an array named possiblePrimes. Therefore, we no longer need to call it by index. This means we don't have to call possiblePrimes[i] in the loop, but just call i.
Behind the scenes, this iteration takes advantage of ES6's shiny new Symbol.iterator() method. This method is responsible for describing iteration and when called, returns a JavaScript object containing the next value in the loop and a done key, which is true or false depending on whether the loop is completed.
If you are interested in this detail, you can read this wonderful blog post "Iterators gonna iterate" by Jake Archibald. As we dig into another part of this article: the generator, it also gives you a good idea of what’s going on behind the scenes.
The generator (also known as the "iter factory") is a new type of JavaScript function used to create specific iterations. They provide you with a special, custom way to loop through content.
Okay, so what does it mean? Let's look at an example. Suppose we want a function, and each time we call it, we will be given the next prime number:
for (var i = 0; i < foo.length; i++) { // 对i执行某些操作 }
If you're used to JavaScript, some of this stuff looks a bit like witchcraft, but it's not too bad in reality. We have that weird asterisk after the keyword function, but that just tells JavaScript that we are defining a generator.
Another strange part is the yield keyword. This is actually what the generator spits out when you call it. It roughly equivalent to return, but it retains the state of the function instead of rerunning everything every time it is called. It "remember" its location at runtime, so the next time you call it, it continues from the interrupt.
This means we can do this:
for (const i of foo) { // 对i执行某些操作 }
Then, whenever we want to get - you guessed it - the next prime number, we can call nextPrime:
function isPrime(number) { if (number <= 1) { return false; } else if (number === 2) { return true; } for (var i = 2; i < number; i++) { if (number % i === 0) { return false; break; } } return true; }
You can also just call nextPrime.next(), which is useful when your generator is not infinite, as it returns an object like this:
var possiblePrimes = [73, 6, 90, 19, 15]; var confirmedPrimes = []; for (var i = 0; i < possiblePrimes.length; i++) { if (isPrime(possiblePrimes[i])) { confirmedPrimes.push(possiblePrimes[i]); } } // confirmedPrimes现在是[73, 19]
Here, the done key tells you whether the function has completed its task. In our case, our function never ends, which theoretically gives us all prime numbers up to infinity (if we have that much computer memory).
Although ECMAScript 2015 has been completed and has been around for many years, browser support for its features (especially generators) is far from perfect. If you really want to use these and other modern features, you can look at translators like Babel and Traceur that will convert your ECMAScript 2015 code into equivalent (if possible) ECMAScript 5 code.
There are also many online editors that support ECMAScript 2015, or focus specifically on it, especially Facebook's Regenerator and JS Bin. If you just want to play and learn how JavaScript is written now, these are worth a look.
Generators and iterators provide quite a lot of new flexibility for our approach to JavaScript problems. Iterators allow us to write for loops in a more Python-like way, which means our code looks cleaner and easier to read.
Generator functions allow us to write functions that remember where they were last seen, and can continue execution from the interrupt. They can also be infinite in terms of what they actually remember, which is very convenient in some cases.
The support for these generators and iterators is good. They are supported in Node and in all modern browsers, except for Internet Explorer. If you need to support older browsers, the best way is to use a translator like Babel.
Iterators and generators are both features of ECMAScript 2015 and are used to process data flows. An iterator is an object that allows the programmer to iterate through all elements in a collection. It has a next() method that returns the next item in the sequence. On the other hand, the generator is a function that can stop halfway and then continue from the stop. In other words, the generator looks like a function, but it behaves like an iterator.
yield keyword is used for ECMAScript 2015 pause and restore generator functions (function* or legacy generator functions). yield can return a value from the generator function. This return value is usually an object with two properties: value and done. The value attribute is the result of calculating the yield expression, and done is a boolean value indicating whether the generator has generated its last value.
How to use generators for asynchronous programming in ECMAScript 2015?
What is the difference between for…of loop and for…in loop in ECMAScript 2015?
How to create a custom iterator in ECMAScript 2015?
What is the role of Symbol.iterator in ECMAScript 2015?
Of course, this is a simple example of generator functions in ECMAScript 2015:
for (var i = 0; i < foo.length; i++) { // 对i执行某些操作 }
In this example, the idMaker function is a generator that produces a sequence of numbers.
The throw() method in ECMAScript 2015 can be used in the generator to restore the execution of the generator function and throw an error from the yield expression. The throw() method can be used to handle errors that occur during the execution of the generator function.
done property is a boolean value returned by the iterator in ECMAScript 2015. It indicates whether the iterator has more values to return. If done is true, the iterator has exceeded the end of the iteration sequence. If done is false, the iterator can still generate more values.
The above is the detailed content of ES6 Generators and Iterators: a Developer's Guide. For more information, please follow other related articles on the PHP Chinese website!