Learnitweb

generator and generator function in JavaScript

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 method next() which returns a value yielded by the yield 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’s next() method is called, the generator function’s body is executed.
  • The return type of next() is an object with two properties, value and done. Here value is the value returned by the generator and done is a boolean 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, its done property is set to true.
  • Calling next() on a finished iterator does not execute its body and returns an object of the form {value: undefined, done: true}.
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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
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.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 }
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 }
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
function* generator() {}
let obj = new generator(); // TypeError: generator is not a constructor
function* generator() {} let obj = new generator(); // TypeError: generator is not a constructor
function* generator() {}
let obj = new generator(); // TypeError: generator is not a constructor

7. Generator as an object property

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 }
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 }
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

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 }
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 }
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 }