繁体   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

当我有代理时,get 和 set 陷阱都提供对底层目标 Object 以及初始访问请求的代理接收器的访问。 这很好,因为对于我需要的代理的一些“伪属性”,我在 WeakMap 上查找代理以找到扩展 object,它具有适用于代理但不适用于底层目标 object 的属性。

当底层目标 Object 是一个 Function 时,apply trap 会起作用,但它的 arguments 只是裸露的 function,而 thisArg 和 arguments,不是初始 apply 的 Proxy receiver。 所以现在我无法查找代理的扩展属性。

有没有其他方法可以让我从应用陷阱中返回到代理? 这不应该被视为代理规范中的错误吗? 或者至少是不一致? 如果 Proxy 在 get 和 set 陷阱中被认为有用,为什么它在 apply 陷阱中被认为没有用?

我想首先回答隐含的问题“为什么有些陷阱有接收器而有些没有?”。 请参阅此处以获取所有陷阱的列表。 起初我想念自己在其中一些功能中对接收器的引用。 但逻辑如下:所有这些陷阱都是独立于Proxy存在的函数的拦截器: object 内部方法,只要与 object 发生交互,就会调用这些方法。 这些内部方法可以通过命名空间Reflect的 static 函数访问。 这些 static 函数与代理处理程序的函数具有相同的 arguments,但它们在没有代理的情况下仍然有意义(尽管显然Reflect API 在设计时考虑了代理,即使内部方法可用于代理)。 这些功能中的每一个都有尽可能多的 arguments,因为它需要执行它所做的事情(没有任何代理)。 如果没有代理,向Reflect.apply添加额外的receiver参数将毫无意义,因为已经为 function 应用程序传递了thisArg 另一方面,Reflect.get 获取Reflect.get属性的 getter,然后应用它 - 通常将 object 本身用作this ,但可能希望用任何其他 object 替换this (特别是在原型的情况下)链,其中原型的 getter 应用于后代)。 因此,即使没有代理,额外的参数receiver也是有意义的。

正如@Bergi 在评论中指出的那样,即使在陷阱 function 中作为参数出现, receiver也不一定与代理相同,而只是在this上下文中的 getter 或 setter 的 this,因此可以是代理的原型后代甚至完全不同的东西。 要理解后者,请考虑以下几点:如果使用代理作为target参数调用Reflect函数,这将导致调用相应的陷阱 function,代理被代理的目标替换。 例如,调用Reflect.get(proxy, 'value', exoticObject)将导致handler.get的调用,其中proxy替换为代理的目标(我们称之为proxyTarget )但另一个 arguments 不变,即: handler.get(proxyTarget, 'value', exoticObject) 所以在这个例子中,接收者甚至与代理无关。

现在的问题是如何从陷阱中访问代理:一种可能性是为每个代理创建一个特定的处理程序并将对代理的引用存储为处理程序的属性。 始终可以通过“this”在陷阱中访问处理程序。 所以this.proxy会给你每个陷阱函数中的代理。

OPs 问题还提到了具有补充属性的扩展 object 和用于获取它的 WeakMap。 除了使用代理在 WeakMap 中查找扩展之外,还可以在处理程序中保存对扩展的引用,并通过陷阱中的this.extension访问它。

我想提供的代码采纳了@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;
}

示例对话框:

> 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