JS: Generator Function (asterisk)

By Xah Lee. Date: . Last updated: .

(new in ECMAScript 2015)

What is Generator Function

A generator function is a function that returns a Generator .

Purpose of Generator Function

For writing a function that return a object such that it is both Iterable Object and Iterator .

Syntax

Generator function declaration

function * name (params) {body}

generator function declaration.

The space before or after the asterisk * can be omitted.

  • In the generator function body, you use yield instead of return.
  • Each yield is a stopping point.
  • When the generator function is called, it exit at yield point and save state.
  • When it is its called again, it resume at the yield point.

🟢 TIP: you can use while loop or for-loop in the body of generator function. 〔see JS: Loop. for while do〕. However, if you want to do functional programing approach, use for-of Loop. Do not use array methods 〔see JS: Array.prototype〕 , because array methods usually do not work with Iterable Object.

🟢 TIP: Arrow Function cannot be used for generator function.

Example. Simple Yields Statements

// define a generator function
function* gf() {
 yield 3;
 yield 4;
 yield 5;
}

// generator function returns a generator object
const xout = gf();
// now xout is a generator

// result is iterable
console.assert(Reflect.has(xout, Symbol.iterator));

// result is iterator
console.assert(Reflect.has(xout, "next"));

// use Array.from to turn it into array
console.assert(JSON.stringify(Array.from(xout)) === `[3,4,5]`);

Example. Convert Array to Iterable

// convert array to iterable
function* gf() {
 for (let x of [3, 7, 2, 5]) yield x;
}

// use Array.from to turn it into array
console.assert(JSON.stringify(Array.from(gf())) === `[3,7,2,5]`);

Example. Convert Data Object to iterable

// convert data object to iterable
function* gf() {
 for (let x of Object.entries({ aa: 1, bb: 2, cc: 3 })) yield x;
}

// use Array.from to turn it into array
console.assert(
 JSON.stringify(Array.from(gf())) === `[["aa",1],["bb",2],["cc",3]]`,
);

Generator function expression

function * (params) {body}

generator function expression

Generator method in object literal expression

{etc, * name (params) {body}, etc}

Generator Method, defined inside Object Literal Expression

The Type of Generator Function

Type of Generator Function is a Generator Function object, and typeof operator returns "function".

Type of Generator is Generator object (and not a function object), and typeof operator returns "object".

// define a generator function
function* ff() {
  yield 3;
  yield 4;
  yield 5;
}

// type of Generator Function is function
console.assert(typeof ff === "function");

const gg = ff();

// type of Generator is object
console.assert(typeof gg === "object");

〔see Determine Type of Object

Generator Function Constructor

Another way to create generator function is by calling the generator function constructor.

In JavaScript spec, generator function constructor is written as “GeneratorFunction”. But it is not a keyword you can use.

There's no syntax that represents generator function constructor “GeneratorFunction” , but you can get it by:

const GeneratorFunction = Reflect.getPrototypeOf(function* () {}).constructor;

console.log(GeneratorFunction);
// [Function: GeneratorFunction]

Once you have the constructor GeneratorFunction, you can create new generator function by the syntax:

GeneratorFunction (p1, p2, … , pn, body)

where all arguments are strings.

It works similarly to Function Constructor.

〔see Function Constructor

For example,

const gf = Reflect.getPrototypeOf ( function *(){} ).constructor ; const ff = gf ( " yield 3; yield 4; yield 5;" );

is roughly equivalent to:

function * ff () { yield 3; yield 4; yield 5; }

Here is a full example.

const gf = Reflect.getPrototypeOf(function* () {}).constructor;

// define a generator function
const ff = gf(" yield 3; yield 4; yield 5;");

// this is basically equivalent to
// function * ff () { yield 3; yield 4; yield 5; }

// generator function returns a generator object
const gg = ff();
// now gg is a generator object

// because generator is also a iterable object

// we can use Array.from on iterable object
console.log(Array.from(gg));
// [ 3, 4, 5 ]

In general, there is no practical use of Generator Function constructor. Use instead this literal expression

function * name () {body}

The reason the generator function constructor object exist is so that JavaScript can maintain the language semantic relationship consistency of its object and class and constructor.

That is, each object of type x has a constructor object Xcon that creates objects of type x, and Xcon has property key of string type "prototype", whose value is a data object that is the parent of all object of type x, and this object has property key of string type "constructor", whose value is the Xcon.

JavaScript. Iterable, Iterator