最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Using Proxy.apply() on Node.js does not work. Is this a bug or am I doing it wrong? - Stack Overflow

programmeradmin1浏览0评论

I am using Proxy to Proxy an object. The getter and setter work fine like expected. However, the apply method is never called.

    var p = new Proxy({}, {
    /* getter */
    get(target, name) {
        return target[name]
    },
    /* setter */
    set(target, name, value) {
        target[name] = value
    }, 
    /* supposedly called apply */
    apply(target,that,arg) {
        console.log('apply is called, what to do here?')        
    }
})

This way, I can assign something to p or return something even if it doesn't exist. When I for instance let the getter function return this

get(target, name) {
    return 'getting ' + name
},

and then console.log(p.flappy) I will get the response "getting flappy" even when it doesn't exist.

So far so good but when I try to call flappy doing p.flapppy() it wil throw an error that flappy is not a function.

This is still somewhat obvious because the getter does not return a function. When I let the getter return a function like this

get(target, name) {
    return function() { return 'this is '+name } 
},

I can call the property without it having to exist.

console.log(
    p.flappy() // this is flappy!
)

So when does apply get called? Not in the snippet I just showed here and also not in this case:

p.foo = function() {
    console.log('yay!')
    return 'foo!'
}

It does not work to do p.foo() or p.foo.call() or p.foo.apply(), in neither cases apply is called.

The ultimate purpose of this journey is that I want to return a DIFFERENT value depending on whether a property is being read or being called. Like this:

   p.someNewProperty // return what the getter function returns

    p.anotherProperty() // return something else here because this is a function call

Is this possible?

I am using Proxy to Proxy an object. The getter and setter work fine like expected. However, the apply method is never called.

    var p = new Proxy({}, {
    /* getter */
    get(target, name) {
        return target[name]
    },
    /* setter */
    set(target, name, value) {
        target[name] = value
    }, 
    /* supposedly called apply */
    apply(target,that,arg) {
        console.log('apply is called, what to do here?')        
    }
})

This way, I can assign something to p or return something even if it doesn't exist. When I for instance let the getter function return this

get(target, name) {
    return 'getting ' + name
},

and then console.log(p.flappy) I will get the response "getting flappy" even when it doesn't exist.

So far so good but when I try to call flappy doing p.flapppy() it wil throw an error that flappy is not a function.

This is still somewhat obvious because the getter does not return a function. When I let the getter return a function like this

get(target, name) {
    return function() { return 'this is '+name } 
},

I can call the property without it having to exist.

console.log(
    p.flappy() // this is flappy!
)

So when does apply get called? Not in the snippet I just showed here and also not in this case:

p.foo = function() {
    console.log('yay!')
    return 'foo!'
}

It does not work to do p.foo() or p.foo.call() or p.foo.apply(), in neither cases apply is called.

The ultimate purpose of this journey is that I want to return a DIFFERENT value depending on whether a property is being read or being called. Like this:

   p.someNewProperty // return what the getter function returns

    p.anotherProperty() // return something else here because this is a function call

Is this possible?

Share Improve this question edited Jun 3, 2023 at 17:07 dumbass 27.2k4 gold badges36 silver badges73 bronze badges asked Jun 5, 2016 at 20:56 Jochem StoelJochem Stoel 1,3811 gold badge15 silver badges24 bronze badges 1
  • stackoverflow.com/questions/32360218/… – Damaged Organic Commented Apr 2, 2021 at 13:55
Add a comment  | 

3 Answers 3

Reset to default 12

I know this is question is a year old, but I ran into this as well and I found a way to do what you are trying to do. So this is for future reference, as I didn't find correct solutions elsewhere.

Short version: accessing functions inside an object (or a class) is essentially getting the property of the object that has the function. The trick is to return another Proxy with apply so you can proxy these functions correctly.

Consider the following object:

const myObject = {
  a: 'Hello world!',
  b: x => x * x
};

Accessing a or b shall both be caught by a Proxy's get, because they are properties of the object. You should catch all get and then filter for functions. Once you have a function, you return a new Proxy that catches this particular function with Proxy.apply. Then, to let the function execute as intended, inside the Proxy.apply we return a Reflect.apply, which calls the original function with the correct arguments as expected.

You will end up with this code:

const myProxyObject = new Proxy(myObject, {
  get(target, propKey, receiver) {    
    // Calling functions
    if (typeof target[propKey] === 'function') {
      return new Proxy(target[propKey], {
        apply(applyTarget, thisArg, args) {
          console.log(`Calling ${thisArg.constructor.name}.${propKey}(${args})`);
          return Reflect.apply(applyTarget, thisArg, args);
        }
      });
    }

    // Accessing properties
    if (target.hasOwnProperty(propKey)) {
      console.log(`Get value of ${target.constructor.name}.${propKey}`);
      console.log(`Value: ${target[propKey]}`);
    }

    return target[propKey];
  }
});

Demo on jsfiddle

You don't get the result of the function, because that would require you to execute it.

Note: it is possible to use this with classes and it works very nicely. The only caveat is that your Proxy will be catching all internal functions as well. In order to prevent logging dozens of valueOfs, I highly recommend to test if a function is native or not with something like this isNative function

As documented on MDN, the apply proxy method is for proxying a function call on the proxy object itself, not a call on a method of the object.

It only works with functions (as the Proxy target), not regular object instances, but here is how it would work:

var p = new Proxy(function() {}, {
    apply: function() {
        console.log('apply called');
    }
});
p();

The ultimate purpose of this journey is that I want to return a DIFFERENT value depending on whether a property is being read or being called.

It is not possible to directly do what you intend, nor would it really make sense. To call is to read the property.

and after some years...

yes, you can! you can return a DIFFERENT value depending on whether a property is being read or being called!

const authUser = { id: 1 }

const user = new Proxy(function () {}, {
    get (target, property) {
    return authUser.id
  },
  apply (target, thisArg, args) {
    // some stuff to get user
    return { id: args[0] }
  }
})

console.log(user.id)
console.log(user(2).id)

or you can use two step proxy.

const authUser = { id: 1 }

const user = new Proxy(function () {}, {
  get (target, property) {
    return userProxy(authUser.id, property)
  },
  apply (target, thisArg, args) {
    return userProxy(args[0])
  }
})

function userProxy(id, property) {
  // some stuff to get user
  const user = { id }

  return property ? user[property] : new Proxy(user, {
    get (target, property) {
      return user[property]
    }
  })
}

console.log(user.id)
console.log(user(2).id)

发布评论

评论列表(0)

  1. 暂无评论