监控所有 JavaScript 对象属性(神奇的 getter 和 setter)
如何在 JavaScript 中模拟 PHP 风格的 __get() 和 __set() 魔术 getter/setter?很多人说,目前这是不可能的。我几乎可以肯定这是可能的,因为像 nowjs (http://nowjs.com) 这样的项目就是这样做的。
我知道您可以利用 get 和 set,但是当您不确定属性名称时这些不起作用将。例如,如果您希望在创建新属性时执行事件处理程序,该怎么办?
我想做的示例:(
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“Harmony”标准(可能是 ES6)中。您可以在此处阅读更多内容。引入了一个新的“代理”对象,并带有几个方法(即 Create() 和 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 可以实现: 节点代理。
How do I emulate PHP-style __get() and __set() magic getter/setters in JavaScript? A lot of people say that this is currently impossible. I am almost certain that it is possible because projects like nowjs (http://nowjs.com) do something like this.
I know that you can utilize get and set, but these don't work when you're not sure what the property name will be. For example, what if you wanted an event handler to execute when a new property is created?
Example of what I'd want to do:
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!
(The question is similar to the following questions:
)
EDIT: It looks like this feature is called "dynamic proxies" and should appear in the ECMAScript "Harmony" standard (probably ES6). You can read more here. A new 'Proxy' Object is introduced with a couple methods (I.e. Create() and createFunction() ).
One could do this:
//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)
Bottom line here: it doesn't work in most browsers, but an implementation is available for Node.js: node-proxy.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
查看 nowjs 源代码,我相信他们是通过持续监视 now 对象并在检测到变化时在客户端和服务器之间推送更改来实现这一点的。不过,我承认我还没有完全理解他们的代码。
在浏览器中,这可以通过一些有趣的
setInterval
hack 来完成。编辑:是的,这确实是他们所做的:客户端
now.js
的第 368 行。他们做了一些更多技巧,这样一旦检测到一个新属性,未来对其的访问将由 getter 和 setter 捕获,但这些修改仅在每次进行setTimeout
中的时间为 1000 毫秒。另一个证明这在当前 JavaScript 中不可能的证据是 ECMAScript 的代理提案Harmony 的设计明确就是为了实现此类场景,这强烈暗示它们目前无法实现。最近的 Mozilla 浏览器有原型代理实现,如果这可能就足够了。显然,V8 正在努力添加支持,这可能是足够了,具体取决于目前使用的 V8 Node 版本。
编辑2:哦酷,在服务器端显然nowjs确实使用代理!这可能意味着它们在 Node 中已经足够成熟,可供您使用。看看他们在做什么 https://github.com/Flotype/now /blob/master/lib/proxy.js。或者只需执行 var Proxy = require("nodejs-proxy") 并希望它们遵循规范,以便您可以利用 MDC 和其他地方的文档。
Looking through the nowjs source code, I believe they do this by continuously monitoring the
now
object and pushing changes between client and server whenever they are detected. I admit I haven't fully grokked their code yet, however.In a browser, this would be done with some fun
setInterval
hacks.EDIT: yes, that is indeed what they do: line 368 of the client
now.js
. They do some more tricks so that once a new property is detected, future access to it is caught by getters and setters, but those modifications are only made every 1000 ms in asetTimeout
.Another piece of evidence that this is impossible in current JavaScript is that the proxies proposal for ECMAScript Harmony is designed explicitly to enable such scenarios, implying very strongly that they can't be done currently. Recent Mozilla browsers have a prototype proxies implementation, if perhaps that's enough. And apparently V8 is working to add support, which could be enough depending on what version of V8 Node is using these days.
EDIT2: oh cool, on the server side apparently nowjs does use proxies! Which likely means they are mature enough in Node for your usage. See what they do at https://github.com/Flotype/now/blob/master/lib/proxy.js. Or just do
var Proxy = require("nodejs-proxy")
and hope they follow the spec so you can take advantage of the documentation from MDC and elsewhere.在 Firefox 中,您可以使用 Object.watch 。如果您查看此线程,Object.watch() 适用于所有浏览器? ,有一个在所有浏览器中使用类似的示例。
糟糕,我刚刚意识到您想要观看所有属性,而不是特定属性...上面的解决方案是观看特定属性。
In Firefox, you can use Object.watch. If you look at this thread, Object.watch() for all browsers?, there's an example of using it something like it in all browsers.
Ooops, I just realized you want to watch all properties, not a specific property... The solution above is to watch a specific property.
也许这篇文章会有所帮助......?然而,这仅适用于特定属性和基于 Gecko 的浏览器...如果您需要其他浏览器的支持,它有问题,但您可以查看 onpropertychange。这是 MSDN 页面。希望能有点帮助...
Perhaps this post would help...? That is however, only for specific properties and Gecko based browsers... If you need support for other browsers, its buggy, but you could look into the onpropertychange. Here's the MSDN Page. Hope that helps a bit...