David Given
David Given

Reputation: 13691

How to modify the constructor of an ES6 class

I'm trying to do hot code reloading with ES6 classes. I need to be able to modify a classes' constructor, without replacing the class with a new one (because other people may have a reference to it).

However, I'm finding that it looks as if the class object has some internal reference to the constructor it was originally defined with; instantiating the class with new doesn't look up either constructor or prototype.constructor on the class.

Example:

class OldC { constructor() { console.log("old"); } }
class NewC { constructor() { console.log("new"); } }

OldC.prototype.constructor = NewC.prototype.constructor;
OldC.constructor = NewC.constructor;
new OldC();

---> "old"

(Updating all the other methods works fine; it's just the constructor I'm having trouble with.)

Thinking that the constructor might be being found via [[prototype]], I've also added this:

Object.setPrototypeOf(OldC, Object.getPrototypeOf(NewC));
Object.setPrototypeOf(OldC.prototype, Object.getPrototypeOf(NewC.prototype));

That doesn't help either (and I wouldn't have expected it to given that no subclassing is happening).

After all this, inspecting OldC shows that the prototype properties are exactly as I would expect them to be, with OldC.prototype.constructor being the new one. But still, constructing an instance of OldC calls the original constructor.

What's going on, and how can I fix it?

Upvotes: 7

Views: 5388

Answers (1)

Bergi
Bergi

Reputation: 664297

Still, constructing an instance of OldC calls the original constructor.

Yes, because OldC itself is the constructor function. You need to overwrite the OldC variable to change what new OldC does.

Modify a classes' constructor, without replacing the class with a new one (because other people may have a reference to it).

As @trincot pointed out in the comments, you cannot modify the code of a function. You must replace the constructor with a new one, there's no way around it.

You can keep the prototype object though (which is mutable), as this is what most other things (especially the old instances) will reference.

NewC.prototype = OldC.prototype;
NewC.prototype.constructor = NewC;
OldC = NewC;

People who took a reference to the old constructor that cannot be changed now can't be helped. Your best bet is not handing out the class itself at all, but only a factory whose behaviour your update code knows to modify.

Upvotes: 4

Related Questions