Monkey patching constructors in builtin class hierarchies?

/#!/JoePea joe at trusktr.io
Tue Oct 24 17:47:41 UTC 2017


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


More information about the es-discuss mailing list