11

I am trying to call .toString() on a function proxy.

Simply creating a function proxy and calling toString causes "TypeError: Function.prototype.toString is not generic", setting the toString to return the source of the original causes "RangeError: Maximum call stack size exceeded", but creating a get trap for toString works.

Why does simply setting the toString function not work, but making a get trap does?

function wrap(source) {
 return(new Proxy(source, {}))
}
wrap(function() { }).toString()

function wrap(source) {
 let proxy = new Proxy(source, {})
 proxy.toString = function() {
  return(source.toString())
 }
 return(proxy)
}
wrap(function() { }).toString()

function wrap(source) {
 return(new Proxy(source, {
  get(target, key) {
   if(key == "toString") {
    return(function() {
     return(source.toString())
    })
   } else {
    return(Reflect.get(source, key))
} } })) }
wrap(function() { }).toString()

2
  • related: esdiscuss.org/topic/… Commented Nov 7, 2017 at 22:29
  • Unrelated: return is a keyword, not a function in itself, so it's return x not return(x). The parens doesn't do anything here. Commented Feb 24, 2018 at 1:34

2 Answers 2

8

I was having the same issue. I finally figured out that it's an issue with this. Add a get trap to your handler, bind the proxied object as this on the proxied property if it's a function, and it seems to work okay:

function wrap(source) {
    return new Proxy(source, {
        get: function (target, name) {
            const property = target[name];
            return (typeof property === 'function') 
                ? property.bind(target)
                : property;
        }
    });
}

console.log(wrap(function () {}).toString());

Sign up to request clarification or add additional context in comments.

Comments

2

TypeError: Function.prototype.toString is not generic

Seems like Function.prototype.toString is not supposed to be called on Proxy.

proxy.toString = function() {

This assignment to proxy is passed to the source object as you do not have trap for assignment. If you check source.hasOwnProperty('toString') you'll get true. When you add get trap, you don't change toString method and don't add it into source object, so it works.

The other possible solution is

function wrap(source) {
  let proxy = new Proxy(source, {})
  proxy.toString = Function.prototype.toString.bind(source)
  return proxy
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.