At the July TC39 meeting we decided to explore removing @@create in favor of a model where super()
in a [[Construct]]
call creates the instance object. To correctly know how to create the instance and set the prototype a [[Construct]]
call gets an implicit receiver which is the constructor function new
was called with.
class Base {
constructor() {
var object = Object.create(new*.prototype); // new binding needs new syntax...
// bikeshed...
myWeakMap.set(object, myHiddenData);
return object;
}
}
class Derived extends Base {
constructor() {
// this cannot be accessed here because the instance is
// created by the call to super() below
super(); // as if "const this = Base.[[Construct]](arguments, receiver)"
// where receiver is the operand in "new C"
// this is now defined.
console..log(this);
}
}
In this case the Base class gets to create the instance object (it does not have to return an object, this is the usual constructor semantics but if an exotic object is needed return is simple way to think of it).
For custom elements we could imagine this working something like this:
class MyElement extends HTMLImageElement {
constructor(src) {
super(src, 32, 32);
}
}
document.registerElement(MyElement);
class HTMLElement extends Element {
constructor() {
var receiver = new*; // bikeshed
var tagName = getTagNameFromConstructor(receiver);
var instance = document.createElement(tagName);
Object.setPrototypeOf(instance, receiver.prototype);
return instance;
}
}
class HTMLImageElement extends HTMLElement {
constructor(src, w, h) {
super();
this.src = src;
...
}
set src(v) {
this.setAttribute('src', v);
}
...
}
This works because the HTMLElement constructor (in the p.o.c. above) is responsible for creating the actual instance and the new proposal passes F
in new F
all the way down through the construct call chain (implicitly).