我正在试验Harmony Proxies,我想在代理上下文中运行代码,这意味着代码的全局对象将是代理。例如,如果我在代码中调用函数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
语句,并直接引用全局上下文。
答案 0 :(得分:1)
简短的回答:甚至没有想到它。 :)
更长的答案:V8处理全局对象有很多魔力,以处理浏览器问题,如帧,安全访问检查等。目前,这种魔法与使用代理完全不兼容在它的位置。这可能最终会改变,但不会很快改变。
话虽如此,我也不认为你应该那样做。全局对象是一个非常hacky功能,它将在Harmony中被降级,并且最好不要尝试用它来玩肮脏的技巧。
答案 1 :(得分:1)
这有两种可能。在Node中,我能够通过略微修改的上下文来做到这一点。 Contextify是一个模块,允许将任意对象转换为全局上下文,以便与vm模块类似地运行。它通过创建一个具有命名属性拦截器的全局对象来实现这一点,该对象然后转发对该对象的访问,因此它能够保持引用“实时”而不是像节点的内置虚拟机那样复制属性。我做的修改是更改它,以便这些访问将触发正确的代理陷阱,IE将ctx->sandbox->GetRealNamedProperty(property)
(不会触发代理获取陷阱)更改为ctx->sandbox->Get(property)
。 has,set等的类似更改。属性枚举不能正常工作(通常也不正常),因为提交属性列表的能力(至少对于getOwnPropertyNames)不会暴露给API。
Contextify: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);
答案 2 :(得分: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));
}