2012-06-04 23 views
1

我正在嘗試使用Harmony代理,並且希望在代理上下文中運行代碼,這意味着代碼的全局對象將是代理。例如,如果我在代碼中調用函數foo(),它將由代理get()方法管理。在代理上下文中運行代碼

但是使用Proxy.create()和vm.runInNewContext()不起作用,似乎代理對象被新的上下文對象覆蓋並且失去了他的屬性。

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語句,直接引用了全球範圍內的。

回答

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); 
+0

我正在看看這個問題,謝謝! 關於你的第二個解決方案,我怎麼能夠在不必聲明'foo'之前調用'foo('bar')'? –

+0

其實你可以做的一個方法是特別真棒和邪惡的。 'global.__ proto__ = yourproxy'或'Window.prototype .__ proto__ = yourproxy'。這有助於捕捉全球範圍內沒有聲明的任何東西,而我上面提到的用於將所聲明的所有內容都包含在內的方法涵蓋了其餘部分。 – 2012-06-13 13:56:56

+0

嘗試'foo('bar')'時,我得到'ReferenceError:foo未定義',並且在使用'global.foo()'嘗試時,TypeError:Object#沒有方法'foo''。你有沒有任何工作實現你所描述的方法的例子? –

1

簡答:甚至不要想起它。 :)

較長的答案:有很多魔法涉及V8的全球對象的處理,以處理像框架,安全訪問檢查等瀏覽器問題。就目前來看,這種魔法是完全不相容的使用代理代替它。這可能最終會改變,但不會很快。

話雖如此,我也不認爲你應該那樣做。全局對象是一個非常糟糕的功能,它將在和諧中降級,並且建議您不要嘗試用它來玩弄骯髒的技巧。

+0

胡:C我的夢想正在破滅。代理人畢竟不是那麼神奇。 無論如何,謝謝你的答案。 –

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)); 
} 
+0

拋出'ReferenceError:hello is not defined'。是否有可能改變全球原型?對你起作用嗎? –

+1

這可能是因爲我正在使用較新版本的節點。 3.8之前的V8在代理實現方面存在一些重要的錯誤,這會影響Node 0.6.x.你需要使用Node 0.7.x(很快就會是0.8)來使用Proxies。 – 2012-06-13 15:44:43

+0

完全是這樣。對於nodejs 0.6.19,'global .__ proto__ = proxy'將不起作用,但對於0.7.x,'global .__ proto__ = proxy'確實可行。非常感謝你的幫助 ! –