This is all intimately tied to the still-ongoing how-to-subclass-builtins 
discussion that is unfortunately happening on a private TC39 thread. The 
essential idea, however, is that as long as you do

```js
class MyInputElement extends HTMLInputElement {
  constructor() {
    super(); // this is key
  }
}
```

then all instances of MyInputElement will get all internal slots and other 
exotic behavior of HTMLInputElement. The `super()` call is the signal that the 
object should be allocated and initialized using the logic of HTMLInputElement 
instead of Function.prototype (the default).

This will require defining a constructor for HTMLInputElement, of course, but 
it's pretty predictable you wouldn't be able to create subclasses of something 
without a constructor.

I am not sure exactly how this fits in with an ES6-era 
document.registerElement. This is the right time to start thinking about that, 
certainly.

Off the top of my head, ideally document.registerElement should just be a 
"registration" call, and should not actually need to modify the constructor or 
create a new constructor as it does today. The generated constructor in [1] 
does nothing special that the above constructor (which consists entirely of 
`super()`) could not be made to do automatically, as long as the Element 
constructor was made smart enough. (`super()` eventually will delegate up to 
the Element constructor.)

To explain that in more detail I need one more probable-ES6 concept, which is 
the "new target." In the expression `var x = new MyInputElement()`, ` 
MyInputElement` is the "new target". Part of the ES6 subclassing story is that 
all superclass constructors will be passed an implicit parameter for the new 
target. So, when the `MyInputElement()` constructor calls `super()`, that calls 
the [[Construct]] internal method of HTMLInputElement, passing in the new 
target of MyInputElement. Similarly when HTMLInputElement in turn calls 
`super()`, that will call the [[Construct]] internal method of HTMLElement, 
still passing in the new target of MyInputElement. Etc. until Element also gets 
a new target of MyInputElement.

With this in hand we could see how to define a "smart enough" element 
constructor. It would first look up the new target in the custom element 
registry. If it is there, it retrieves the definition for it, and can do all 
the work currently specified in [1]. That means that the actual constructor for 
`MyInputElement` can be as above, i.e. simply `super()`.

[1]: 
https://w3c.github.io/webcomponents/spec/custom/#dfn-custom-element-constructor-generation

> Conceptually, when I wrote it I'd imagined that the constructor will be 
> called only when you explicitly invoke it (new FooElement...). When parsing 
> or upgrading, the constructor would not be called. The createdCallback will 
> be invoked in either case.

I do not think this makes any sense. All instances of a class can only be 
created through its constructor. createdCallback should be left behind as 
legacy IMO.

--

With all this in mind I do not think "extends" is necessary. I am less sure 
about this though so take what follows with a grain of salt. But anyway, IMO 
you should just look at the inheritance chain for the constructor passed in to 
registerElement.

Also there is a pretty simple hack if you still want extends. Which is that the 
HTML standard should just define that `HTMLInputElement.extends = "input"`. 
Then in Dmitry's

```js
class X extends HTMLInputElement { .. }
X.extends = "input" // additional line.
document.register("x-input", X)
var xinput = new X
```

the need for the additional line disappears since `X.extends === 
HTMLInputElement.extends === "input"`.

(I guess this breaks for classes that have multiple tag names :-/. But it is 
pretty weird that I can't define `class QQ extends HTMLQuoteElement {}` and 
then do both `<q is="x-qq">` and `<blockquote is="x-qq">`. You would think I 
could do both. More reason to dislike `extends`.)

Reply via email to