Monkey patching constructors in builtin class hierarchies?

Michał Wadas michalwadas at gmail.com
Tue Oct 24 17:55:54 UTC 2017


> 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>


More information about the es-discuss mailing list