Check out a free preview of the full Vanilla JavaScript Projects course:
The "Generators" Lesson is part of the full, Vanilla JavaScript Projects course featured in this preview video. Here's what you'd learn in this lesson:

Anjana compares iterable objects with generator functions. The yield keyword in generator functions allows the function to pause and resume execution. Generator functions can be used to implement iterables, and an example of using a generator as an iterator in a for-of loop is shared.

Get Unlimited Access Now

Transcript from the "Generators" Lesson

[00:00:00]
>> Let's complicate things even more. All right, so how do you write a iterator? Well, it's just a function that returns a certain type of object, so you can already do it. We all know how to write a function that returns an object, and you can write a complicated function that's like, if this is fun, and then return, that it's not done, and then if it is done, then return done, true.

[00:00:24] And essentially, that's totally possible without generators. But generators are a particular type of special function, they have their own keyword, it's function*. So when I said before that, functions run to completion, asterisk, it literally meant asterisk. Because generator functions, which you declare basically the same way you do a regular function, but with a little star after the word function, are really special.

[00:00:57] They have their own special keyword yield, which is similar to return, except return is like, and we're done forever, adieu, goodbye forever, adios. And yield is a little bit more like, okay, here's your value output but, au revior, hasta la vista, and not goodbye forever, we'll see you next time, see you soon.

[00:01:28] And so, for example, in a function body, when you have the word return, and then any other stuff after that, you've got a whole bunch of useless code that's never gonna run, right, unreachable code. Yield is just like, let's put a pin in it. And what this does is, instead of the function on the call stack having to run through its whole thing, the generator function can pop off the call stack, and then at some later point, resume execution right where it left off.

[00:02:05] And there is a whole bunch more to say about generators, I think they're super cool. They're not extremely widely used, even though I think they could be in JavaScript. But one thing that they are super, super, super useful for, is implementing iterables, because a generator qualifies according to both protocols.

[00:02:30] The iterator protocol, it is an iterator, meaning that you can call .next on it and get out the next value that was yielded in the function. And it's also an iterable, meaning that you can iterate over the values that it spits out, essentially. You can treat it like as if it were an array of those values or any other iterable of those values.

[00:03:05] So this is all to say, generators, function*, are a great easy way to write that specific type of iterator function that you need to be the value returned by symbol .iterator. Okay, now, where are we gonna go to read way more about all of this later, so that we can really get clear on all these different symbols and these different protocols and so on and so forth?

[00:03:35]
>> MDN.
>> MDN, of course, and I also, if you're curious, I have a couple other talks and things about iterators and generators. But for now, let's just look at a very relevant, very professional example in this professional JavaScript course. Okay, I have a generator that's called dogerator.

[00:03:59] And it essentially is gonna spit out different strings, randomly selected, not at all for compliance with a certain meme grammar. [LAUGH] So yield is sort similar to return, right? We notice the differences between dogerator and a regular function is, we've got the star on the function and we've got yield instead of return, and their stuff after the yield, and then we have a return.

[00:04:32] So generators are functions, they can return stuff, although that's not really what they're super useful for. Yield works much the same way as return, except that the generator can later be picked up and resume running. So for example, if I create an object called meme, and this object literally has nothing else in it of its own.

[00:05:01] [LAUGH] Other than I assign a value to symbol .iterator, which is this very special property that then JavaScript knows what to do with in the context of a for of loop, let's say. And I give the value of that iterator as the generator function, which yields, Strings, a few of them.

[00:05:34] Now, I can use meme in a for of loop. So I can say for (;et phrase of meme) and hopefully get out the extremely useful, Output that we're gonna see here. So iterator much generate, wow, undefined. So what's happening here? First, we got the so iterator yielded out, and that was essentially the value of calling, dogerator.next, but now, it's not working because, all right, in any case, this is essentially the same thing as, Asking it one at a time for the next value.

[00:06:41] for of is doing this under the hood for us. It is calling these .next methods, it's looking up the iterator from the symbol. It's following all of that, all of those pointers to find the right function which has the right type of return value, which returns the right type of objects that conform with this iteration protocol.

[00:07:03] So there's kind of a lot of magic happening under the hood, and it's way more complex than just calling .map on the underlying object, right? But the nice part about that is, once we wrap our heads around being able to quickly define iterators as generators, let's say. And being able to assign whatever objects we want a symbol iterator property with a particular type of value, we have now custom iterables for whatever we want.

[00:07:40] So you wanna make a meme collection, no problem, slapping iterator on it. You want to make a recommended Frontend Masters courses collection that you can put in a for of loop, have at it. And this is essentially why both the array of our engines and the HTML collection were able to be used in a for of loop, is because they implement this protocol.

[00:08:16] Now, that is all to say, are we gonna be implementing custom iterables every day in our life as JavaScript developers? I don't know too many who are. But it is, I think very important to understand, how we can expose a more convenient interface for, let's say, some very complex piece of data that our particular code base needs to pass around and people need to be able to get stuff out of it and what have you.

[00:08:46] How can we make it easier to work with that data, instead of having to remember some arcane method name that's like for each but not every single one, maybe just every third one? Whatever you wanna do in your fancy, complex piece of data that other people wanna be able to go through, you can implement that for your users or yourself, your future self, [LAUGH] with these iteration protocols.