简体   繁体   English

javascript Proxy of function apply trap gives no access to the receiver Proxy

[英]javascript Proxy of function apply trap gives no access to the receiver Proxy

When I have a Proxy the get and set traps both provide access to the underlying target Object as well as the Proxy receiver of the initial access request.当我有代理时,get 和 set 陷阱都提供对底层目标 Object 以及初始访问请求的代理接收器的访问。 This is good, because for some "pseudo properties" of the Proxy that I need, I look up the Proxy on a WeakMap to find an extension object which has such properties that apply to the Proxy but not to the underlying target object.这很好,因为对于我需要的代理的一些“伪属性”,我在 WeakMap 上查找代理以找到扩展 object,它具有适用于代理但不适用于底层目标 object 的属性。

When the underlying target Object is a Function, then the apply trap will work, but its arguments are only the naked function, and the thisArg and the arguments, not the Proxy receiver of the initial apply.当底层目标 Object 是一个 Function 时,apply trap 会起作用,但它的 arguments 只是裸露的 function,而 thisArg 和 arguments,不是初始 apply 的 Proxy receiver。 So now my ability to look up extension properties to the Proxy fail.所以现在我无法查找代理的扩展属性。

Is there any other way that I can get back to the Proxy from within the apply trap?有没有其他方法可以让我从应用陷阱中返回到代理? Shouldn't that be considered a bug in the Proxy specification?这不应该被视为代理规范中的错误吗? Or at least an inconsistency?或者至少是不一致? If the Proxy is considered useful in get and set traps, why is it not considered useful in the apply trap?如果 Proxy 在 get 和 set 陷阱中被认为有用,为什么它在 apply 陷阱中被认为没有用?

I'd like to first give an answer to the implicit question "Why do some traps have a receiver and others don't?".我想首先回答隐含的问题“为什么有些陷阱有接收器而有些没有?”。 See here for a list of all traps.请参阅此处以获取所有陷阱的列表。 I was at first missing myself a reference to the receiver within some of these functions.起初我想念自己在其中一些功能中对接收器的引用。 But the logic is as follows: All these traps are interceptors for functions that exist independently from the Proxy : the object internal methods which are invoked whenever an interaction with an object takes place.但逻辑如下:所有这些陷阱都是独立于Proxy存在的函数的拦截器: object 内部方法,只要与 object 发生交互,就会调用这些方法。 These internal methods have been made accessible via the static functions of the namespace Reflect .这些内部方法可以通过命名空间Reflect的 static 函数访问。 These static functions have the same arguments as those of the proxy handler, yet they are meaningful without a proxy (even though apparently the Reflect API was designed having proxies in mind, ie making the internal methods available to the proxy).这些 static 函数与代理处理程序的函数具有相同的 arguments,但它们在没有代理的情况下仍然有意义(尽管显然Reflect API 在设计时考虑了代理,即使内部方法可用于代理)。 Each of these functions has as many arguments as it needs to perform what it does (without any proxy around).这些功能中的每一个都有尽可能多的 arguments,因为它需要执行它所做的事情(没有任何代理)。 Adding an additional receiver argument to Reflect.apply would be meaningless without a proxy around as one already passes a thisArg for the function application.如果没有代理,向Reflect.apply添加额外的receiver参数将毫无意义,因为已经为 function 应用程序传递了thisArg On the other hand, Reflect.get gets the getter for a property of an object and then applies it - usually with the object itself as this , but one might want to replace this by any other object (in particular in the case of a prototype chain, where the getter of a prototype is applied to a descendant).另一方面,Reflect.get 获取Reflect.get属性的 getter,然后应用它 - 通常将 object 本身用作this ,但可能希望用任何其他 object 替换this (特别是在原型的情况下)链,其中原型的 getter 应用于后代)。 Therefore the extra argument receiver makes sense even without a proxy around.因此,即使没有代理,额外的参数receiver也是有意义的。

And as @Bergi pointed out in the comments, even where present as argument in a trap function, the receiver isn't necessarily identical to the proxy anyway, but is simply the this of a getter or setter in this context, so can be a prototype descendant of a proxy or even something completely different.正如@Bergi 在评论中指出的那样,即使在陷阱 function 中作为参数出现, receiver也不一定与代理相同,而只是在this上下文中的 getter 或 setter 的 this,因此可以是代理的原型后代甚至完全不同的东西。 To understand the latter, consider the following: If one calls the Reflect functions with a proxy as the target argument, this leads to a call of the corresponding trap function with the proxy replaced by the target of the proxy.要理解后者,请考虑以下几点:如果使用代理作为target参数调用Reflect函数,这将导致调用相应的陷阱 function,代理被代理的目标替换。 Eg the call Reflect.get(proxy, 'value', exoticObject) will lead to a call of handler.get with proxy replaced by the target of the proxy (let's call it proxyTarget ) but the other arguments unchanged, ie: handler.get(proxyTarget, 'value', exoticObject) .例如,调用Reflect.get(proxy, 'value', exoticObject)将导致handler.get的调用,其中proxy替换为代理的目标(我们称之为proxyTarget )但另一个 arguments 不变,即: handler.get(proxyTarget, 'value', exoticObject) So in this example, the receiver is not even related to the proxy.所以在这个例子中,接收者甚至与代理无关。

Now for the question how to access the proxy from within the traps: One possibility is to create a specific handler for each proxy and store a reference to the proxy as property of the handler.现在的问题是如何从陷阱中访问代理:一种可能性是为每个代理创建一个特定的处理程序并将对代理的引用存储为处理程序的属性。 The handler is always accessible within the traps via "this".始终可以通过“this”在陷阱中访问处理程序。 So this.proxy would give you the proxy within each of the trap functions.所以this.proxy会给你每个陷阱函数中的代理。

The OPs question mentions also an extension object with supplemental properties and a WeakMap to obtain it. OPs 问题还提到了具有补充属性的扩展 object 和用于获取它的 WeakMap。 Instead of using the proxy to look up the extension in the WeakMap one could alternatively as well save a reference to the extension in the handler and access it via this.extension in the traps.除了使用代理在 WeakMap 中查找扩展之外,还可以在处理程序中保存对扩展的引用,并通过陷阱中的this.extension访问它。

I want to provide code that takes the suggestion by @Sebastian https://stackoverflow.com/a/74467044/7666635 and shows how I can always have access to the proxy from a closure:我想提供的代码采纳了@Sebastian https://stackoverflow.com/a/74467044/7666635的建议,并展示了我如何始终可以从闭包中访问代理:

function makeProxyFor(object) {
    const proxy = new Proxy(object, {
        get: function(target, prop, receiver) {
            console.log("get", proxy, target, prop, receiver);
            const result = Reflect.get(target, prop, receiver);
            if(typeof result == 'function' || typeof result == 'object')
                return makeProxyFor(result);
            else
                return result;
        },
        apply: function proxyGet(func, thisArg, args) {
            console.log("apply", proxy, func, thisArg, args);
            const result = func.apply(thisArg, args);
            if(typeof result == 'function' || typeof result == 'object')
                return makeProxyFor(result);
            else
                return result;
        }
    });
    return proxy;
}

Example dialog:示例对话框:

> p = makeProxyFor({ x: function() { return { x: 'x'}; } })
< Proxy {x: ƒ}
> p.x().x
+ get Proxy {x: ƒ} {x: ƒ} x Proxy {x: ƒ}
+ apply Proxy {length: 0, name: 'x', arguments: null, caller: null, prototype: {…}} ƒ () { return { x: 'x'}; } Proxy {x: ƒ} []
+ get Proxy {x: 'x'} {x: 'x'} x Proxy {x: 'x'}
< 'x'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM