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
Generator
has a methodnext()
which returns a value yielded by theyield
expression 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,value
anddone
. Herevalue
is the value returned by the generator anddone
is aboolean
which represents whether the generator has yielded the last value. - The
return
statement when executed makes the generator as finished. If a value is returned by the generator, itsdone
property 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 }