Re: [w3c/webcomponents] defineElement should not cache lifecycle callbacks and prototype of a custom element class (#417)

I talked with people who work on our JSC engine, and they're all opposed to having this store-at-definition-time behavior.

> I brought this up at TC39 in a couple hallway discussions, and the general consensus was that although late-binding is important for things called by other developers, it's an antipattern for things called by the platform. That is why, for example, subclassing hooks in ES6 are done using late binding, but JSON parsing on the platform doesn't go through `JSON.parse` but instead uses the JSON parsing algorithm directly, and `async`/`await` does not go through `Promise.prototype.then` but uses PromisePerformThen directly, and reading data from an ArrayBuffer does not use the public `.length` property but uses [[ArrayBufferByteLength]] directly.

A better analogy would be something like [`Symbol.species`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/species) which specifies the derived object's type in builtin methods like [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), and these builtin functions lookup `Symbol.species` when `map` not when class was defined.

Storing the callback object at the time of `elements.define` introduces an inconsistent behavior whereby which overriding properties on the prototype is allowed by not reflected in certain cases.

e.g.
```js
class MyElement extends HTMLElement {
    attributeChangedCallback() {
        alert('hi');
    }
}
MyElement.prototype.attributeChangedCallback = function () { alert('(1)'); }
document.elements.define('my-element', MyElement, MyElement.prototype);
var myElement = document.createElement('my-element');
MyElement.prototype.attributeChangedCallback = function () { alert('(2)'); }
Object.defineOwnProperty(myElement, 'attributeChangedCallback', function () { alert('(3)'); });
myElement.setAttribute('class', 'foo');
```
would run `alert('(1)')` because it happened before `elements.define` whereas (2) is ignored as it happens after `elements.define` is called, and `alert('(3)')` is ignored because we never run `[[Get]]` on an instance.

And the whole argument about performance is moot now because we have a mandatory `attributeFilter` which specifies what attributes are observed.  Whether `attributeChangedCallback` is present or not on the prototype doesn't really matter.

---
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/webcomponents/issues/417#issuecomment-205569999

Received on Tuesday, 5 April 2016 01:07:24 UTC