Monkey patching constructors in builtin class hierarchies?

Andrea Giammarchi andrea.giammarchi at gmail.com
Tue Oct 24 18:36:04 UTC 2017


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>


More information about the es-discuss mailing list