1

I'm writing a framework that uses wrapping of functions in order to create a debug tool. Currently, I want to report and aggregate information upon function call. I'm using the following code:

function wrap(label, cb) {
    return function () {
        report(label);
        cb.apply(this, arguments);
    }
}

And then in order to bind the debug operation I will use:

function funcToWrap (){/* Some existing function*/}

funcToWrap = wrap("ContextLabel", funcToWrap); 

Now, when funcToWrap is invoked, it is wired to go through report() method.

The requirement I have is to now change this syntax so that the wrapping is done via:

funcToWrap.wrap("ContextLabel");

Ideally, something like this would solve my issue, but this of course is illegal:

Function.prototype.time = function(label){
    var func = this;
    // The actual difference:
    this = function () { // ILLEGAL
        report(label);
        func.apply(this, arguments);
    }
};

Thank you from ahead for any insight regarding this.

Selfish
  • 6,023
  • 4
  • 44
  • 63
  • 1
    Notice that your wrapped function is missing a `return` before `cb.apply(…)`. – Bergi Mar 18 '15 at 19:32
  • @TravisJ: `arguments` is a built-in feature: It's a pseudo-array of the runtime arguments provided when calling the function. So the OP's `wrap` is returning a function that correctly reuses the `this` it was called with and the arguments it was called with. (It's missing a `return`, as Bergi pointed out.) – T.J. Crowder Mar 18 '15 at 19:33
  • @TravisJ: I made the same mistake the first time I saw it. :-) – T.J. Crowder Mar 18 '15 at 19:35

2 Answers2

2

The requirement I have is to now change this syntax so that the wrapping is done via:

funcToWrap.wrap("ContextLabel");

Unless there's a funcToWrap = at the beginning of that, you simply can't meet that requirement. There's no way to change the guts of the function, you can only do what you're doing, create a new function to take its place.

If you have a funcToWrap = at the beginning, of course, it's quite straightforward. But I take it that's not the requirement.


But if I'm mistaking the requirement, then:

Function.prototype.wrap = function wrap(label) {
    var f = this;
    return function () {
        report(label);
        return f.apply(this, arguments); // Note the added `return` here
    };
};

Usage:

funcToWrap = funcToWrap.wrap("ContextLabel");

Reasonably certain from the question, though, that A) That's not what you're looking for, and B) You could have done it if it were.

Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks. You are not mistaking the requirement, the idea is ti make this as effortless as possible to use. Regarding the last suggestion, it is similar to using the original solution, so nit much in it. But thank you again. – Selfish Mar 18 '15 at 19:55
  • @NitaiJ.Perez: Yeah, exactly. I'm afraid the main answer is "you can't do that" (change just the guts of a function). – T.J. Crowder Mar 18 '15 at 20:04
1

The requirement I have is to now change this syntax so that the wrapping is done via:

funcToWrap.wrap("ContextLabel");

That's impossible. One cannot alter a function's behaviour from the outside, it's much like an immutable primitive value in that regard. The only thing you can do is to create a new function and overwrite the old one, but this overwriting has to be explicit. You could use some eval magic for that (like here), but I recommend to use an assignment like in your first example (regardless whether the wrap function is static or a Function method).

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Thanks for your comment. I'd rather avoid using eval at all cost. I was hoping to be able to get around something, but apparently not. – Selfish Mar 18 '15 at 19:57