Javascript Generator Function Basics
Tags: javascript
Published: 2021-07-27 08:03:30

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?

```js
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!

```js
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.

```js
let word = greet()
console.log(word) // Object [Generator] {}
```

And then we can get the values by invoking the `next` method from the `word` variable.

```js
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:

```js
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.

```js
...
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 }
```

## Working with loop

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.

```js
for(let w of word) {
  console.log(w)
}
/*
Hello world!
Hello again!
Hello, I am bored
*/
```

## Endless value generator

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:

```js
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:

```js
// 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:

```js
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:

```js
// 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:

dcode: https://www.youtube.com/watch?v=EzdgkEMvrvA&t=4s