Nishant
Nishant

Reputation: 21914

Decorating functions in JavaScript

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.

Upvotes: 1

Views: 1751

Answers (1)

Bergi
Bergi

Reputation: 664297

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.

Upvotes: 3

Related Questions