1

I already have a function for modifing other class methods:

class MyClass {
    constructor() {
        this.num = 1;
    }
    inc(){
        this.num++;
    }
}

runAfterMethod(classHandle, methodName, executeAfter) {
    const oldHandle = classHandle.prototype[methodName];
    classHandle.prototype[methodName] = function () {
        const returnValue = oldHandle.apply(this, arguments);
        //@ts-ignore
        executeAfter.apply(this, arguments);
        return returnValue;
    };
}

runAfterMethod(MyClass, "inc", function() {console.log(this.num)})
new MyClass().inc(); // Prints 2

However, this does not work for the constructor of the class (because it is technically the class itself)

What I would really be happy with is something that mimics this behavior:

class MyClass {
    constructor() {
        this.num = 1;
    }
}

extendConstructor(MyClass, function(){
    this.str = "hello world"
})

new MyClass(); // num: 1, str: "hello world"

I have looked at things like How to modify the constructor of an ES6 class however, they all require = somewhere, which does not work inside of a function (where that only changes the value of the class inside the function, not the class itself)

Bagel03
  • 725
  • 7
  • 22
  • 3
    I think that you want to implement what is called "decorator pattern", not to be confused with decorators. In a nutshell: you don't modify the constructor; you create an instance of the class and then give it as argument to the constructor of another class which is quite similar to the original class, but with all the changes you want to make – anotherOne Jan 24 '22 at 01:21
  • You may want to look into tools like `stampit`, they have some neat ways of managing object creation. I haven't used recent versions, but older ones were very helpful in creating composed OO code without relying on class syntax. – Derek Jan 24 '22 at 01:31
  • I found [this free resource](https://www.oreilly.com/library/view/learning-javascript-design/9781449334840/ch09s14.html) on decorator pattern in case you are interested. – anotherOne Jan 24 '22 at 01:38
  • Indeed there is no to do this without an assignment. Just write `MyClass = extendConstructor(MyClass, …);`. Nothing wrong with that. – Bergi Jan 24 '22 at 01:44
  • See [here](https://stackoverflow.com/a/21243884/1048572) and [there](https://stackoverflow.com/a/31789308/1048572) for how that could be achieved. – Bergi Jan 24 '22 at 01:52
  • This would be a good solution, if I didn't have to wrap it in a function https://jsfiddle.net/9p82xho3/6/ – Bagel03 Jan 24 '22 at 02:48
  • It is worth mentioning that you could change the internals of the class (MyClass.prototype.x) with an `=`, but not the whole class. So if there was a way to set the whole class by only changing internals, that would work – Bagel03 Jan 25 '22 at 13:26

1 Answers1

1

Mutating the existing class is really weird. What would be much less of a code smell IMO would be to create a wrapper around the class that instantiates the class, then calls it with your custom callback, and then returns the instance - it'd be a lot more straightforward. Would that work for your purposes?

class MyClass {
    constructor() {
        this.num = 1;
    }
}

const extendConstructor = (theClass, callback) => function(...args) {
  const instance = new theClass(...args);
  callback.call(instance);
  return instance;
};
const Extended = extendConstructor(MyClass, function(){
    this.str = "hello world"
})

console.log(new Extended()); // num: 1, str: "hello world"
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Unfortunately, it would not, as it is being used for a mod-loader in which mods may change things about components that the game uses internally (such as letting buildings be rotated or mirrored by adding to a `position` component. However in another case yes this would work – Bagel03 Jan 24 '22 at 02:25