13

I created a Proxy object with an "apply" trap:

var target = {},
    handler = { apply: () => 42 }
    proxy = new Proxy(target, handler);
proxy(); // TypeError: proxy is not a function

Therefore, the Proxy object should be callable. However, it doesn't work.

Why?

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • maybe related: [Making an object (non-)callable](http://stackoverflow.com/q/29680473/1048572) – Bergi Sep 02 '15 at 19:59

2 Answers2

25

According to the definition of the [[Call]] internal method of Proxy objects it should work:

However, there is a problem: not all Proxy objects have the [[Call]] method:

A Proxy exotic object only has a [[Call]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Call]] internal method.

Therefore, the target must be a function object:

var target = () => {},
    handler = { apply: () => 42 }
    proxy = new Proxy(target, handler);
proxy(); // 42

Note that I defined target using an arrow function in order to create a function object which is not a constructor function. This way the Proxy object can be called but not instantiated.

If you want to add a "construct" trap too, the target must have a [[Construct]] method, so define it with a function declaration or function expression.

Oriol
  • 274,082
  • 63
  • 437
  • 513
  • "not all Proxy objects have the [[Call]] method" - this is the exact sentence that is missing in MDN docs. Thanks! – Jan Molak Jan 17 '22 at 23:50
1

I came here from Google searching for 'callable proxy'.
While the existing answer works, there is another alternative that may be 'cleaner' for some purposes:

class Callable extends Function {
  constructor() {
    super()    
    return new Proxy(this, {
      apply: (target, thisArg, args) => target._call(...args)
    })
  }
  
  _call(...args) {
    console.log(this, args)
  }
}

You can define all traps in proxy as usual.
All credits to arccoza and his gist here.

user0103
  • 1,246
  • 3
  • 18
  • 36