1. Introduction
Regular functions return a single value which could be primitive or object. A regular function can not be used to return multiple values based on demand. Generators can do that. A Generator can be used to create a data stream. A Generator will return a value based on a certain logic, each time it is called. For example, if you want to get a number 1 to 100 from a function, starting with 1 and each time incremented by 1, you can use Generator in this case. A regular function can’t do it as it does not have any functionality to keep track of previously returned value.
A generator complies to both iterable and iterator protocols. A Generator object is returned by a generator function. So, let us now discuss about generator function.
2. Generator function
A generator function starts with function* (function keyword followed by asterisk) and returns a Generator object. A Generator is a function which can be re-executed with their variable bindings saved for re-execution.
Following are some important points about a generator function:
- A
Generatorhas a methodnext()which returns a value yielded by theyieldexpression defined in the generator function. The body of a generator function is not executed immediately, instead an iterator object for function is returned. When the iterator’snext()method is called, the generator function’s body is executed. - The return type of
next()is an object with two properties,valueanddone. Herevalueis the value returned by the generator anddoneis abooleanwhich represents whether the generator has yielded the last value. - The
returnstatement when executed makes the generator as finished. If a value is returned by the generator, itsdoneproperty is set totrue. - Calling
next()on a finished iterator does not execute its body and returns an object of the form{value: undefined, done: true}.
function* generator(i) {
yield i;
yield i + 1;
yield i + 2;
}
const gen = generator(15);
console.log(gen.next().value); //15
console.log(gen.next().value); //16
console.log(gen.next().value); //17
You can also use function expression syntax for Generator.
let myGenerator = function* generator(i) {
yield i;
yield i + 1;
yield i + 2;
};
const gen = myGenerator(15);
console.log(gen.next().value); //15
console.log(gen.next().value); //16
console.log(gen.next().value); //17
3. yield*
yield* is used to call another generator.
function* double(x) {
yield x * 2;
yield x * 2;
}
function* generator(x) {
yield* double(x); // call another generator double
}
let gen = generator(5);
console.log(gen.next().value); // 10
console.log(gen.next().value); // 10
4. Infinite generator
function* infiniteGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const generator = infiniteGenerator();
console.log(generator.next().value); // 0
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
5. Return statement in generator
function* generator() {
yield 1;
return 2;
yield "unreachable";
}
var gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: true }
console.log(gen.next()); // { value: undefined, done: true }
6. Generators are not constructable
function* generator() {}
let obj = new generator(); // TypeError: generator is not a constructor
7. Generator as an object property
const generatorObj = {
*generator() {
yield 1;
yield 2;
},
};
const gen = generatorObj.generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
8. Generator as an object method
class Generator {
*generatorFn() {
yield 1;
yield 2;
yield 3;
}
}
const genObj = new Generator();
const gen = genObj.generatorFn();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
