Intercept function calls in javascript

Viewed 4402

What's the equivalent of the __call magic method from PHP ?

I was under the impression that Proxy can do this, but it can't.

class MyClass{
  constructor(){
    return new Proxy(this, {
      apply: function(target, thisArg, args){
        console.log('call', thisArg, args);
        return 'test';
      },

      get: function(target, prop){
        console.log('get', prop, arguments);
      }


    });

  }

}

var inst = new MyClass();
console.log(inst.foo(123));

get seems to work because I see "get foo", but apply does not. I get is not a function error.

3 Answers

apply actually handles a function call to the object itself, i.e. if you do new Proxy(someFunction, { apply: ... }), apply would be called before someFunction is called.

There is nothing for trapping a call to a property, because this would be superfluous – get already handles when a property is returned. You can simply return a function that then produces some debug output when called.

class MyClass{
  constructor(){
    return new Proxy(this, {
      get: function(target, prop) {
        return function() {
          console.log('function call', prop, arguments);
          return 42;
        };
      }
    });
  }
}

var inst = new MyClass();
console.log(inst.foo(123));

This another way of achieving what you have requested.

class MyClass{
  constructor(){
     return new Proxy(this, {
        get(target, propKey, receiver) {
            const origMethod = target[propKey];
            return function (...args) {
                let result = origMethod.apply(this, args);
                console.log(propKey + JSON.stringify(args)
                    + ' -> ' + JSON.stringify(result));
                return result;
            };
        }
    });
  }
  
foo = (x) => {
  return x + 1;
};

}

var inst = new MyClass();
console.log(inst.foo(123));

Yeah Proxy can do that, but even when trapping methods you have to use get of Proxy.

Then here I also executes your real method, but I don't know if you want to mock it.

class MyClass {
  constructor() {
    return new Proxy(this, {
      get(target, prop, receiver) {
        if (typeof target[prop] !== "function") {
          return "etcetcetc";
        }
        return function(...args) {
          console.log('call', args);
          return target[prop]();
        };
      }
    });
  }

  foo() {
    console.log('I am foo!');
  }
}

var inst = new MyClass();
inst.foo(123);

As you can see, if you are calling a method of your instance, I will intercept it, and then return your original method execution.

If you are accessing an attribute of your instance, I will return always a mocked string.

Then of course change it with the behavior that you want to.

Related