[英]Using Proxy.apply() on Node.js does not work. Is this a bug or am I doing it wrong?
I am using Proxy to Proxy an object.我正在使用代理来代理一个对象。 The getter and setter work fine like expected. getter 和 setter 可以正常工作。 However, the apply method is never called.但是,从不调用 apply 方法。
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.这样,即使它不存在,我也可以将某些内容分配给p
或返回某些内容。 When I for instance let the getter function return this例如,当我让 getter 函数返回这个时
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.然后console.log(p.flappy)
我会得到响应“getting flappy”,即使它不存在。
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.到目前为止一切p.flapppy()
但是当我尝试调用 flappy 做p.flapppy()
它会抛出一个错误,即 flappy 不是函数。
This is still somewhat obvious because the getter does not return a function.这仍然有些明显,因为 getter 不返回函数。 When I let the getter return a function like this当我让 getter 返回这样的函数时
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.它不起作用p.foo()
或p.foo.call()
或p.foo.apply()
,在这两种情况下都调用 apply 。
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 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 get
ting the property of the object that has the function.简短版本:访问对象(或类)内的函数本质上是get
具有该函数的对象的属性。 The trick is to return another Proxy with apply
so you can proxy these functions correctly.诀窍是使用apply
返回另一个代理,以便您可以正确代理这些功能。
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.访问a
或b
都将被代理的get
捕获,因为它们是对象的属性。 You should catch all get
and then filter for functions.您应该捕获所有get
然后过滤函数。 Once you have a function, you return a new Proxy that catches this particular function with Proxy.apply
.一旦你有了一个函数,你就会返回一个新的代理,它用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.然后,为了让函数按预期执行,在Proxy.apply
我们返回一个Reflect.apply ,它按预期使用正确的参数调用原始函数。
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 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 valueOf
s, I highly recommend to test if a function is native or not with something like this isNative function为了防止记录数十个valueOf
,我强烈建议使用类似 isNative 函数来测试一个函数是否是原生的
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.如MDN 上所述, apply
代理方法用于代理对代理对象本身的函数调用,而不是对对象方法的调用。
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.