Monkey patching constructors in builtin class hierarchies?

/#!/JoePea joe at trusktr.io
Tue Oct 24 18:03:46 UTC 2017


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


More information about the es-discuss mailing list