Monkey patching constructors in builtin class hierarchies?

Andrea Giammarchi andrea.giammarchi at gmail.com
Tue Oct 24 17:36:42 UTC 2017


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>


More information about the es-discuss mailing list