1

Here is a simple decorator pattern which modifies a normal function:

function decorator1(f){
   function wrapper(...args){
       pre();
       return f(...args);
       post();
   }
   return wrapper
}

Now assume there is an object obj and it has a property prop in its prototype. I want to modify the object's bound function for some reason.

I can't use this pattern directly to decorate the bound function obj.prop because if I pass it as an argument to the decorator, it won't get invoked with the correct object in the wrapper because JavaScript relies on the calling to pass the correct object. So obj.prop() is context-aware but obj.prop is not. Is there a way to overcome this limitation?

If that is not possible I need to either:

Change the pattern to accept the object and property as 2 different arguments and make it work.

function decorator2(o, f){
   function wrapper(...args){
       pre();
       return o.f(...args);
       post();
   }
   return wrapper
}

obj.prop = decorator2(obj, prop);

Pass a bound function which for some reason I think is a hard-coding.

// This creates a bound function to itself.
obj.prop = obj.prop.bind(obj)
// This modifies it.
obj.prop = decorator1(obj.prop)

Which one is preferred? I would go for the former because I think that creating bound functions are not good unless you really need them.

Nishant
  • 20,354
  • 18
  • 69
  • 101

1 Answers1

3

You can just use this in the wrapper:

function decorate(f) {
    return function wrapper(...args) {
        pre();
        const res = f.apply(this, args); // or f.call(this, ...args)
//                          ^^^^
        post();
        return res; // make post() work
    };
}

With this, a plain obj.prop = decorate(obj.prop); will work.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Yes @Bergi, this is another one I tried. Thanks for pointing it out. This one makes it callers responsibility to pass the object preserving the original behavior which is the cleanest thing to do. I got a JS Lint warning saying that `if a strict mode function is executed using function invocation 'this' will be undefined`. Do I have to worry about that? I thought this is the best approach actually. – Nishant Jun 02 '18 at 10:10
  • The error code is `w040`. Probably something I can ignore based on the answer to https://stackoverflow.com/questions/7688765/why-is-jshint-complaining-that-this-is-a-strict-violation? – Nishant Jun 02 '18 at 10:14
  • 1
    Yes, you should ignore that warning. We *want* `this` to be `undefined` when the caller doesn't provide one, because then we don't want to provide one to `f` either. – Bergi Jun 02 '18 at 10:20