1

我正在试验 Harmony 代理,我想在代理上下文中运行代码,这意味着代码的全局对象将是代理。例如,如果我在代码中调用函数 foo(),它将由代理 get() 方法管理。

但是使用 Proxy.create() 和 vm.runInNewContext() 不起作用,似乎 Proxy 对象被新的上下文对象覆盖并失去了他的属性。

var vm = require('vm');

var proxy = Proxy.create({
    get: function(a, name){
        return function(){
            console.log(arguments);
        }
    }
});

vm.runInNewContext("foo('bar')", proxy); // ReferenceError: foo is not defined

有什么办法可以实现我想要做的事情吗?

// 编辑

(function() {
    eval("this.foo('bar')");
}).call(proxy);

上面的代码效果很好,但是我希望可以不用this语句,直接引用全局上下文。

4

3 回答 3

1

简短的回答:不要想它。:)

更长的答案:V8 对全局对象的处理涉及很多魔法,以处理诸如框架、安全访问检查等浏览器问题。就目前而言,这种魔法与使用代理完全不兼容. 这种情况最终可能会改变,但不会很快改变。

话虽如此,我也不认为你应该这样做。全局对象是一个非常骇人听闻的功能,它将在 Harmony 中被降级,最好不要尝试用它玩肮脏的把戏。

于 2012-06-06T15:13:07.387 回答
1

这有两种可能。在 Node 中,我可以通过稍微修改的 contextify 来做到这一点。Contextify 是一个允许将任意对象转换为全局上下文以运行的模块,类似于 vm 模块。它通过创建一个具有命名属性拦截器的全局对象来实现这一点,该对象然后转发对该对象的访问,因此它能够保持引用“活动”而不是像节点的内置 vm 那样复制属性。我所做的修改是更改它,以便这些访问会触发正确的代理陷阱,IE 更改ctx->sandbox->GetRealNamedProperty(property)(不会触发代理获取陷阱)到ctx->sandbox->Get(property). has、set 等的类似更改。属性枚举不能正常工作(在上下文中也不正常),因为处理属性列表的能力(至少对于 getOwnPropertyNames)没有暴露给 API。

上下文化:https ://github.com/brianmcd/contextify 我的分叉:https ://github.com/Benvie/contextify 拉取请求:https ://github.com/brianmcd/contextify/pull/23

第二种方法将普遍适用,但实际上不会产生代理全局。本质上,您为全局中的每个现有对象创建代理,然后在创建的函数中加载所需的代码,该函数将所有属性作为函数参数进行隐藏。就像是:

var globals = Object.getOwnPropertyNames(global);
var proxies = globals.map(function(key){
  return forwardingProxy(global[key]);
});
globals.push(codeToRun);
var compiled = Function.apply(null, globals);
var returnValue = compiled.apply(forwardingProxy(global), proxies);
于 2012-06-10T15:38:05.400 回答
1
global.__proto__ = forwarder(global.__proto__);
console.log([hello, my, name, is, bob, weeeee])

function forwarder(target){
  var traps = {
    getOwnPropertyDescriptor: Object.getOwnPropertyDescriptor.bind(null, target),
    getOwnPropertyNames: Object.getOwnPropertyNames.bind(null, target),
    keys: Object.keys.bind(null, target),
    defineProperty: Object.defineProperty.bind(null, target),
    get: function(r,k){ return target[k] },
    set: function(r,k,v){ target[k] = v; return true },
    has: function(k){ return k in target },
    hasOwn: function(k){ return {}.hasOwnProperty.call(target, k) },
    delete: function(k){ delete target[k]; return true },
    enumerate: function(){ var i=0,k=[]; for (k[i++] in target); return k }
  };

  var names = {
    get: 1,
    set: 1,
    has: 0,
    hasOwn: 0,
    delete: 0,
    defineProperty: 0,
    getOwnPropertyDescriptor: 0
  }

  return Proxy.create(Proxy.create({
    get: function(r, trap){
      return function(a, b){
        if (trap in names)
          console.log(trap, arguments[names[trap]])
        else
          console.log(trap);

        if (trap === 'get' && !target[b]);
          return b;

        if (trap in traps)
          return traps[trap].apply(target, arguments);
      }
    }
  }), Object.getPrototypeOf(target));
}
于 2012-06-13T14:31:18.717 回答