Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monitor All JavaScript Object Properties (magic getters and setters)

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:

  • Is there a way to monitor changes to an object?
  • JavaScript getter for all properties

)

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.

like image 702
BMiner Avatar asked Aug 08 '11 16:08

BMiner


People also ask

How can you get the list of all properties in an object in JavaScript?

To get all own properties of an object in JavaScript, you can use the Object. getOwnPropertyNames() method. This method returns an array containing all the names of the enumerable and non-enumerable own properties found directly on the object passed in as an argument.

What are accessors in JavaScript?

In JavaScript, accessor properties are methods that get or set the value of an object. For that, we use these two keywords: get - to define a getter method to get the property value. set - to define a setter method to set the property value.

What are all the properties in JavaScript?

A JavaScript property is a characteristic of an object, often describing attributes associated with a data structure. There are two kinds of properties: Instance properties hold data that are specific to a given object instance. Static properties hold data that are shared among all object instances.


2 Answers

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 a setTimeout.

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.

like image 70
Domenic Avatar answered Sep 22 '22 10:09

Domenic


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.

like image 33
Juan Mendes Avatar answered Sep 20 '22 10:09

Juan Mendes