【问题标题】:How to get proxy's handler from proxy object?如何从代理对象获取代理的处理程序?
【发布时间】:2016-07-14 23:04:38
【问题描述】:

例如,如果我有这个处理程序/代理(来自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__ 属性,它将响应您的请求。
  • 代理的重点是不允许消费者那样检查它,他们应该像对待任何其他对象一样对待它。如果您是代理的创建者,那么保留对​​ handler 的引用相当简单
  • @Bergi,令我感到奇怪的是,标准以这种方式强制要求“代理点”。我认为理想情况下,代理的创建者有责任将代理声明为公开/公开或私有,即使 95% 的“正确”答案是消费者无法检查/增强它。
  • 是的,确切地说,代理创建者可以公开处理程序 - 如果需要,只需执行 new Proxy({__handler__: handler}, handler)。默认情况下它不会公开,因为 95% 的情况是不需要的。
  • @Bergi,啊,我明白你现在的意思了。从您的原始评论中,我并不明显。请考虑添加/扩展您的想法作为答案。我认为您所说/暗示的关于故意隐藏代理的内容很有见地,而您的解决方案使其成为可能非常相关,并且可能也非常适用于任何想知道这一点的人。

标签: javascript ecmascript-6 es6-proxy


【解决方案1】:

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]]
}

【讨论】:

  • 那么铬呢?
【解决方案2】:

为 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);

【讨论】:

    【解决方案3】:

    如果您想在已有代理后动态更改处理程序/陷阱,我可以看到这很有用

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

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

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

    如果你是原始 Proxy 的作者,你可以在构造它的时候做这样的事情:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2011-11-20
      • 2019-01-29
      • 2022-11-07
      相关资源
      最近更新 更多