alternate view on constructors for custom elements

OK, after reading Dominic's proposal [1], I'm a little confused. I thought that I understood how constructors should work, but there's some magic going on that I can't follow... I'm sure you folks can help.

```
class CustomElement extends HTMLElement {
   constructor() {
      super();
   }
}

Something magical happens here. The use of super() is supposed to call the constructor of the HTMLElement class-but that's not a normal JS class. It doesn't have a defined constructor() method [yet?]. Also, as has been pointed out, running the CustomElement constructor code _before_ instantiating the actual element (at parse-time for example) opens up a world of potential problems as have been explored:

*        Javascript classes are mutable-what if CustomElement's proto chain is mutated later?

*        What if the constructor throws?
...just to name a few.

I'm trying to rationalize the custom elements previous design with the use of constructors. Basically, I think it should still be a two-stage creation model:

1.      Native [internal] element is created with appropriate tag name, attributes, etc.

2.      JS constructor is called and provided the instance (as 'this')

#1 is triggered by the parser, or by a native constructor function. That constructor function could either be provided separately like it is returned from registerElement today, or in some other way (replacing the original constructor?). Since replacing the original constructor sounds weird and probably violates a bunch of JS invariants, I'll assume sticking with the original model.

This makes it much safer for implementations, since the native custom element can always be safely created first, before running JS code. It also means there's no magic super() at work-which seems to leave too much control up to author code to get right.

Basic example of what I'm thinking:

class XFooStartup extends HTMLElement {
   constructor(val1, val2) {
      this.prop = val1;
      this.prop2 = val2;
   }
}
window.XFoo = document.registerElement('x-foo', XFooStartup);

// (1)
var x1 = new XFooStartup("first", "second");
// (2)
var x2 = new XFoo("first", "second");

Calling (1) does not create a custom element. Extending from HTMLElement is not magical, it's just a prototype inheritance, as can be done today. super() would do whatever super() does when the super class has no defined method to invoke. x1 is a regular JS object with a .prop and .prop2.

Calling (2) runs the platform-provided constructor function which internally inits a new HTMLElement in the C++ (or could be Element if in XML document?). Then the platform immediately (synchronously) invokes the provided constructor function as if:
XFooStartup.apply(newHTMLElementInstance, argsPassedThroughFromCall);
so that XFooStartup's constructor operates on the 'this' being the instance created by the platform.


[1] https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Optional-Upgrades-Optional-Constructors.md

Received on Friday, 17 July 2015 18:03:42 UTC