0

I can do something like this:

var foo = ...// some function assignment
var fooString = foo.toString()
...
// add some alert to foo
...
var fooWithAlert = new Function(forStringWithAlert)

Is there a way to mutate first foo instead of creating new function? I need it to monkey patch some dependency without recreating whole hierarchy of objects.

I need to patch a constructor function in a library, just add an alert on every call. But without juggling with prototypes

3
  • you can manipulate the string by adding the alert function and then appending this manipulated string into a head tag, Not sure with other solutions. Commented Feb 22, 2016 at 10:22
  • It's good to simplify things, but I think you've gone so far simplifying this question that you've probably omitted details relevant to the answers. What, specifically, do you need to do to the function foo refers to? Can you come up with a simple, but representative, thing you need to do? Commented Feb 22, 2016 at 10:25
  • Possible duplicate of Javascript: Extend a Function Commented Feb 22, 2016 at 10:26

1 Answer 1

3

No, you can't modify the function foo refers to. You can only make foo refer to a new function that does what you want. One way to do that is to use your toString approach, but it's best to avoid that if at all possible, because the function you get as a result will not be the same as the original; the scope it has access to will be different.

Usually, you do want a proxy/wrapper, e.g.:

// The original foo
var foo = function(arg) {
    return "original foo says '" + arg + "'";
};
console.log(foo("bar"));

// Let's wrap it
(function() {
    var originalFoo = foo;
    foo = function() {
        return originalFoo.apply(this, arguments) + " plus updated foo";
    };
})();
console.log(foo("bar"));

This doesn't create a hierarchy of objects or similar, it just wraps foo.

If foo is a constructor function (let's call it Foo), you'll also want to copy Foo.prototype:

// The original Foo
var Foo = function(arg) {
    this.value = "original foo";
    this.arg = arg;
};
Foo.prototype.getArg = function() {
    return this.arg;
};
var f1 = new Foo("bar");
console.log(f1.getArg());

// Let's wrap it
(function() {
    var originalFoo = Foo;
    Foo = function() {
        var rv = originalFoo.apply(this, arguments);
        this.arg += " (plus more from augmented foo)";
        return rv;
    };
    Foo.prototype = originalFoo.prototype;
})();
var f2 = new Foo("bar");
console.log(f2.getArg());

And of course, if you need to wrap a function on Foo.prototype, you can do it just like foo in my first example:

// The original Foo
var Foo = function(arg) {
    this.value = "original foo";
    this.arg = arg;
};
Foo.prototype.getArg = function() {
    return this.arg;
};
var f = new Foo("bar");
console.log(f.getArg());

// Let's wrap its getArg
(function() {
    var originalGetArg = Foo.prototype.getArg;
    Foo.prototype.getArg = function() {
        return originalGetArg.apply(this, arguments) + " updated";
    };
})();
console.log(f.getArg());

Note how it doesn't matter that we wrapped the prototype function after creating the f object.

Sign up to request clarification or add additional context in comments.

10 Comments

better perhaps to encapsulate the originalFoo in an IIFE ?
what if he wants to add some 20 lines of code logic into it? Can it still be achieved by this method?
I guess i need to be more concrete github.com/Jxck/assert/blob/master/assert.js#L190 What happens with foo prototype in the case?
@Reddy: Yes, the quantity doesn't matter, just the location. Wrappers work for doing things before the original, or after, or both, but not in the middle.
@Alnitak: I wasn't expecting the OP to use the code verbatim, I was expecting some common sense. :-)
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.