如何从代理对象获取代理的处理程序?

How to get proxy's handler from proxy object?

例如,如果我有这个 handler/proxy(来自 MDN example)...

var handler = {
    get: function(target, name){
        return name in target?
            target[name] :
            37;
    }
};

var p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;

console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37

是否可以通过某种方式探测代理 p,从而使我能够取回 handler 对象。

大致如下:

p.__handler__   // returns handler object -> Object {get: handler.get(), set: handler.set(), ...}
p.__handler__.get  // returns get prop/fn of handler -> function(target, name){ ...}

很明显,在handler中设置的各种陷阱仍然"known"到proxy,但是有没有明确的办法return他们/handler从代理本身?如果可以,怎么做?

目前我没有具体的用例,但如果您想在已经拥有代理后动态更改 handler/traps,我认为这很有用。

ECMAScript 不提供访问内部 [[ProxyHandler]] 或 [[ProxyTarget]] 槽的方法。

有些实现可能会提供一些非标准的方式,但不要想当然。

例如,在 Firefox 特权代码上,您可以使用

知道对象是否是代理
Components.utils.isProxy(object);

我建议实施类似的方法来公开 [[ProxyHandler]] 和 [[ProxyTarget]]。他们告诉我在 Debugger.Object 而不是 Components.utils.

中实现它们

当补丁登陆后,就可以使用

Components.utils.import('resource://gre/modules/jsdebugger.jsm');
var Cc = Components.classes;

// Add a debugger to a new global
var global = new Components.utils.Sandbox(
  Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal),
  { freshZone: true }
);
addDebuggerToGlobal(global);
var dbg = new global.Debugger().addDebuggee(this);

// Create a debugger object of your object, and run proxy getters
var dbgObj = dbg.makeDebuggeeValue(object);
if(dbgObj.isProxy) { // a boolean
  dbgObj.proxyHandler.unsafeDereference(); // the [[ProxyHandler]]
  dbgObj.proxyTarget.unsafeDereference(); // the [[ProxyTarget]]
}

添加一个"special"自我描述符属性到getOwnPropertyDescriptor

const target = {
  //Fns ..
  //Props ...
};

const handler = {
  getOwnPropertyDescriptor(target, prop) {
    if(prop == "[[handler]]"){
        return { configurable: true, enumerable: true, value: this };
    }
    return undefined;
  },
  prop1: 'abcd'
  
};

const proxy = new Proxy(target, handler);

console.log(Object.getOwnPropertyDescriptor(proxy, '[[handler]]').value.prop1);

I could see this being useful if you wanted to dynamically change a handler/traps after you already have a proxy

如果您只想在您已经有权访问的(代理)对象上添加处理程序:您可以通过创建一个新的代理来处理您想要的特定陷阱来实现此目的更改,例如:

let newProxyWithDifferentGet = new Proxy(originalProxy, {
  get: (target, key){ ... }
}

如果您想访问原始代理的目标:

如果您是 Proxy 的原作者,那么在构建的时候可以这样操作:

let openedProxy = new Proxy(Object.assign(target, {
  _originalHandler: handler,
  _originalTarget: target
}), handler)

如果您不是作者,那么该原始目标是否应该对用户可用由编写该原始代理的人决定。如果您不同意该作者关于他们的封装,那是一个社会问题,而不是技术问题,并且这不是 ES6 的代理所特有或独有的。如果您正在使用开源代码,请向上游发送一个 PR 来解释为什么您认为原始目标应该对用户可用,或者只是将他们的代码与您的更改分叉并使用它,同时将他们的更新合并到原始存储库中。