0

it seems that I'm in a bad situation here.

I'm using a javascript library and I need to augment a property inside a class but it seems that it can't be done because the property definition does not set configurabe: to true.

Here is the library code:

Object.defineProperty(PIXI.DisplayObjectContainer.prototype, 'width', {
  // no configurable: true
  get: function () { ... },
  set: function (value) { ... }
});

My attempt is override this code with something really similar, but when I try do run it, this error happen:

Uncaught TypeError: Cannot redefine property: width
    at Function.defineProperties (<anonymous>)

My question is: is that a way to force this override? I know this is not beautiful at all but we REALLY run out of options here.

Kleber
  • 942
  • 1
  • 15
  • 25
  • Have you heard about javascript Proxy object? I'm not too familiar with it, but it wraps a target object, and can either pass through or set traps for fundamental operations - including property access. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy – IAmDranged May 05 '21 at 19:47
  • "*I need to augment a property inside a class*" - can you tell us more about the actual problem? Maybe there's a better way to solve it. – Bergi May 05 '21 at 21:54
  • 1
    Can you link the whole library code please? Notice that if you can access `PIXI.DisplayObjectContainer.prototype` before the above code runs, you can create the property as configurable and the `defineProperty` won't change that. – Bergi May 05 '21 at 21:55
  • @IAmDranged I didn't know this Proxy object, but it seems that it creates a new instance of the class, what I need is to alter the original one so all classes that extend it also have the new behavior. Thanks, though! – Kleber May 06 '21 at 13:43
  • @Bergi here is the link to the library source code: https://github.com/photonstorm/phaser-ce/blob/6f21578d3086ac34a757267e3ac4675552838654/src/pixi/display/DisplayObjectContainer.js#L582 . And your idea of accessing it before the code execution is interesting I'll try something here. Thanks! – Kleber May 06 '21 at 13:49
  • 1
    @ Kleber - It doesn't create a new instance of the target object, but it creates a wrapper object around it, yes. Maybe I'm not thinking straight - but couldn't you just consider reassigning the prototype to a proxied version of it? Or is the prototype itself not writable? Maybe this is just not the best idea after all, sounds like you may be onto some other more promising lead. – IAmDranged May 06 '21 at 14:04
  • @Kleber Looks like you can't access it before that line, since the object is only created in the same file. But again, why do you need to overwrite it? What is the problem you're trying to solve by messing with the library code? – Bergi May 06 '21 at 14:30
  • @IAmDranged unfortunatelly I can't reassign the prototype since I need all the classes that extend this base class inside the library itself be altered. Yes, it's not the best solution but we are altering some core features of the library, so it must be done!!! – Kleber May 06 '21 at 17:00
  • @Bergi The thing is, Phaser, the library, does not support laying out stuff dinamically in the screen for multiple device resolutions / orientations. So we are implementing it. And for that, we need to override some stuff inside it. It worked like a charm until we got stuck with this problem with only two properties. – Kleber May 06 '21 at 17:08
  • 1
    @Kleber Wouldn't it be sufficient to overwrite `getLocalBounds()` only? Also I suggest making a feature request for the dynamic layout you need - or as a short-term solution, a PR with a patch that makes the property configurable. – Bergi May 06 '21 at 18:30

1 Answers1

1

You can swap out the entire prototype object:

const DOC = PIXI.DisplayObjectContainer
DOC.prototype = Object.assign(Object.create(Obect.getPrototypeOf(DOC.prototype)), DOC.prototype);

This should work since the accessor properties are not enumerable as well - if they are, you need to manually copy only those properties that you need instead of using Object.assign. After this, you can do

Object.defineProperties(DOC.prototype, {
    width: { … },
    height: { … },
});

Ensure you do the replacement before the class is instantiated for the first time.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I couldn't make this work :/. After running the first piece of code, the definitions made by the second are somewhat ignored or ovewritten and the new functions I declare inside it are not there at runtime. I'll give it a try on Monday again to see if I can make this work as I need. – Kleber May 08 '21 at 12:46