簡體   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