Monkey patching constructors in builtin class hierarchies?
This feels like a problem similar to esdiscuss.org/topic/block
This feels like a problem similar to https://esdiscuss.org/topic/block-scoped-prototype-extensions > On Oct 24, 2017, at 9:50 AM, /#!/JoePea <joe at trusktr.io> wrote: > > Is it possible to monkey-patch an intermediate constructor of a built-in subclass? > > For example, suppose I want all `Element` instances in a web app to have new instance properties, is there a way to monkey-patch the Element constructor so that when I make a custom element by extending a subclass of `Element` that the new logic will fire? > > For example: > > ```js > // monkey-patch the Element constructor somehow so that it logs "patched in Element". > > // then > class FooBar extends HTMLElement {} > customElement.define('foo-bar', FooBar) > new FooBar // "patched in Element" > ``` > > I tried > > ```js > const OldElement = window.Element > > window.Element = function Element() { > const _this = new OldElement > console.log("patched in Element") > return _this > } > > window.Element.prototype = OldElement.prototype > window.Element.prototype.constructor = window.Element > > class FooBar extends HTMLElement {} > customElements.define('f-b', FooBar) > new FooBar // does not log "patched in Element" > ``` > > But when I make a new custom element, constructing it seems to use the old Element constructor, as if a non-global reference to the original constructor is kept inside a module so that modifying the global wouldn't have any effect. > > Is there a way to monkey patch a constructor in the middle of a built-in prototype chain or to otherwise inject construction logic to base classes of existing class hierarchies? > > > /#!/JoePea -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/ea5da6eb/attachment-0001.html>
if that would be possible, then everyone could just monkey patch Object
,
right?
I'm not sure I'd be up for it
if that would be possible, then everyone could just monkey patch `Object`, right? I'm not sure I'd be up for it On Tue, Oct 24, 2017 at 1:56 PM, Boris Cherny <boris at performancejs.com> wrote: > This feels like a problem similar to https://esdiscuss.org/ > topic/block-scoped-prototype-extensions > > On Oct 24, 2017, at 9:50 AM, /#!/JoePea <joe at trusktr.io> wrote: > > Is it possible to monkey-patch an intermediate constructor of a built-in > subclass? > > For example, suppose I want all `Element` instances in a web app to have > new instance properties, is there a way to monkey-patch the Element > constructor so that when I make a custom element by extending a subclass of > `Element` that the new logic will fire? > > For example: > > ```js > // monkey-patch the Element constructor somehow so that it logs "patched > in Element". > > // then > class FooBar extends HTMLElement {} > customElement.define('foo-bar', FooBar) > new FooBar // "patched in Element" > ``` > > I tried > > ```js > const OldElement = window.Element > > window.Element = function Element() { > const _this = new OldElement > console.log("patched in Element") > return _this > } > > window.Element.prototype = OldElement.prototype > window.Element.prototype.constructor = window.Element > > class FooBar extends HTMLElement {} > customElements.define('f-b', FooBar) > new FooBar // does not log "patched in Element" > ``` > > But when I make a new custom element, constructing it seems to use the old > Element constructor, as if a non-global reference to the original > constructor is kept inside a module so that modifying the global wouldn't > have any effect. > > Is there a way to monkey patch a constructor in the middle of a built-in > prototype chain or to otherwise inject construction logic to base classes > of existing class hierarchies? > > > */#!/*JoePea > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/73880e44/attachment-0001.html>
AFAIR DOM classes are not extensible by any means.
AFAIR DOM classes are not extensible by any means. On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > Is it possible to monkey-patch an intermediate constructor of a built-in > subclass? > > For example, suppose I want all `Element` instances in a web app to have > new instance properties, is there a way to monkey-patch the Element > constructor so that when I make a custom element by extending a subclass of > `Element` that the new logic will fire? > > For example: > > ```js > // monkey-patch the Element constructor somehow so that it logs "patched > in Element". > > // then > class FooBar extends HTMLElement {} > customElement.define('foo-bar', FooBar) > new FooBar // "patched in Element" > ``` > > I tried > > ```js > const OldElement = window.Element > > window.Element = function Element() { > const _this = new OldElement > console.log("patched in Element") > return _this > } > > window.Element.prototype = OldElement.prototype > window.Element.prototype.constructor = window.Element > > class FooBar extends HTMLElement {} > customElements.define('f-b', FooBar) > new FooBar // does not log "patched in Element" > ``` > > But when I make a new custom element, constructing it seems to use the old > Element constructor, as if a non-global reference to the original > constructor is kept inside a module so that modifying the global wouldn't > have any effect. > > Is there a way to monkey patch a constructor in the middle of a built-in > prototype chain or to otherwise inject construction logic to base classes > of existing class hierarchies? > > > */#!/*JoePea > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/dc970fc3/attachment.html>
The problem is that DOM defines the Element
interface without a [Constructor] extended attribute.
This means that Element
can't be directly constructed. However, you can still use something like
class FooBar extends Element {
constructor() {
console.log("patched in Element");
let el = document.createElement('foo-bar');
return Object.setPrototypeOf(el, FooBar.prototype);
}
}
The problem is that DOM defines the [`Element` interface](https://dom.spec.whatwg.org/#element) without a [\[Constructor\] extended attribute](https://heycam.github.io/webidl/#Constructor). This means that `Element` can't be directly constructed. However, you can still use something like ```js class FooBar extends Element { constructor() { console.log("patched in Element"); let el = document.createElement('foo-bar'); return Object.setPrototypeOf(el, FooBar.prototype); } } ``` -Oriol -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/3c77212a/attachment.html>
This feels like a problem similar to esdiscuss.org/topic/block-scoped-prototype-extensions
@Boris, even if it were scoped, how do we monkey patch a
constructor? By the way, for some reason your link to
https://esdiscuss.org/topic/block-scoped-prototype-extensions
posted
as https://esdiscuss.org/topic/block
which is 404. If you can edit
it it would help others not to stumble on a broken link.
if that would be possible, then everyone could just monkey patch Object, right?
But everyone can monkey patch the entire class already, aside from the constructor, by modifying the prototype. Obviously if someone returns something new from the constructor they might break everything, but it will be completely obvious and people then won't do that. The same applies with methods and properties, it is super easy to break entire applications monkey patching methods.
So suppose I want to "polyfill" a concept. For example, I want all
elements to have a new "foo" accessor after they've been constructed.
Or for example, suppose HTMLElement.prototype.style
and
SVGElement.prototype.style
didn't exist yet. How would I patch those
in?
/#!/JoePea
> This feels like a problem similar to https://esdiscuss.org/topic/block-scoped-prototype-extensions @Boris, even if it were scoped, how do we monkey patch a *constructor*? By the way, for some reason your link to `https://esdiscuss.org/topic/block-scoped-prototype-extensions` posted as `https://esdiscuss.org/topic/block` which is 404. If you can edit it it would help others not to stumble on a broken link. > if that would be possible, then everyone could just monkey patch Object, right? But everyone can monkey patch the entire class already, aside from the constructor, by modifying the prototype. Obviously if someone returns something new from the constructor they might break everything, but it will be completely obvious and people then won't do that. The same applies with methods and properties, it is super easy to break entire applications monkey patching methods. --- So suppose I want to "polyfill" a concept. For example, I want all elements to have a new "foo" accessor after they've been constructed. Or for example, suppose `HTMLElement.prototype.style` and `SVGElement.prototype.style` didn't exist yet. How would I patch those in? /#!/JoePea On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> wrote: > AFAIR DOM classes are not extensible by any means. > > > > On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >> >> Is it possible to monkey-patch an intermediate constructor of a built-in >> subclass? >> >> For example, suppose I want all `Element` instances in a web app to have >> new instance properties, is there a way to monkey-patch the Element >> constructor so that when I make a custom element by extending a subclass of >> `Element` that the new logic will fire? >> >> For example: >> >> ```js >> // monkey-patch the Element constructor somehow so that it logs "patched >> in Element". >> >> // then >> class FooBar extends HTMLElement {} >> customElement.define('foo-bar', FooBar) >> new FooBar // "patched in Element" >> ``` >> >> I tried >> >> ```js >> const OldElement = window.Element >> >> window.Element = function Element() { >> const _this = new OldElement >> console.log("patched in Element") >> return _this >> } >> >> window.Element.prototype = OldElement.prototype >> window.Element.prototype.constructor = window.Element >> >> class FooBar extends HTMLElement {} >> customElements.define('f-b', FooBar) >> new FooBar // does not log "patched in Element" >> ``` >> >> But when I make a new custom element, constructing it seems to use the old >> Element constructor, as if a non-global reference to the original >> constructor is kept inside a module so that modifying the global wouldn't >> have any effect. >> >> Is there a way to monkey patch a constructor in the middle of a built-in >> prototype chain or to otherwise inject construction logic to base classes of >> existing class hierarchies? >> >> >> /#!/JoePea >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >
Well, I know I can set accessors on a prototype easily, but what I
mean is, I need each instance of an Element
to have exactly one
instance of something right after construction during the same
synchronous operation.
For example, if we have an application with a bunch of pre-existing
Elements that do not extend from any classes of mine, I'd like for the
all to have foo
properties, so that I can do this:
const el = new SomeCustomElementThatWasDefinedCreatedByMe
console.log(el.foo) // it exists and is specific to the instance, not
a prototype property
// or
const div = document.createElement('div')
console.log(div.foo) // it exists and is specific to the instance, not
a prototype property
Can this be done? /#!/JoePea
Well, I know I can set accessors on a prototype easily, but what I mean is, I need each instance of an `Element` to have exactly one instance of something right after construction during the same synchronous operation. For example, if we have an application with a bunch of pre-existing Elements that do not extend from any classes of mine, I'd like for the all to have `foo` properties, so that I can do this: ```js const el = new SomeCustomElementThatWasDefinedCreatedByMe console.log(el.foo) // it exists and is specific to the instance, not a prototype property // or const div = document.createElement('div') console.log(div.foo) // it exists and is specific to the instance, not a prototype property ``` Can this be done? /#!/JoePea On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: >> This feels like a problem similar to https://esdiscuss.org/topic/block-scoped-prototype-extensions > > @Boris, even if it were scoped, how do we monkey patch a > *constructor*? By the way, for some reason your link to > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` posted > as `https://esdiscuss.org/topic/block` which is 404. If you can edit > it it would help others not to stumble on a broken link. > >> if that would be possible, then everyone could just monkey patch Object, right? > > But everyone can monkey patch the entire class already, aside from the > constructor, by modifying the prototype. Obviously if someone returns > something new from the constructor they might break everything, but it > will be completely obvious and people then won't do that. The same > applies with methods and properties, it is super easy to break entire > applications monkey patching methods. > > --- > > So suppose I want to "polyfill" a concept. For example, I want all > elements to have a new "foo" accessor after they've been constructed. > Or for example, suppose `HTMLElement.prototype.style` and > `SVGElement.prototype.style` didn't exist yet. How would I patch those > in? > /#!/JoePea > > > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> wrote: >> AFAIR DOM classes are not extensible by any means. >> >> >> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >>> >>> Is it possible to monkey-patch an intermediate constructor of a built-in >>> subclass? >>> >>> For example, suppose I want all `Element` instances in a web app to have >>> new instance properties, is there a way to monkey-patch the Element >>> constructor so that when I make a custom element by extending a subclass of >>> `Element` that the new logic will fire? >>> >>> For example: >>> >>> ```js >>> // monkey-patch the Element constructor somehow so that it logs "patched >>> in Element". >>> >>> // then >>> class FooBar extends HTMLElement {} >>> customElement.define('foo-bar', FooBar) >>> new FooBar // "patched in Element" >>> ``` >>> >>> I tried >>> >>> ```js >>> const OldElement = window.Element >>> >>> window.Element = function Element() { >>> const _this = new OldElement >>> console.log("patched in Element") >>> return _this >>> } >>> >>> window.Element.prototype = OldElement.prototype >>> window.Element.prototype.constructor = window.Element >>> >>> class FooBar extends HTMLElement {} >>> customElements.define('f-b', FooBar) >>> new FooBar // does not log "patched in Element" >>> ``` >>> >>> But when I make a new custom element, constructing it seems to use the old >>> Element constructor, as if a non-global reference to the original >>> constructor is kept inside a module so that modifying the global wouldn't >>> have any effect. >>> >>> Is there a way to monkey patch a constructor in the middle of a built-in >>> prototype chain or to otherwise inject construction logic to base classes of >>> existing class hierarchies? >>> >>> >>> /#!/JoePea >>> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>
You can use getters mutating an object for this task.
But why do you need this?
You can use getters mutating an object for this task. But why do you need this? On 24 Oct 2017 7:25 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > Well, I know I can set accessors on a prototype easily, but what I > mean is, I need each instance of an `Element` to have exactly one > instance of something right after construction during the same > synchronous operation. > > For example, if we have an application with a bunch of pre-existing > Elements that do not extend from any classes of mine, I'd like for the > all to have `foo` properties, so that I can do this: > > ```js > const el = new SomeCustomElementThatWasDefinedCreatedByMe > console.log(el.foo) // it exists and is specific to the instance, not > a prototype property > > // or > > const div = document.createElement('div') > console.log(div.foo) // it exists and is specific to the instance, not > a prototype property > ``` > > Can this be done? > /#!/JoePea > > > On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: > >> This feels like a problem similar to https://esdiscuss.org/topic/ > block-scoped-prototype-extensions > > > > @Boris, even if it were scoped, how do we monkey patch a > > *constructor*? By the way, for some reason your link to > > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` posted > > as `https://esdiscuss.org/topic/block` which is 404. If you can edit > > it it would help others not to stumble on a broken link. > > > >> if that would be possible, then everyone could just monkey patch > Object, right? > > > > But everyone can monkey patch the entire class already, aside from the > > constructor, by modifying the prototype. Obviously if someone returns > > something new from the constructor they might break everything, but it > > will be completely obvious and people then won't do that. The same > > applies with methods and properties, it is super easy to break entire > > applications monkey patching methods. > > > > --- > > > > So suppose I want to "polyfill" a concept. For example, I want all > > elements to have a new "foo" accessor after they've been constructed. > > Or for example, suppose `HTMLElement.prototype.style` and > > `SVGElement.prototype.style` didn't exist yet. How would I patch those > > in? > > /#!/JoePea > > > > > > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> > wrote: > >> AFAIR DOM classes are not extensible by any means. > >> > >> > >> > >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > >>> > >>> Is it possible to monkey-patch an intermediate constructor of a > built-in > >>> subclass? > >>> > >>> For example, suppose I want all `Element` instances in a web app to > have > >>> new instance properties, is there a way to monkey-patch the Element > >>> constructor so that when I make a custom element by extending a > subclass of > >>> `Element` that the new logic will fire? > >>> > >>> For example: > >>> > >>> ```js > >>> // monkey-patch the Element constructor somehow so that it logs > "patched > >>> in Element". > >>> > >>> // then > >>> class FooBar extends HTMLElement {} > >>> customElement.define('foo-bar', FooBar) > >>> new FooBar // "patched in Element" > >>> ``` > >>> > >>> I tried > >>> > >>> ```js > >>> const OldElement = window.Element > >>> > >>> window.Element = function Element() { > >>> const _this = new OldElement > >>> console.log("patched in Element") > >>> return _this > >>> } > >>> > >>> window.Element.prototype = OldElement.prototype > >>> window.Element.prototype.constructor = window.Element > >>> > >>> class FooBar extends HTMLElement {} > >>> customElements.define('f-b', FooBar) > >>> new FooBar // does not log "patched in Element" > >>> ``` > >>> > >>> But when I make a new custom element, constructing it seems to use the > old > >>> Element constructor, as if a non-global reference to the original > >>> constructor is kept inside a module so that modifying the global > wouldn't > >>> have any effect. > >>> > >>> Is there a way to monkey patch a constructor in the middle of a > built-in > >>> prototype chain or to otherwise inject construction logic to base > classes of > >>> existing class hierarchies? > >>> > >>> > >>> /#!/JoePea > >>> > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss at mozilla.org > >>> https://mail.mozilla.org/listinfo/es-discuss > >>> > >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/861a49db/attachment-0001.html>
Given that these are constructors that you don't own, adding your own properties to them seems like an overall ugly approach to me. Why not store your data separately in a WeakMap and rather than injecting properties onto existing objects? Then you can initialize the stored data on first access of the data you want.
Given that these are constructors that you don't own, adding your own properties to them seems like an overall ugly approach to me. Why not store your data separately in a WeakMap and rather than injecting properties onto existing objects? Then you can initialize the stored data on first access of the data you want. On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: > Well, I know I can set accessors on a prototype easily, but what I > mean is, I need each instance of an `Element` to have exactly one > instance of something right after construction during the same > synchronous operation. > > For example, if we have an application with a bunch of pre-existing > Elements that do not extend from any classes of mine, I'd like for the > all to have `foo` properties, so that I can do this: > > ```js > const el = new SomeCustomElementThatWasDefinedCreatedByMe > console.log(el.foo) // it exists and is specific to the instance, not > a prototype property > > // or > > const div = document.createElement('div') > console.log(div.foo) // it exists and is specific to the instance, not > a prototype property > ``` > > Can this be done? > /#!/JoePea > > > On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: > >> This feels like a problem similar to https://esdiscuss.org/topic/ > block-scoped-prototype-extensions > > > > @Boris, even if it were scoped, how do we monkey patch a > > *constructor*? By the way, for some reason your link to > > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` posted > > as `https://esdiscuss.org/topic/block` which is 404. If you can edit > > it it would help others not to stumble on a broken link. > > > >> if that would be possible, then everyone could just monkey patch > Object, right? > > > > But everyone can monkey patch the entire class already, aside from the > > constructor, by modifying the prototype. Obviously if someone returns > > something new from the constructor they might break everything, but it > > will be completely obvious and people then won't do that. The same > > applies with methods and properties, it is super easy to break entire > > applications monkey patching methods. > > > > --- > > > > So suppose I want to "polyfill" a concept. For example, I want all > > elements to have a new "foo" accessor after they've been constructed. > > Or for example, suppose `HTMLElement.prototype.style` and > > `SVGElement.prototype.style` didn't exist yet. How would I patch those > > in? > > /#!/JoePea > > > > > > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> > wrote: > >> AFAIR DOM classes are not extensible by any means. > >> > >> > >> > >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > >>> > >>> Is it possible to monkey-patch an intermediate constructor of a > built-in > >>> subclass? > >>> > >>> For example, suppose I want all `Element` instances in a web app to > have > >>> new instance properties, is there a way to monkey-patch the Element > >>> constructor so that when I make a custom element by extending a > subclass of > >>> `Element` that the new logic will fire? > >>> > >>> For example: > >>> > >>> ```js > >>> // monkey-patch the Element constructor somehow so that it logs > "patched > >>> in Element". > >>> > >>> // then > >>> class FooBar extends HTMLElement {} > >>> customElement.define('foo-bar', FooBar) > >>> new FooBar // "patched in Element" > >>> ``` > >>> > >>> I tried > >>> > >>> ```js > >>> const OldElement = window.Element > >>> > >>> window.Element = function Element() { > >>> const _this = new OldElement > >>> console.log("patched in Element") > >>> return _this > >>> } > >>> > >>> window.Element.prototype = OldElement.prototype > >>> window.Element.prototype.constructor = window.Element > >>> > >>> class FooBar extends HTMLElement {} > >>> customElements.define('f-b', FooBar) > >>> new FooBar // does not log "patched in Element" > >>> ``` > >>> > >>> But when I make a new custom element, constructing it seems to use the > old > >>> Element constructor, as if a non-global reference to the original > >>> constructor is kept inside a module so that modifying the global > wouldn't > >>> have any effect. > >>> > >>> Is there a way to monkey patch a constructor in the middle of a > built-in > >>> prototype chain or to otherwise inject construction logic to base > classes of > >>> existing class hierarchies? > >>> > >>> > >>> /#!/JoePea > >>> > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss at mozilla.org > >>> https://mail.mozilla.org/listinfo/es-discuss > >>> > >> > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/ee5c09b1/attachment.html>
I know I'm going to regret this already, but since I've secretly played with polyfills, you can still do this:
window.HTMLElement = class extends HTMLElement {
constructor() {
super();
console.log('hello darkness my old friend');
}
};
// then ...
class MyEl extends HTMLElement {}
customElements.define('my-el', MyEl);
new MyEl;
I know I'm going to regret this already, but since I've secretly played with polyfills, you can still do this: ```js window.HTMLElement = class extends HTMLElement { constructor() { super(); console.log('hello darkness my old friend'); } }; // then ... class MyEl extends HTMLElement {} customElements.define('my-el', MyEl); new MyEl; ``` Regards On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> wrote: > Given that these are constructors that you don't own, adding your own > properties to them seems like an overall ugly approach to me. Why not store > your data separately in a WeakMap and rather than injecting properties onto > existing objects? Then you can initialize the stored data on first access > of the data you want. > > On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: > >> Well, I know I can set accessors on a prototype easily, but what I >> mean is, I need each instance of an `Element` to have exactly one >> instance of something right after construction during the same >> synchronous operation. >> >> For example, if we have an application with a bunch of pre-existing >> Elements that do not extend from any classes of mine, I'd like for the >> all to have `foo` properties, so that I can do this: >> >> ```js >> const el = new SomeCustomElementThatWasDefinedCreatedByMe >> console.log(el.foo) // it exists and is specific to the instance, not >> a prototype property >> >> // or >> >> const div = document.createElement('div') >> console.log(div.foo) // it exists and is specific to the instance, not >> a prototype property >> ``` >> >> Can this be done? >> /#!/JoePea >> >> >> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: >> >> This feels like a problem similar to https://esdiscuss.org/topic/bl >> ock-scoped-prototype-extensions >> > >> > @Boris, even if it were scoped, how do we monkey patch a >> > *constructor*? By the way, for some reason your link to >> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` >> <https://esdiscuss.org/topic/block-scoped-prototype-extensions> posted >> > as `https://esdiscuss.org/topic/block` >> <https://esdiscuss.org/topic/block> which is 404. If you can edit >> > it it would help others not to stumble on a broken link. >> > >> >> if that would be possible, then everyone could just monkey patch >> Object, right? >> > >> > But everyone can monkey patch the entire class already, aside from the >> > constructor, by modifying the prototype. Obviously if someone returns >> > something new from the constructor they might break everything, but it >> > will be completely obvious and people then won't do that. The same >> > applies with methods and properties, it is super easy to break entire >> > applications monkey patching methods. >> > >> > --- >> > >> > So suppose I want to "polyfill" a concept. For example, I want all >> > elements to have a new "foo" accessor after they've been constructed. >> > Or for example, suppose `HTMLElement.prototype.style` and >> > `SVGElement.prototype.style` didn't exist yet. How would I patch those >> > in? >> > /#!/JoePea >> > >> > >> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> >> wrote: >> >> AFAIR DOM classes are not extensible by any means. >> >> >> >> >> >> >> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >> >>> >> >>> Is it possible to monkey-patch an intermediate constructor of a >> built-in >> >>> subclass? >> >>> >> >>> For example, suppose I want all `Element` instances in a web app to >> have >> >>> new instance properties, is there a way to monkey-patch the Element >> >>> constructor so that when I make a custom element by extending a >> subclass of >> >>> `Element` that the new logic will fire? >> >>> >> >>> For example: >> >>> >> >>> ```js >> >>> // monkey-patch the Element constructor somehow so that it logs >> "patched >> >>> in Element". >> >>> >> >>> // then >> >>> class FooBar extends HTMLElement {} >> >>> customElement.define('foo-bar', FooBar) >> >>> new FooBar // "patched in Element" >> >>> ``` >> >>> >> >>> I tried >> >>> >> >>> ```js >> >>> const OldElement = window.Element >> >>> >> >>> window.Element = function Element() { >> >>> const _this = new OldElement >> >>> console.log("patched in Element") >> >>> return _this >> >>> } >> >>> >> >>> window.Element.prototype = OldElement.prototype >> >>> window.Element.prototype.constructor = window.Element >> >>> >> >>> class FooBar extends HTMLElement {} >> >>> customElements.define('f-b', FooBar) >> >>> new FooBar // does not log "patched in Element" >> >>> ``` >> >>> >> >>> But when I make a new custom element, constructing it seems to use >> the old >> >>> Element constructor, as if a non-global reference to the original >> >>> constructor is kept inside a module so that modifying the global >> wouldn't >> >>> have any effect. >> >>> >> >>> Is there a way to monkey patch a constructor in the middle of a >> built-in >> >>> prototype chain or to otherwise inject construction logic to base >> classes of >> >>> existing class hierarchies? >> >>> >> >>> >> >>> /#!/JoePea >> >>> >> >>> _______________________________________________ >> >>> es-discuss mailing list >> >>> es-discuss at mozilla.org >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >>> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/38a2deb6/attachment.html>
@Michał
But why do you need this?
To "polyfill" an idea I have for DOM, to propose it later, etc.
@Logan
Why not store your data separately in a WeakMap and rather than injecting properties onto existing objects? Then you can initialize the stored data on first access of the data you want.
I thought about that, it seems like the only way, but was curious to see about the the during-construction way if possible.
@Andrea
But this one doesn't work:
window.Element = class extends Element {
constructor() {
super();
console.log('hello darkness my old friend');
}
};
// then ...
class MyEl extends HTMLElement {}
customElements.define('my-el', MyEl);
new MyEl;
/#!/JoePea
@Michał > But why do you need this? To "polyfill" an idea I have for DOM, to propose it later, etc. @Logan > Why not store your data separately in a WeakMap and rather than injecting properties onto existing objects? Then you can initialize the stored data on first access of the data you want. I thought about that, it seems like the only way, but was curious to see about the the during-construction way if possible. @Andrea But this one doesn't work: ```js window.Element = class extends Element { constructor() { super(); console.log('hello darkness my old friend'); } }; // then ... class MyEl extends HTMLElement {} customElements.define('my-el', MyEl); new MyEl; ``` /#!/JoePea On Tue, Oct 24, 2017 at 10:36 AM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote: > I know I'm going to regret this already, but since I've secretly played with > polyfills, you can still do this: > > ```js > window.HTMLElement = class extends HTMLElement { > constructor() { > super(); > console.log('hello darkness my old friend'); > } > }; > > // then ... > class MyEl extends HTMLElement {} > customElements.define('my-el', MyEl); > > new MyEl; > ``` > > Regards > > > > On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> wrote: >> >> Given that these are constructors that you don't own, adding your own >> properties to them seems like an overall ugly approach to me. Why not store >> your data separately in a WeakMap and rather than injecting properties onto >> existing objects? Then you can initialize the stored data on first access of >> the data you want. >> >> On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: >>> >>> Well, I know I can set accessors on a prototype easily, but what I >>> mean is, I need each instance of an `Element` to have exactly one >>> instance of something right after construction during the same >>> synchronous operation. >>> >>> For example, if we have an application with a bunch of pre-existing >>> Elements that do not extend from any classes of mine, I'd like for the >>> all to have `foo` properties, so that I can do this: >>> >>> ```js >>> const el = new SomeCustomElementThatWasDefinedCreatedByMe >>> console.log(el.foo) // it exists and is specific to the instance, not >>> a prototype property >>> >>> // or >>> >>> const div = document.createElement('div') >>> console.log(div.foo) // it exists and is specific to the instance, not >>> a prototype property >>> ``` >>> >>> Can this be done? >>> /#!/JoePea >>> >>> >>> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: >>> >> This feels like a problem similar to >>> >> https://esdiscuss.org/topic/block-scoped-prototype-extensions >>> > >>> > @Boris, even if it were scoped, how do we monkey patch a >>> > *constructor*? By the way, for some reason your link to >>> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` posted >>> > as `https://esdiscuss.org/topic/block` which is 404. If you can edit >>> > it it would help others not to stumble on a broken link. >>> > >>> >> if that would be possible, then everyone could just monkey patch >>> >> Object, right? >>> > >>> > But everyone can monkey patch the entire class already, aside from the >>> > constructor, by modifying the prototype. Obviously if someone returns >>> > something new from the constructor they might break everything, but it >>> > will be completely obvious and people then won't do that. The same >>> > applies with methods and properties, it is super easy to break entire >>> > applications monkey patching methods. >>> > >>> > --- >>> > >>> > So suppose I want to "polyfill" a concept. For example, I want all >>> > elements to have a new "foo" accessor after they've been constructed. >>> > Or for example, suppose `HTMLElement.prototype.style` and >>> > `SVGElement.prototype.style` didn't exist yet. How would I patch those >>> > in? >>> > /#!/JoePea >>> > >>> > >>> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas <michalwadas at gmail.com> >>> > wrote: >>> >> AFAIR DOM classes are not extensible by any means. >>> >> >>> >> >>> >> >>> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >>> >>> >>> >>> Is it possible to monkey-patch an intermediate constructor of a >>> >>> built-in >>> >>> subclass? >>> >>> >>> >>> For example, suppose I want all `Element` instances in a web app to >>> >>> have >>> >>> new instance properties, is there a way to monkey-patch the Element >>> >>> constructor so that when I make a custom element by extending a >>> >>> subclass of >>> >>> `Element` that the new logic will fire? >>> >>> >>> >>> For example: >>> >>> >>> >>> ```js >>> >>> // monkey-patch the Element constructor somehow so that it logs >>> >>> "patched >>> >>> in Element". >>> >>> >>> >>> // then >>> >>> class FooBar extends HTMLElement {} >>> >>> customElement.define('foo-bar', FooBar) >>> >>> new FooBar // "patched in Element" >>> >>> ``` >>> >>> >>> >>> I tried >>> >>> >>> >>> ```js >>> >>> const OldElement = window.Element >>> >>> >>> >>> window.Element = function Element() { >>> >>> const _this = new OldElement >>> >>> console.log("patched in Element") >>> >>> return _this >>> >>> } >>> >>> >>> >>> window.Element.prototype = OldElement.prototype >>> >>> window.Element.prototype.constructor = window.Element >>> >>> >>> >>> class FooBar extends HTMLElement {} >>> >>> customElements.define('f-b', FooBar) >>> >>> new FooBar // does not log "patched in Element" >>> >>> ``` >>> >>> >>> >>> But when I make a new custom element, constructing it seems to use >>> >>> the old >>> >>> Element constructor, as if a non-global reference to the original >>> >>> constructor is kept inside a module so that modifying the global >>> >>> wouldn't >>> >>> have any effect. >>> >>> >>> >>> Is there a way to monkey patch a constructor in the middle of a >>> >>> built-in >>> >>> prototype chain or to otherwise inject construction logic to base >>> >>> classes of >>> >>> existing class hierarchies? >>> >>> >>> >>> >>> >>> /#!/JoePea >>> >>> >>> >>> _______________________________________________ >>> >>> es-discuss mailing list >>> >>> es-discuss at mozilla.org >>> >>> https://mail.mozilla.org/listinfo/es-discuss >>> >>> >>> >> >>> _______________________________________________ >>> es-discuss mailing list >>> es-discuss at mozilla.org >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >
On 10/24/17 12:50 PM, /#!/JoePea wrote:
Is it possible to monkey-patch an intermediate constructor of a built-in subclass?
Right now, no.
For example, suppose I want all
Element
instances in a web app to have new instance properties, is there a way to monkey-patch the Element constructor so that when I make a custom element by extending a subclass ofElement
that the new logic will fire?
If you want to limit this to custom elements you control, in the sense of html.spec.whatwg.org/multipage/custom-elements.html, then "sort of, yes". You could just define a class that extends HTMLElement, have its constructor do whatever instance-property-setting you want, and have all your actual custom element classes extend that one class.
If you want to do this to custom elements you do NOT control, you can sort of do it too, using Andrea's suggestion later in this thread: as long as your code runs first, you can set your class as window.HTMLElement so everyone else is extending you, not the "real" HTMLElement.
const OldElement = window.Element
This won't work, because Element is not constructible, so all the constructor behavior lives in HTMLElement. But if you did this with HTMLElement, I would expect it would work, as in Andrea's suggestion.
Is there a way to monkey patch a constructor in the middle of a built-in prototype chain or to otherwise inject construction logic to base classes of existing class hierarchies?
Right now, no.
On 10/24/17 12:50 PM, /#!/JoePea wrote: > Is it possible to monkey-patch an intermediate constructor of a built-in > subclass? Right now, no. > For example, suppose I want all `Element` instances in a web app to have > new instance properties, is there a way to monkey-patch the Element > constructor so that when I make a custom element by extending a subclass > of `Element` that the new logic will fire? If you want to limit this to custom elements you control, in the sense of <https://html.spec.whatwg.org/multipage/custom-elements.html>, then "sort of, yes". You could just define a class that extends HTMLElement, have its constructor do whatever instance-property-setting you want, and have all your actual custom element classes extend that one class. If you want to do this to custom elements you do NOT control, you can sort of do it too, using Andrea's suggestion later in this thread: as long as your code runs first, you can set your class as window.HTMLElement so everyone else is extending you, not the "real" HTMLElement. > const OldElement = window.Element This won't work, because Element is not constructible, so all the constructor behavior lives in HTMLElement. But if you did this with HTMLElement, I would expect it would work, as in Andrea's suggestion. > Is there a way to monkey patch a constructor in the middle of a built-in > prototype chain or to otherwise inject construction logic to base > classes of existing class hierarchies? Right now, no. -Boris
To "polyfill" an idea I have for DOM, to propose it later, etc.
You can consider something like this depending on your needs: gist.github.com/Ginden/03004e52b3d331e236b5256e3b4c08ff
> To "polyfill" an idea I have for DOM, to propose it later, etc. You can consider something like this depending on your needs: https://gist.github.com/Ginden/03004e52b3d331e236b5256e3b4c08ff On Tue, Oct 24, 2017 at 7:47 PM, /#!/JoePea <joe at trusktr.io> wrote: > @Michał > > > But why do you need this? > > To "polyfill" an idea I have for DOM, to propose it later, etc. > > @Logan > > > Why not store your data separately in a WeakMap and rather than > injecting properties onto existing objects? Then you can initialize the > stored data on first access of the data you want. > > I thought about that, it seems like the only way, but was curious to > see about the the during-construction way if possible. > > @Andrea > > But this one doesn't work: > > ```js > window.Element = class extends Element { > constructor() { > super(); > console.log('hello darkness my old friend'); > } > }; > > // then ... > class MyEl extends HTMLElement {} > customElements.define('my-el', MyEl); > > new MyEl; > ``` > > /#!/JoePea > > > On Tue, Oct 24, 2017 at 10:36 AM, Andrea Giammarchi > <andrea.giammarchi at gmail.com> wrote: > > I know I'm going to regret this already, but since I've secretly played > with > > polyfills, you can still do this: > > > > ```js > > window.HTMLElement = class extends HTMLElement { > > constructor() { > > super(); > > console.log('hello darkness my old friend'); > > } > > }; > > > > // then ... > > class MyEl extends HTMLElement {} > > customElements.define('my-el', MyEl); > > > > new MyEl; > > ``` > > > > Regards > > > > > > > > On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> > wrote: > >> > >> Given that these are constructors that you don't own, adding your own > >> properties to them seems like an overall ugly approach to me. Why not > store > >> your data separately in a WeakMap and rather than injecting properties > onto > >> existing objects? Then you can initialize the stored data on first > access of > >> the data you want. > >> > >> On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: > >>> > >>> Well, I know I can set accessors on a prototype easily, but what I > >>> mean is, I need each instance of an `Element` to have exactly one > >>> instance of something right after construction during the same > >>> synchronous operation. > >>> > >>> For example, if we have an application with a bunch of pre-existing > >>> Elements that do not extend from any classes of mine, I'd like for the > >>> all to have `foo` properties, so that I can do this: > >>> > >>> ```js > >>> const el = new SomeCustomElementThatWasDefinedCreatedByMe > >>> console.log(el.foo) // it exists and is specific to the instance, not > >>> a prototype property > >>> > >>> // or > >>> > >>> const div = document.createElement('div') > >>> console.log(div.foo) // it exists and is specific to the instance, not > >>> a prototype property > >>> ``` > >>> > >>> Can this be done? > >>> /#!/JoePea > >>> > >>> > >>> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: > >>> >> This feels like a problem similar to > >>> >> https://esdiscuss.org/topic/block-scoped-prototype-extensions > >>> > > >>> > @Boris, even if it were scoped, how do we monkey patch a > >>> > *constructor*? By the way, for some reason your link to > >>> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` > posted > >>> > as `https://esdiscuss.org/topic/block` which is 404. If you can edit > >>> > it it would help others not to stumble on a broken link. > >>> > > >>> >> if that would be possible, then everyone could just monkey patch > >>> >> Object, right? > >>> > > >>> > But everyone can monkey patch the entire class already, aside from > the > >>> > constructor, by modifying the prototype. Obviously if someone returns > >>> > something new from the constructor they might break everything, but > it > >>> > will be completely obvious and people then won't do that. The same > >>> > applies with methods and properties, it is super easy to break entire > >>> > applications monkey patching methods. > >>> > > >>> > --- > >>> > > >>> > So suppose I want to "polyfill" a concept. For example, I want all > >>> > elements to have a new "foo" accessor after they've been constructed. > >>> > Or for example, suppose `HTMLElement.prototype.style` and > >>> > `SVGElement.prototype.style` didn't exist yet. How would I patch > those > >>> > in? > >>> > /#!/JoePea > >>> > > >>> > > >>> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas < > michalwadas at gmail.com> > >>> > wrote: > >>> >> AFAIR DOM classes are not extensible by any means. > >>> >> > >>> >> > >>> >> > >>> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > >>> >>> > >>> >>> Is it possible to monkey-patch an intermediate constructor of a > >>> >>> built-in > >>> >>> subclass? > >>> >>> > >>> >>> For example, suppose I want all `Element` instances in a web app to > >>> >>> have > >>> >>> new instance properties, is there a way to monkey-patch the Element > >>> >>> constructor so that when I make a custom element by extending a > >>> >>> subclass of > >>> >>> `Element` that the new logic will fire? > >>> >>> > >>> >>> For example: > >>> >>> > >>> >>> ```js > >>> >>> // monkey-patch the Element constructor somehow so that it logs > >>> >>> "patched > >>> >>> in Element". > >>> >>> > >>> >>> // then > >>> >>> class FooBar extends HTMLElement {} > >>> >>> customElement.define('foo-bar', FooBar) > >>> >>> new FooBar // "patched in Element" > >>> >>> ``` > >>> >>> > >>> >>> I tried > >>> >>> > >>> >>> ```js > >>> >>> const OldElement = window.Element > >>> >>> > >>> >>> window.Element = function Element() { > >>> >>> const _this = new OldElement > >>> >>> console.log("patched in Element") > >>> >>> return _this > >>> >>> } > >>> >>> > >>> >>> window.Element.prototype = OldElement.prototype > >>> >>> window.Element.prototype.constructor = window.Element > >>> >>> > >>> >>> class FooBar extends HTMLElement {} > >>> >>> customElements.define('f-b', FooBar) > >>> >>> new FooBar // does not log "patched in Element" > >>> >>> ``` > >>> >>> > >>> >>> But when I make a new custom element, constructing it seems to use > >>> >>> the old > >>> >>> Element constructor, as if a non-global reference to the original > >>> >>> constructor is kept inside a module so that modifying the global > >>> >>> wouldn't > >>> >>> have any effect. > >>> >>> > >>> >>> Is there a way to monkey patch a constructor in the middle of a > >>> >>> built-in > >>> >>> prototype chain or to otherwise inject construction logic to base > >>> >>> classes of > >>> >>> existing class hierarchies? > >>> >>> > >>> >>> > >>> >>> /#!/JoePea > >>> >>> > >>> >>> _______________________________________________ > >>> >>> es-discuss mailing list > >>> >>> es-discuss at mozilla.org > >>> >>> https://mail.mozilla.org/listinfo/es-discuss > >>> >>> > >>> >> > >>> _______________________________________________ > >>> es-discuss mailing list > >>> es-discuss at mozilla.org > >>> https://mail.mozilla.org/listinfo/es-discuss > >> > >> > >> > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > >> > > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/581eb90f/attachment.html>
I'm going to use the accessor technique as it's the only way. Thanks!
I was trying to patch Element
because there's also SVGElement
. I
suppose I can duplicate efforts and patch both HTMLElement
and
SVGElement
; that's not too difficult, but it is conceptually uglier
because for example, what if browsers come out with MathElement
,
WebGLElement
, etc.
/#!/JoePea
I'm going to use the accessor technique as it's the only way. Thanks! I was trying to patch `Element` because there's also `SVGElement`. I suppose I can duplicate efforts and patch both `HTMLElement` and `SVGElement`; that's not too difficult, but it is conceptually uglier because for example, what if browsers come out with `MathElement`, `WebGLElement`, etc. /#!/JoePea On Tue, Oct 24, 2017 at 10:55 AM, Michał Wadas <michalwadas at gmail.com> wrote: >> To "polyfill" an idea I have for DOM, to propose it later, etc. > > You can consider something like this depending on your needs: > https://gist.github.com/Ginden/03004e52b3d331e236b5256e3b4c08ff > > On Tue, Oct 24, 2017 at 7:47 PM, /#!/JoePea <joe at trusktr.io> wrote: >> >> @Michał >> >> > But why do you need this? >> >> To "polyfill" an idea I have for DOM, to propose it later, etc. >> >> @Logan >> >> > Why not store your data separately in a WeakMap and rather than >> > injecting properties onto existing objects? Then you can initialize the >> > stored data on first access of the data you want. >> >> I thought about that, it seems like the only way, but was curious to >> see about the the during-construction way if possible. >> >> @Andrea >> >> But this one doesn't work: >> >> ```js >> window.Element = class extends Element { >> constructor() { >> super(); >> console.log('hello darkness my old friend'); >> } >> }; >> >> // then ... >> class MyEl extends HTMLElement {} >> customElements.define('my-el', MyEl); >> >> new MyEl; >> ``` >> >> /#!/JoePea >> >> >> On Tue, Oct 24, 2017 at 10:36 AM, Andrea Giammarchi >> <andrea.giammarchi at gmail.com> wrote: >> > I know I'm going to regret this already, but since I've secretly played >> > with >> > polyfills, you can still do this: >> > >> > ```js >> > window.HTMLElement = class extends HTMLElement { >> > constructor() { >> > super(); >> > console.log('hello darkness my old friend'); >> > } >> > }; >> > >> > // then ... >> > class MyEl extends HTMLElement {} >> > customElements.define('my-el', MyEl); >> > >> > new MyEl; >> > ``` >> > >> > Regards >> > >> > >> > >> > On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> >> > wrote: >> >> >> >> Given that these are constructors that you don't own, adding your own >> >> properties to them seems like an overall ugly approach to me. Why not >> >> store >> >> your data separately in a WeakMap and rather than injecting properties >> >> onto >> >> existing objects? Then you can initialize the stored data on first >> >> access of >> >> the data you want. >> >> >> >> On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: >> >>> >> >>> Well, I know I can set accessors on a prototype easily, but what I >> >>> mean is, I need each instance of an `Element` to have exactly one >> >>> instance of something right after construction during the same >> >>> synchronous operation. >> >>> >> >>> For example, if we have an application with a bunch of pre-existing >> >>> Elements that do not extend from any classes of mine, I'd like for the >> >>> all to have `foo` properties, so that I can do this: >> >>> >> >>> ```js >> >>> const el = new SomeCustomElementThatWasDefinedCreatedByMe >> >>> console.log(el.foo) // it exists and is specific to the instance, not >> >>> a prototype property >> >>> >> >>> // or >> >>> >> >>> const div = document.createElement('div') >> >>> console.log(div.foo) // it exists and is specific to the instance, not >> >>> a prototype property >> >>> ``` >> >>> >> >>> Can this be done? >> >>> /#!/JoePea >> >>> >> >>> >> >>> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> wrote: >> >>> >> This feels like a problem similar to >> >>> >> https://esdiscuss.org/topic/block-scoped-prototype-extensions >> >>> > >> >>> > @Boris, even if it were scoped, how do we monkey patch a >> >>> > *constructor*? By the way, for some reason your link to >> >>> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` >> >>> > posted >> >>> > as `https://esdiscuss.org/topic/block` which is 404. If you can edit >> >>> > it it would help others not to stumble on a broken link. >> >>> > >> >>> >> if that would be possible, then everyone could just monkey patch >> >>> >> Object, right? >> >>> > >> >>> > But everyone can monkey patch the entire class already, aside from >> >>> > the >> >>> > constructor, by modifying the prototype. Obviously if someone >> >>> > returns >> >>> > something new from the constructor they might break everything, but >> >>> > it >> >>> > will be completely obvious and people then won't do that. The same >> >>> > applies with methods and properties, it is super easy to break >> >>> > entire >> >>> > applications monkey patching methods. >> >>> > >> >>> > --- >> >>> > >> >>> > So suppose I want to "polyfill" a concept. For example, I want all >> >>> > elements to have a new "foo" accessor after they've been >> >>> > constructed. >> >>> > Or for example, suppose `HTMLElement.prototype.style` and >> >>> > `SVGElement.prototype.style` didn't exist yet. How would I patch >> >>> > those >> >>> > in? >> >>> > /#!/JoePea >> >>> > >> >>> > >> >>> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas >> >>> > <michalwadas at gmail.com> >> >>> > wrote: >> >>> >> AFAIR DOM classes are not extensible by any means. >> >>> >> >> >>> >> >> >>> >> >> >>> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >> >>> >>> >> >>> >>> Is it possible to monkey-patch an intermediate constructor of a >> >>> >>> built-in >> >>> >>> subclass? >> >>> >>> >> >>> >>> For example, suppose I want all `Element` instances in a web app >> >>> >>> to >> >>> >>> have >> >>> >>> new instance properties, is there a way to monkey-patch the >> >>> >>> Element >> >>> >>> constructor so that when I make a custom element by extending a >> >>> >>> subclass of >> >>> >>> `Element` that the new logic will fire? >> >>> >>> >> >>> >>> For example: >> >>> >>> >> >>> >>> ```js >> >>> >>> // monkey-patch the Element constructor somehow so that it logs >> >>> >>> "patched >> >>> >>> in Element". >> >>> >>> >> >>> >>> // then >> >>> >>> class FooBar extends HTMLElement {} >> >>> >>> customElement.define('foo-bar', FooBar) >> >>> >>> new FooBar // "patched in Element" >> >>> >>> ``` >> >>> >>> >> >>> >>> I tried >> >>> >>> >> >>> >>> ```js >> >>> >>> const OldElement = window.Element >> >>> >>> >> >>> >>> window.Element = function Element() { >> >>> >>> const _this = new OldElement >> >>> >>> console.log("patched in Element") >> >>> >>> return _this >> >>> >>> } >> >>> >>> >> >>> >>> window.Element.prototype = OldElement.prototype >> >>> >>> window.Element.prototype.constructor = window.Element >> >>> >>> >> >>> >>> class FooBar extends HTMLElement {} >> >>> >>> customElements.define('f-b', FooBar) >> >>> >>> new FooBar // does not log "patched in Element" >> >>> >>> ``` >> >>> >>> >> >>> >>> But when I make a new custom element, constructing it seems to use >> >>> >>> the old >> >>> >>> Element constructor, as if a non-global reference to the original >> >>> >>> constructor is kept inside a module so that modifying the global >> >>> >>> wouldn't >> >>> >>> have any effect. >> >>> >>> >> >>> >>> Is there a way to monkey patch a constructor in the middle of a >> >>> >>> built-in >> >>> >>> prototype chain or to otherwise inject construction logic to base >> >>> >>> classes of >> >>> >>> existing class hierarchies? >> >>> >>> >> >>> >>> >> >>> >>> /#!/JoePea >> >>> >>> >> >>> >>> _______________________________________________ >> >>> >>> es-discuss mailing list >> >>> >>> es-discuss at mozilla.org >> >>> >>> https://mail.mozilla.org/listinfo/es-discuss >> >>> >>> >> >>> >> >> >>> _______________________________________________ >> >>> es-discuss mailing list >> >>> es-discuss at mozilla.org >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >> >> >> >> _______________________________________________ >> >> es-discuss mailing list >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> > >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss > >
are you patching things you know need patching or you want to pollute forever the future with your patch? Whatever you are doing should not compromise WebGLElement so it's good you are unable to patch Element, IMO
are you patching things you know need patching or you want to pollute forever the future with your patch? Whatever you are doing should not compromise WebGLElement so it's good you are unable to patch Element, IMO On Tue, Oct 24, 2017 at 3:03 PM, /#!/JoePea <joe at trusktr.io> wrote: > I'm going to use the accessor technique as it's the only way. Thanks! > > I was trying to patch `Element` because there's also `SVGElement`. I > suppose I can duplicate efforts and patch both `HTMLElement` and > `SVGElement`; that's not too difficult, but it is conceptually uglier > because for example, what if browsers come out with `MathElement`, > `WebGLElement`, etc. > /#!/JoePea > > > On Tue, Oct 24, 2017 at 10:55 AM, Michał Wadas <michalwadas at gmail.com> > wrote: > >> To "polyfill" an idea I have for DOM, to propose it later, etc. > > > > You can consider something like this depending on your needs: > > https://gist.github.com/Ginden/03004e52b3d331e236b5256e3b4c08ff > > > > On Tue, Oct 24, 2017 at 7:47 PM, /#!/JoePea <joe at trusktr.io> wrote: > >> > >> @Michał > >> > >> > But why do you need this? > >> > >> To "polyfill" an idea I have for DOM, to propose it later, etc. > >> > >> @Logan > >> > >> > Why not store your data separately in a WeakMap and rather than > >> > injecting properties onto existing objects? Then you can initialize > the > >> > stored data on first access of the data you want. > >> > >> I thought about that, it seems like the only way, but was curious to > >> see about the the during-construction way if possible. > >> > >> @Andrea > >> > >> But this one doesn't work: > >> > >> ```js > >> window.Element = class extends Element { > >> constructor() { > >> super(); > >> console.log('hello darkness my old friend'); > >> } > >> }; > >> > >> // then ... > >> class MyEl extends HTMLElement {} > >> customElements.define('my-el', MyEl); > >> > >> new MyEl; > >> ``` > >> > >> /#!/JoePea > >> > >> > >> On Tue, Oct 24, 2017 at 10:36 AM, Andrea Giammarchi > >> <andrea.giammarchi at gmail.com> wrote: > >> > I know I'm going to regret this already, but since I've secretly > played > >> > with > >> > polyfills, you can still do this: > >> > > >> > ```js > >> > window.HTMLElement = class extends HTMLElement { > >> > constructor() { > >> > super(); > >> > console.log('hello darkness my old friend'); > >> > } > >> > }; > >> > > >> > // then ... > >> > class MyEl extends HTMLElement {} > >> > customElements.define('my-el', MyEl); > >> > > >> > new MyEl; > >> > ``` > >> > > >> > Regards > >> > > >> > > >> > > >> > On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> > >> > wrote: > >> >> > >> >> Given that these are constructors that you don't own, adding your own > >> >> properties to them seems like an overall ugly approach to me. Why not > >> >> store > >> >> your data separately in a WeakMap and rather than injecting > properties > >> >> onto > >> >> existing objects? Then you can initialize the stored data on first > >> >> access of > >> >> the data you want. > >> >> > >> >> On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: > >> >>> > >> >>> Well, I know I can set accessors on a prototype easily, but what I > >> >>> mean is, I need each instance of an `Element` to have exactly one > >> >>> instance of something right after construction during the same > >> >>> synchronous operation. > >> >>> > >> >>> For example, if we have an application with a bunch of pre-existing > >> >>> Elements that do not extend from any classes of mine, I'd like for > the > >> >>> all to have `foo` properties, so that I can do this: > >> >>> > >> >>> ```js > >> >>> const el = new SomeCustomElementThatWasDefinedCreatedByMe > >> >>> console.log(el.foo) // it exists and is specific to the instance, > not > >> >>> a prototype property > >> >>> > >> >>> // or > >> >>> > >> >>> const div = document.createElement('div') > >> >>> console.log(div.foo) // it exists and is specific to the instance, > not > >> >>> a prototype property > >> >>> ``` > >> >>> > >> >>> Can this be done? > >> >>> /#!/JoePea > >> >>> > >> >>> > >> >>> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> > wrote: > >> >>> >> This feels like a problem similar to > >> >>> >> https://esdiscuss.org/topic/block-scoped-prototype-extensions > >> >>> > > >> >>> > @Boris, even if it were scoped, how do we monkey patch a > >> >>> > *constructor*? By the way, for some reason your link to > >> >>> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` > >> >>> > posted > >> >>> > as `https://esdiscuss.org/topic/block` which is 404. If you can > edit > >> >>> > it it would help others not to stumble on a broken link. > >> >>> > > >> >>> >> if that would be possible, then everyone could just monkey patch > >> >>> >> Object, right? > >> >>> > > >> >>> > But everyone can monkey patch the entire class already, aside from > >> >>> > the > >> >>> > constructor, by modifying the prototype. Obviously if someone > >> >>> > returns > >> >>> > something new from the constructor they might break everything, > but > >> >>> > it > >> >>> > will be completely obvious and people then won't do that. The same > >> >>> > applies with methods and properties, it is super easy to break > >> >>> > entire > >> >>> > applications monkey patching methods. > >> >>> > > >> >>> > --- > >> >>> > > >> >>> > So suppose I want to "polyfill" a concept. For example, I want all > >> >>> > elements to have a new "foo" accessor after they've been > >> >>> > constructed. > >> >>> > Or for example, suppose `HTMLElement.prototype.style` and > >> >>> > `SVGElement.prototype.style` didn't exist yet. How would I patch > >> >>> > those > >> >>> > in? > >> >>> > /#!/JoePea > >> >>> > > >> >>> > > >> >>> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas > >> >>> > <michalwadas at gmail.com> > >> >>> > wrote: > >> >>> >> AFAIR DOM classes are not extensible by any means. > >> >>> >> > >> >>> >> > >> >>> >> > >> >>> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: > >> >>> >>> > >> >>> >>> Is it possible to monkey-patch an intermediate constructor of a > >> >>> >>> built-in > >> >>> >>> subclass? > >> >>> >>> > >> >>> >>> For example, suppose I want all `Element` instances in a web app > >> >>> >>> to > >> >>> >>> have > >> >>> >>> new instance properties, is there a way to monkey-patch the > >> >>> >>> Element > >> >>> >>> constructor so that when I make a custom element by extending a > >> >>> >>> subclass of > >> >>> >>> `Element` that the new logic will fire? > >> >>> >>> > >> >>> >>> For example: > >> >>> >>> > >> >>> >>> ```js > >> >>> >>> // monkey-patch the Element constructor somehow so that it logs > >> >>> >>> "patched > >> >>> >>> in Element". > >> >>> >>> > >> >>> >>> // then > >> >>> >>> class FooBar extends HTMLElement {} > >> >>> >>> customElement.define('foo-bar', FooBar) > >> >>> >>> new FooBar // "patched in Element" > >> >>> >>> ``` > >> >>> >>> > >> >>> >>> I tried > >> >>> >>> > >> >>> >>> ```js > >> >>> >>> const OldElement = window.Element > >> >>> >>> > >> >>> >>> window.Element = function Element() { > >> >>> >>> const _this = new OldElement > >> >>> >>> console.log("patched in Element") > >> >>> >>> return _this > >> >>> >>> } > >> >>> >>> > >> >>> >>> window.Element.prototype = OldElement.prototype > >> >>> >>> window.Element.prototype.constructor = window.Element > >> >>> >>> > >> >>> >>> class FooBar extends HTMLElement {} > >> >>> >>> customElements.define('f-b', FooBar) > >> >>> >>> new FooBar // does not log "patched in Element" > >> >>> >>> ``` > >> >>> >>> > >> >>> >>> But when I make a new custom element, constructing it seems to > use > >> >>> >>> the old > >> >>> >>> Element constructor, as if a non-global reference to the > original > >> >>> >>> constructor is kept inside a module so that modifying the global > >> >>> >>> wouldn't > >> >>> >>> have any effect. > >> >>> >>> > >> >>> >>> Is there a way to monkey patch a constructor in the middle of a > >> >>> >>> built-in > >> >>> >>> prototype chain or to otherwise inject construction logic to > base > >> >>> >>> classes of > >> >>> >>> existing class hierarchies? > >> >>> >>> > >> >>> >>> > >> >>> >>> /#!/JoePea > >> >>> >>> > >> >>> >>> _______________________________________________ > >> >>> >>> es-discuss mailing list > >> >>> >>> es-discuss at mozilla.org > >> >>> >>> https://mail.mozilla.org/listinfo/es-discuss > >> >>> >>> > >> >>> >> > >> >>> _______________________________________________ > >> >>> es-discuss mailing list > >> >>> es-discuss at mozilla.org > >> >>> https://mail.mozilla.org/listinfo/es-discuss > >> >> > >> >> > >> >> > >> >> _______________________________________________ > >> >> es-discuss mailing list > >> >> es-discuss at mozilla.org > >> >> https://mail.mozilla.org/listinfo/es-discuss > >> >> > >> > > >> _______________________________________________ > >> es-discuss mailing list > >> es-discuss at mozilla.org > >> https://mail.mozilla.org/listinfo/es-discuss > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20171024/9efbf455/attachment-0001.html>
It's a generic thing to forever impact all future descendants of Element, in theory. For example, a feature like "Element Behaviors" as described here (but I'm going to close that one and open a more concise issue with a working implementation).
The idea is that it would work on any type of element because it is really generic (just like jQuery works on any type of element), so patching Element seemed the best way to do it. /#!/JoePea
It's a generic thing to forever impact all future descendants of Element, in theory. For example, a feature like "Element Behaviors" as [described here](https://github.com/w3c/webcomponents/issues/662) (but I'm going to close that one and open a more concise issue with a working implementation). The idea is that it would work on any type of element because it is really generic (just like jQuery works on any type of element), so patching Element seemed the best way to do it. /#!/JoePea On Tue, Oct 24, 2017 at 11:36 AM, Andrea Giammarchi <andrea.giammarchi at gmail.com> wrote: > are you patching things you know need patching or you want to pollute > forever the future with your patch? > Whatever you are doing should not compromise WebGLElement so it's good you > are unable to patch Element, IMO > > On Tue, Oct 24, 2017 at 3:03 PM, /#!/JoePea <joe at trusktr.io> wrote: >> >> I'm going to use the accessor technique as it's the only way. Thanks! >> >> I was trying to patch `Element` because there's also `SVGElement`. I >> suppose I can duplicate efforts and patch both `HTMLElement` and >> `SVGElement`; that's not too difficult, but it is conceptually uglier >> because for example, what if browsers come out with `MathElement`, >> `WebGLElement`, etc. >> /#!/JoePea >> >> >> On Tue, Oct 24, 2017 at 10:55 AM, Michał Wadas <michalwadas at gmail.com> >> wrote: >> >> To "polyfill" an idea I have for DOM, to propose it later, etc. >> > >> > You can consider something like this depending on your needs: >> > https://gist.github.com/Ginden/03004e52b3d331e236b5256e3b4c08ff >> > >> > On Tue, Oct 24, 2017 at 7:47 PM, /#!/JoePea <joe at trusktr.io> wrote: >> >> >> >> @Michał >> >> >> >> > But why do you need this? >> >> >> >> To "polyfill" an idea I have for DOM, to propose it later, etc. >> >> >> >> @Logan >> >> >> >> > Why not store your data separately in a WeakMap and rather than >> >> > injecting properties onto existing objects? Then you can initialize >> >> > the >> >> > stored data on first access of the data you want. >> >> >> >> I thought about that, it seems like the only way, but was curious to >> >> see about the the during-construction way if possible. >> >> >> >> @Andrea >> >> >> >> But this one doesn't work: >> >> >> >> ```js >> >> window.Element = class extends Element { >> >> constructor() { >> >> super(); >> >> console.log('hello darkness my old friend'); >> >> } >> >> }; >> >> >> >> // then ... >> >> class MyEl extends HTMLElement {} >> >> customElements.define('my-el', MyEl); >> >> >> >> new MyEl; >> >> ``` >> >> >> >> /#!/JoePea >> >> >> >> >> >> On Tue, Oct 24, 2017 at 10:36 AM, Andrea Giammarchi >> >> <andrea.giammarchi at gmail.com> wrote: >> >> > I know I'm going to regret this already, but since I've secretly >> >> > played >> >> > with >> >> > polyfills, you can still do this: >> >> > >> >> > ```js >> >> > window.HTMLElement = class extends HTMLElement { >> >> > constructor() { >> >> > super(); >> >> > console.log('hello darkness my old friend'); >> >> > } >> >> > }; >> >> > >> >> > // then ... >> >> > class MyEl extends HTMLElement {} >> >> > customElements.define('my-el', MyEl); >> >> > >> >> > new MyEl; >> >> > ``` >> >> > >> >> > Regards >> >> > >> >> > >> >> > >> >> > On Tue, Oct 24, 2017 at 2:32 PM, Logan Smyth <loganfsmyth at gmail.com> >> >> > wrote: >> >> >> >> >> >> Given that these are constructors that you don't own, adding your >> >> >> own >> >> >> properties to them seems like an overall ugly approach to me. Why >> >> >> not >> >> >> store >> >> >> your data separately in a WeakMap and rather than injecting >> >> >> properties >> >> >> onto >> >> >> existing objects? Then you can initialize the stored data on first >> >> >> access of >> >> >> the data you want. >> >> >> >> >> >> On Tue, Oct 24, 2017 at 10:25 AM, /#!/JoePea <joe at trusktr.io> wrote: >> >> >>> >> >> >>> Well, I know I can set accessors on a prototype easily, but what I >> >> >>> mean is, I need each instance of an `Element` to have exactly one >> >> >>> instance of something right after construction during the same >> >> >>> synchronous operation. >> >> >>> >> >> >>> For example, if we have an application with a bunch of pre-existing >> >> >>> Elements that do not extend from any classes of mine, I'd like for >> >> >>> the >> >> >>> all to have `foo` properties, so that I can do this: >> >> >>> >> >> >>> ```js >> >> >>> const el = new SomeCustomElementThatWasDefinedCreatedByMe >> >> >>> console.log(el.foo) // it exists and is specific to the instance, >> >> >>> not >> >> >>> a prototype property >> >> >>> >> >> >>> // or >> >> >>> >> >> >>> const div = document.createElement('div') >> >> >>> console.log(div.foo) // it exists and is specific to the instance, >> >> >>> not >> >> >>> a prototype property >> >> >>> ``` >> >> >>> >> >> >>> Can this be done? >> >> >>> /#!/JoePea >> >> >>> >> >> >>> >> >> >>> On Tue, Oct 24, 2017 at 10:19 AM, /#!/JoePea <joe at trusktr.io> >> >> >>> wrote: >> >> >>> >> This feels like a problem similar to >> >> >>> >> https://esdiscuss.org/topic/block-scoped-prototype-extensions >> >> >>> > >> >> >>> > @Boris, even if it were scoped, how do we monkey patch a >> >> >>> > *constructor*? By the way, for some reason your link to >> >> >>> > `https://esdiscuss.org/topic/block-scoped-prototype-extensions` >> >> >>> > posted >> >> >>> > as `https://esdiscuss.org/topic/block` which is 404. If you can >> >> >>> > edit >> >> >>> > it it would help others not to stumble on a broken link. >> >> >>> > >> >> >>> >> if that would be possible, then everyone could just monkey patch >> >> >>> >> Object, right? >> >> >>> > >> >> >>> > But everyone can monkey patch the entire class already, aside >> >> >>> > from >> >> >>> > the >> >> >>> > constructor, by modifying the prototype. Obviously if someone >> >> >>> > returns >> >> >>> > something new from the constructor they might break everything, >> >> >>> > but >> >> >>> > it >> >> >>> > will be completely obvious and people then won't do that. The >> >> >>> > same >> >> >>> > applies with methods and properties, it is super easy to break >> >> >>> > entire >> >> >>> > applications monkey patching methods. >> >> >>> > >> >> >>> > --- >> >> >>> > >> >> >>> > So suppose I want to "polyfill" a concept. For example, I want >> >> >>> > all >> >> >>> > elements to have a new "foo" accessor after they've been >> >> >>> > constructed. >> >> >>> > Or for example, suppose `HTMLElement.prototype.style` and >> >> >>> > `SVGElement.prototype.style` didn't exist yet. How would I patch >> >> >>> > those >> >> >>> > in? >> >> >>> > /#!/JoePea >> >> >>> > >> >> >>> > >> >> >>> > On Tue, Oct 24, 2017 at 10:07 AM, Michał Wadas >> >> >>> > <michalwadas at gmail.com> >> >> >>> > wrote: >> >> >>> >> AFAIR DOM classes are not extensible by any means. >> >> >>> >> >> >> >>> >> >> >> >>> >> >> >> >>> >> On 24 Oct 2017 6:51 pm, "/#!/JoePea" <joe at trusktr.io> wrote: >> >> >>> >>> >> >> >>> >>> Is it possible to monkey-patch an intermediate constructor of a >> >> >>> >>> built-in >> >> >>> >>> subclass? >> >> >>> >>> >> >> >>> >>> For example, suppose I want all `Element` instances in a web >> >> >>> >>> app >> >> >>> >>> to >> >> >>> >>> have >> >> >>> >>> new instance properties, is there a way to monkey-patch the >> >> >>> >>> Element >> >> >>> >>> constructor so that when I make a custom element by extending a >> >> >>> >>> subclass of >> >> >>> >>> `Element` that the new logic will fire? >> >> >>> >>> >> >> >>> >>> For example: >> >> >>> >>> >> >> >>> >>> ```js >> >> >>> >>> // monkey-patch the Element constructor somehow so that it logs >> >> >>> >>> "patched >> >> >>> >>> in Element". >> >> >>> >>> >> >> >>> >>> // then >> >> >>> >>> class FooBar extends HTMLElement {} >> >> >>> >>> customElement.define('foo-bar', FooBar) >> >> >>> >>> new FooBar // "patched in Element" >> >> >>> >>> ``` >> >> >>> >>> >> >> >>> >>> I tried >> >> >>> >>> >> >> >>> >>> ```js >> >> >>> >>> const OldElement = window.Element >> >> >>> >>> >> >> >>> >>> window.Element = function Element() { >> >> >>> >>> const _this = new OldElement >> >> >>> >>> console.log("patched in Element") >> >> >>> >>> return _this >> >> >>> >>> } >> >> >>> >>> >> >> >>> >>> window.Element.prototype = OldElement.prototype >> >> >>> >>> window.Element.prototype.constructor = window.Element >> >> >>> >>> >> >> >>> >>> class FooBar extends HTMLElement {} >> >> >>> >>> customElements.define('f-b', FooBar) >> >> >>> >>> new FooBar // does not log "patched in Element" >> >> >>> >>> ``` >> >> >>> >>> >> >> >>> >>> But when I make a new custom element, constructing it seems to >> >> >>> >>> use >> >> >>> >>> the old >> >> >>> >>> Element constructor, as if a non-global reference to the >> >> >>> >>> original >> >> >>> >>> constructor is kept inside a module so that modifying the >> >> >>> >>> global >> >> >>> >>> wouldn't >> >> >>> >>> have any effect. >> >> >>> >>> >> >> >>> >>> Is there a way to monkey patch a constructor in the middle of a >> >> >>> >>> built-in >> >> >>> >>> prototype chain or to otherwise inject construction logic to >> >> >>> >>> base >> >> >>> >>> classes of >> >> >>> >>> existing class hierarchies? >> >> >>> >>> >> >> >>> >>> >> >> >>> >>> /#!/JoePea >> >> >>> >>> >> >> >>> >>> _______________________________________________ >> >> >>> >>> es-discuss mailing list >> >> >>> >>> es-discuss at mozilla.org >> >> >>> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >>> >>> >> >> >>> >> >> >> >>> _______________________________________________ >> >> >>> es-discuss mailing list >> >> >>> es-discuss at mozilla.org >> >> >>> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >> >> >> >> >> >> >> >> _______________________________________________ >> >> >> es-discuss mailing list >> >> >> es-discuss at mozilla.org >> >> >> https://mail.mozilla.org/listinfo/es-discuss >> >> >> >> >> > >> >> _______________________________________________ >> >> es-discuss mailing list >> >> es-discuss at mozilla.org >> >> https://mail.mozilla.org/listinfo/es-discuss >> > >> > > >
On 10/24/17 2:03 PM, /#!/JoePea wrote:
I was trying to patch
Element
because there's alsoSVGElement
For what it's worth, looks like for the moment custom elements has given up on the idea of custom non-HTML elements...
On 10/24/17 2:03 PM, /#!/JoePea wrote: > I was trying to patch `Element` because there's also `SVGElement` For what it's worth, looks like for the moment custom elements has given up on the idea of custom non-HTML elements... -Boris
I'm not polyfilling Custom Elements, I'm polyfilling something else that doesn't have the problems that Custom Elements has that makes them not usable with SVG. /#!/JoePea
I'm not polyfilling Custom Elements, I'm polyfilling something else that doesn't have the problems that Custom Elements has that makes them not usable with SVG. /#!/JoePea On Tue, Oct 24, 2017 at 12:42 PM, Boris Zbarsky <bzbarsky at mit.edu> wrote: > On 10/24/17 2:03 PM, /#!/JoePea wrote: >> >> I was trying to patch `Element` because there's also `SVGElement` > > > For what it's worth, looks like for the moment custom elements has given up > on the idea of custom non-HTML elements... > > -Boris > > _______________________________________________ > es-discuss mailing list > es-discuss at mozilla.org > https://mail.mozilla.org/listinfo/es-discuss
Is it possible to monkey-patch an intermediate constructor of a built-in subclass?
For example, suppose I want all
Element
instances in a web app to have new instance properties, is there a way to monkey-patch the Element constructor so that when I make a custom element by extending a subclass ofElement
that the new logic will fire?For example:
I tried
const OldElement = window.Element window.Element = function Element() { const _this = new OldElement console.log("patched in Element") return _this } window.Element.prototype = OldElement.prototype window.Element.prototype.constructor = window.Element class FooBar extends HTMLElement {} customElements.define('f-b', FooBar) new FooBar // does not log "patched in Element"
But when I make a new custom element, constructing it seems to use the old Element constructor, as if a non-global reference to the original constructor is kept inside a module so that modifying the global wouldn't have any effect.
Is there a way to monkey patch a constructor in the middle of a built-in prototype chain or to otherwise inject construction logic to base classes of existing class hierarchies?