2011-08-08 19 views
24

如何在JavaScript中模擬PHP風格的__get()和__set()魔術獲取器/設置器?很多人說這是不可能的。我幾乎可以肯定,這是可能的,因爲諸如nowjs(http://nowjs.com)這樣的項目就是這樣做的。監視所有JavaScript對象屬性(魔法獲取器和設置器)

我知道你可以利用getset,但是當你不確定屬性名稱是什麼時,這些不起作用。例如,如果您希望在創建新屬性時執行事件處理程序,該怎麼辦?

的什麼我想要做的

例子:

var obj = {}; 
notify(obj, function(key, value) { 
    //key is now the name of the property being set. 
    //value is the value of the property about to be set 
    console.log("setting " + key + " to " + value); 
}); 
obj.foo = 2; //prints "setting foo to 2" 
obj.bar = {a: 2}; //prints "setting bar to [Object]" 
//Notice that notify() worked even though 'foo' and 'bar' weren't even defined yet! 

(現在的問題是類似以下問題:

編輯:它看起來像這個功能被稱爲「動態代理」,應該出現在ECMAScript「和諧」標準(可能是ES6)。你可以閱讀更多here。一個新的'代理'對象引入了幾個方法(即創建()和createFunction())。這裏

//Constructing an object proxy (proto is optional) 
var proxy = Proxy.create(handler, proto); 
proxy.foo = 2; //Triggers 'set' function in the handler (read about it) 

底線:

一個能做到這一點,並不在大多數瀏覽器工作,但實現可用於Node.js的:node-proxy

+1

此功能稱爲代理是ECMAScript 6的一部分而不是5. – Raynos

+0

良好的捕獲。修改了我的帖子。謝謝! – BMiner

回答

12

通過nowjs源代碼,我相信他們通過持續監視now對象並在客戶端和服務器檢測到時推送更改來實現此目的。然而,我承認我還沒有完全熟悉他們的代碼。

在瀏覽器中,這可以通過一些樂趣setInterval黑客來完成。

編輯:是的,這的確是他們所做的:line 368的客戶端now.js。他們做some more tricks,這樣一旦一個新的屬性被檢測到,將來的訪問被getter和setter捕獲,但這些修改只會在setTimeout中每1000毫秒進行一次。

在當前JavaScript中這是不可能的另一個證據是the proxies proposal for ECMAScript Harmony明確地設計用於啓用這樣的場景,這意味着非常強烈地表明它們目前無法完成。最近的Mozilla瀏覽器有a prototype proxies implementation,如果可能就夠了。顯然V8 is working to add support,這可能是足夠的,這取決於最近使用的V8節點的版本。

EDIT2:爽哦,對服務器端顯然nowjs不使用代理!這可能意味着它們在Node中足夠成熟,可供您使用。看看他們在https://github.com/Flotype/now/blob/master/lib/proxy.js做什麼。或者只是做var Proxy = require("nodejs-proxy"),並希望他們遵循規範,以便您可以利用MDC和其他地方的文檔。

+0

好吧...我可以理解客戶端黑客,尤其是瀏覽器兼容性問題的B/C。那麼服務器端呢?就像Node.JS一樣?你認爲有可能在那裏做點什麼嗎? – BMiner

+2

我其實只是編輯我的帖子與我的發現,因爲你在評論:) – Domenic

0

也許this post會幫助......?然而,只有特定的屬性和基於Gecko的瀏覽器...如果你需要支持其他瀏覽器,它的越野車,但你可以看看onpropertychange。這是MSDN Page。希望有一點幫助...

+0

感謝您的幫助。 onpropertychange看起來像只適用於DOM對象。這需要爲普通的原始JS對象工作。 – BMiner

2

在Firefox中,您可以使用Object.watch。如果你看這個主題,Object.watch() for all browsers?,有一個在所有瀏覽器中使用它的例子。

Ooops,我只是意識到你想要觀看所有的屬性,而不是一個特定的屬性......上面的解決方案是觀看一個特定的屬性。