I'd like to monkey patch the constructor for this 'Controller' object. But how do I monkey patch the constructor function so I can still call the original? This is what I've tried.
// original
function Controller() {
this._tag = 'div';
}
Controller.prototype.tag = function() {
console.log(this._tag);
}
var c = new Controller();
c.tag(); // -> 'div', as expected
// patch attempt
var original = Controller;
Controller = function() {
original.apply(this);
this._tag = 'patched'; // patch
}
var c = new Controller();
c.tag(); // no method tag, prototype appears wiped...
I'd like to monkey patch the constructor for this 'Controller' object. But how do I monkey patch the constructor function so I can still call the original? This is what I've tried.
// original
function Controller() {
this._tag = 'div';
}
Controller.prototype.tag = function() {
console.log(this._tag);
}
var c = new Controller();
c.tag(); // -> 'div', as expected
// patch attempt
var original = Controller;
Controller = function() {
original.apply(this);
this._tag = 'patched'; // patch
}
var c = new Controller();
c.tag(); // no method tag, prototype appears wiped...
Share
Improve this question
edited Dec 16, 2011 at 18:07
Dane O'Connor
asked Dec 16, 2011 at 6:11
Dane O'ConnorDane O'Connor
77.3k39 gold badges120 silver badges174 bronze badges
7
- The grouping operator around the RHS function expression is superfluous. The "constructor" is declared inside another function, so you can't access it from outside (unless missing code makes it a property of the outer anonymous function or some other object). So if you want to "monkey patch" the constructor (whatever that means), inserting code where you have the comment is the only way. – RobG Commented Dec 16, 2011 at 6:37
- @RobG If curious: en.wikipedia.org/wiki/Monkey_patch Its pretty straight forward to monkey patch a property or method, but because of the constructor functions special status I'm at a loss. You may be correct that this isn't possible, but I'm not sure about the reasons you state yet. I'll updated the code sample to reflect. – Dane O'Connor Commented Dec 16, 2011 at 15:03
- Telling us how to monkey path a normal method is not a better code sample. It only makes it even harder to see what your real question is. – hugomg Commented Dec 16, 2011 at 15:56
- couldn't you wrap the constructor and modify the object after it was created? i.e. define a function that calls the saved old constructor and then does its modification and returns the new object. this is commonly done else were with the factory pattern in python. – Dan D. Commented Dec 16, 2011 at 15:58
- @missingno truth. Edited once more. – Dane O'Connor Commented Dec 16, 2011 at 16:10
3 Answers
Reset to default 9You seem to want to do something like:
Constructor.prototype.oldTag = Constructor.prototype.tag;
Constructor.prototype.tag = function() {/* whatever */};
Now all instances get the new tag method and you can still call oldTag if you want (or put it back).
Or perhaps you want to do something like:
var oldConstructor = Constructor;
var Constructor = function () { /* new constructor */ };
Constructor.prototype = oldConstructor.prototype;
So now you have a new constructor with all the old methods. Or do both the above. Just use plain English to say what you want to do.
The cleaner way is not monkey patching the constructor: put the constructor logic in a separate init
method and monkey patch / inherit that instead.
function Constructor(){
this.init();
}
Constructor.prototype.init = function(){ /*...*/ };
You can also consider building objects with a builder function
function make_fancy_obj(){
var obj = new Constructor();
obj.foo = 'bar';
return obj;
}
Constructor functions may optionally return a different this
, which will override whatever is generated by the new
statement itself - here's your example corrected and annotated:
// original
function Controller() {
this._tag = 'div';
}
Controller.prototype.tag = function() {
console.log(this._tag);
}
var c = new Controller();
c.tag(); // -> 'div', as expected
// patch attempt
var original = Controller;
Controller = function() {
const instance = new original(...arguments); //