Tanmay
Tanmay

Reputation: 3169

Determine if a function is accessed or invoked in the proxy handler

I have a proxy handler like this:

let handler = {
        get: function(target, name) {
            let member = target[name];
            if (typeof member === 'function') {
                return function() {
                    //
                }
            }
            return member;
        }
    }

Whenever a method is called on Proxy object:

var obj = {
    foo: function() {
        //
    }
}

var p = new Proxy(obj, handler);
p.foo();

...It invokes the function that was returned from the handler's getter. But the problem is, when the method is accessed rather than invoked like this:

p.foo;

The entire definition of the function is returned.

Is there any way by which I could check to see if the method is being accessed (p.foo) or invoked (p.foo())? I am trying to achieve something like:

if (typeof member === 'function' && member.isBeingCalled()) {
    return function() {
        //
    }
}

Also, in case of p.foo, I would like to return the definition of member instead of the function that handler's getter returns.

Upvotes: 4

Views: 719

Answers (2)

Black Beard
Black Beard

Reputation: 1618

Another way is to wrap it in another function in get. Then you can decide to call the real method or not:

const obj = {
    someMethod: () => {
        console.log("I'm invoking");
    },
};

const handler = {
    get(target, prop, receiver) {
        if (prop === "someMethod") {
            //here is a wrapper for your target[prop] method
            return () => {
                console.log("This method is called! Do something!");
                target[prop]();
            };
        }
    },
};

const proxyObj = new Proxy(obj, handler);

proxyObj.someMethod; //nothing interesting - just access function literal
proxyObj.someMethod(); //This method is called! Do something! I'm invoking

Upvotes: 1

Aluan Haddad
Aluan Haddad

Reputation: 31833

Yes, this is possible but in order to make it work you need to consider what happens when call a method

 o.foo()

as there is more going on than you might think.

The first operation is a property lookup that retrieves the value of the property having the key "foo" from the object o. Now, the value retrieved is itself an object, specifically a function object.

The second operation is the invocation of that function as a method by way of function.prototype.apply. What this does is invoke the function with its this value bound to o.

Therefore, in order to achieve the desired behavior, one must proxy the value of the property o.foo rather than o itself. your proxy will use the apply trap to intercept and modify the invocation of the function what is the value of that property. This is described well by MDN. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler/apply

Essentially you would write something like

const foo = o.foo;
const proxiedFoo = new Proxy(foo, {
  apply(target, thisArg, argumentsList) {
    if (thisArg) {
      // this function is being invoked as a method
    }
  }
});

o.foo = proxiedFoo;

Upvotes: 2

Related Questions