Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript generators and their prototype chains

I am toying around with JavaScript generators and have 2 questions based on the following code and its output:

const a = function*(){}(); // Object [Generator] {}
const b = a.__proto__;     // Object [Generator] {}
const c = b.__proto__;     // Object [Generator] {}
const d = c.__proto__;     // {}
const e = d.__proto__;     // {}
const f = e.__proto__;     // null
console.log(a, b, c, d, e, f);

Question 1

It seems like every generator object has its own unique prototype, and they all share a common prototype:

const x = function*(){}();
const y = x.__proto__;
const z = y.__proto__;
console.log(b === y); // false
console.log(c === z); // true

Is my above understanding correct?

Question 2

Since f is null, e is probably Object.prototype:

console.log(e === Object.prototype); // true

However, I can't figure out what d is. Is there a Something.prototype that is equal to d?

like image 760
fredoverflow Avatar asked Aug 07 '20 08:08

fredoverflow


2 Answers

In the section GeneratorFunction Objects, there is a figure of the relationships: generator_objects_relationships

Question 1

Yes.

Question 2

d is an IteratorPrototype. And by the doc:

The following expression is one way that ECMAScript code can access the %IteratorPrototype% object:

Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]()))

It seems that there is not an Iterator such that Iterator.prototype is equal to d.

like image 50
yao99 Avatar answered Oct 13 '22 18:10

yao99


Yes. Let's break this down some more:

function* g() {} // a generator function
const GeneratorFunction = Object.getPrototypeOf(g).constructor;
console.assert(Object.getPrototypeOf(GeneratorFunction) == Function);
const Generator = GeneratorFunction.prototype;
console.assert(Object.getPrototypeOf(Generator) == Function.prototype);
const ArrayIteratorPrototype = Object.getPrototypeOf([].values());

const a = g(); // a generator
console.assert(a instanceof g);

const b = Object.getPrototypeOf(a); // a prototype object
console.assert(b == g.prototype);

const c = Object.getPrototypeOf(b); // the Generator.prototype
console.assert(c == Generator.prototype);

const d = Object.getPrototypeOf(c); // the Iterator.prototype
console.assert(d == Object.getPrototypeOf(ArrayIteratorPrototype));

const e = Object.getPrototypeOf(d); // the Object.prototype
console.assert(e == Object.prototype);

const f = Object.getPrototypeOf(e); // null
console.assert(f == null);

The object d you were looking for is the prototype object shared by all iterators (array iterators, map iterators, set iterators, string iterators etc), including generators. There is not global Iterator (yet) just as there are no global Generator or GeneratorFunction.

like image 2
Bergi Avatar answered Oct 13 '22 17:10

Bergi