监控所有 JavaScript 对象属性(魔术 getter 和 setter)

IT技术 javascript node.js setter getter
2021-03-05 17:29:34

如何在 JavaScript 中模拟 PHP 风格的 __get() 和 __set() 魔法 getter/setter?很多人说这目前是不可能的。我几乎可以肯定这是可能的,因为像 nowjs ( http://nowjs.com ) 这样的项目会做这样的事情。

我知道您可以使用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“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 有一个实现:node-proxy

3个回答

查看 nowjs 源代码,我相信他们通过持续监视now对象并在检测到它们时在客户端和服务器之间推送更改来做到这一点然而,我承认我还没有完全理解他们的代码。

在浏览器中,这可以通过一些有趣的setInterval技巧来完成

编辑:是的,这确实是他们所做的:客户端的第 368 行now.js他们做了一些更多的技巧,以便一旦检测到新属性,getter 和 setter 就会捕获未来对它的访问,但这些修改仅在setTimeout.

另一个证明在当前 JavaScript 中这是不可能的证据是ECMAScript Harmony 的代理提案明确设计为支持此类场景,这非常强烈地暗示它们目前无法完成。最近的 Mozilla 浏览器有一个原型代理实现,如果这样就足够了。显然V8 正在努力增加支持,这可能就足够了,具体取决于最近使用的 V8 Node 版本。

EDIT2:哦,酷,在服务器端显然 nowjs 确实使用代理!这可能意味着它们在 Node 中已经足够成熟以供您使用。https://github.com/Flotype/now/blob/master/lib/proxy.js看看他们做了什么或者只是var Proxy = require("nodejs-proxy")希望他们遵循规范,这样您就可以利用 MDC 和其他地方的文档。

我实际上只是在你评论时用我的发现编辑了我的帖子:)
2021-04-22 17:29:34
好吧...我可以理解客户端黑客,尤其是浏览器兼容性问题的 b/c。服务器端呢?比如,在 Node.JS 上?你认为有可能在那里做点什么吗?
2021-05-04 17:29:34

在 Firefox 中,您可以使用Object.watch如果您查看此线程,Object.watch() 适用于所有浏览器?,有一个在所有浏览器中使用它的例子。

oop,我刚刚意识到您想查看所有属性,而不是特定属性...上面的解决方案是查看特定属性。

也许这篇文章会有所帮助...?然而,这仅适用于特定属性和基于 Gecko 的浏览器......如果您需要支持其他浏览器,它的错误,但您可以查看 onpropertychange。这是MSDN 页面希望那有所帮助...

谢谢你的帮助。onpropertychange 看起来只适用于 DOM 对象。这需要适用于普通的原始 JS 对象。
2021-05-02 17:29:34