27
Javascript Generator Function Basics
We'll learn about javasciprt feature not many people use or talk about. It's generator function. So what is it?
Generator function is a function that can generate more than one value. So how do we make it?
function* greet() {
yield 'Hello World!'
}
So what's different with regular function? First, instead of function
we define it with asterisk function*
to indicate this isn't your regular function. Then instead of return
a value, we yield
it. The special thing about yield
is that the function can be yield
-ed more than once!
function* greet() {
yield 'Hello world!'
yield 'Hello again!'
yield 'Hello, I am bored'
}
Now how do we get those values? First we can turn it into generator object by invoking it.
let word = greet()
console.log(word) // Object [Generator] {}
And then we can get the values by invoking the next
method from the word
variable.
let word = greet()
console.log(word.next()) // { value: 'Hello world!', done: false }
Notice that the value logged turned into an object with 'Hello world!'
there in value
property. And we have another property called done
with value false
, what is that? The done
property indicates whether all the value from greet
function has been yielded or not. In a simple way, it tells you:
Hey this is the value you wanted, but I'm not done yet. I still have more.
So if we want to get the other values, we can do it again and again, you get the idea:
let word = greet()
console.log(word.next()) // { value: 'Hello world!', done: false }
console.log(word.next()) // { value: 'Hello again!', done: false }
console.log(word.next()) // { value: 'Hello, I am bored!', done: false }
But wait, is that it? Kind of. Because you can still call next after that. It's just... not too necessary. But hey it's your code.
...
console.log(word.next()) // { value: 'Hello, I am bored!', done: false }
console.log(word.next()) // { value: undefined, done: true }
console.log(word.next()) // { value: undefined, done: true }
console.log(word.next()) // { value: undefined, done: true }
Now assuming the generator function is not ours (maybe it's a package) how do we know how may values can we yield? We can get all of them by using for ... of
loop.
for(let w of word) {
console.log(w)
}
/*
Hello world!
Hello again!
Hello, I am bored
*/
Now say that we want to get the first 5 numbers that are divisible by 3 (3, 6, 9, 12, 15). But when i want the first 7 numbers, 18 and 21 will come along. We can make our function like this:
function* divisibles3() {
let num = 1
while(true) {
if(num % 3 === 0) yield num
num++
}
}
let n = divisibles3()
We can get the values by calling it as many as we want:
// 1. First 5
console.log(n.next().value) // 3
console.log(n.next().value) // 6
console.log(n.next().value) // 9
console.log(n.next().value) // 12
console.log(n.next().value) // 15
// 2. Fisrt 7
for(let i = 0; i < 5; i++) {
console.log(n.next().value) // 3, 6, 9, 12, 15, 18, 21
}
Or better, we can make it dynamic so the function can take any divisible:
function* divisibles(div) {
let num = 1
while(true) {
if(num % div === 0) yield num
num++
}
}
Now we can get any first numbers divisible by any number:
// 1. First 3 divisible by 4
let n = divisibles(4)
for(let i = 0; i < 3; i++) {
console.log(n.next().value) // 4, 8, 12
}
// 2. Fisrt 4 divisible by 7
let n = divisibles(7)
for(let i = 0; i < 4; i++) {
console.log(n.next().value) // 7, 14, 21, 28
}
Source:
27