How to Use a Generator Function as a Constructor

Yifeng Ruan
2 min readMay 11, 2016

--

Generator function is a powerful feature of ECMAScript 2015 (aka ES6), but you cannot use it as a constructor.

function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}

new F()
// TypeError: F is not a constructor

In above code, F is a generator function. You cannot use it with new command, since F is not a constructor.

Is there a way to use it as a constructor, which means to use new command getting an instance, then use generator function’s next() method upon the instance?

I found a workaround.

First, We can use an empty object binding the this object inside generator function.

function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var obj = {};
var f = F.call(obj);

After we call the generator function, the obj will be the instance of the generator function.

f.next();  // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

obj.a // 1
obj.b // 2
obj.c // 3

In above code, f is an iterator returning from F which binds obj to the inside this object. Then we call f.next() three times, since F has two yield expressions inside. After this, all instance properties will be bind to obj, so obj becomes F’s instance.

Next, I use F.prototype replacing obj, which means now we could get instance properties from f.

function* F() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}
var f = F.call(F.prototype);

f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

The last step is wrapping F into a constructor.

function* gen() {
this.a = 1;
yield this.b = 2;
yield this.c = 3;
}

function F() {
return gen.call(gen.prototype);
}

Now we can use new upon F, and use next() upon the instance.

var f = new F();

f.next(); // Object {value: 2, done: false}
f.next(); // Object {value: 3, done: false}
f.next(); // Object {value: undefined, done: true}

f.a // 1
f.b // 2
f.c // 3

All is done. Leave your comments on Hacker News.

--

--