Sunday, 10 February 2013

Object.watch Polyfill

For years Mozilla has kept adding extra features to the JavaScript dialect supported by their JS engines while good part of the community was busy in the ES4 wars... Some of these features have done it to ES5, others will do it to ES6 and others will slip away into nothingness (like EX4, xml was still cool 10 years ago, but seriously who gives a damn about it now?). Every now and then while checking the excellent MDN documentation, some of those additions shows up, and that's what happened the other day with Object.watch.

It provides you with "Observable Properties", which means that you can watch the assignments to a property and interfere with it. I guess this functionality was developed prior to the almighty ES proxies idea, which clearly supersedes it. Anyway, as of today Object.watch still seems useful to me, so writing a polyfill for it seemed like a fun way to spend my time in this nicely rainy winter (I'm not joking, I love rainy weather).

The solution is quite obvious: the accessor properties (get/set) added to ES5. As demonstrated in my intercept.js utility, we can intercept the access to an existing property by redefining it with a new accessor property. Indeed, the MDN page on Object.watch points to this existing polyfill. The problem I found with it is that it will only watch data properties, if the property to be observed is already an accessor property, it'll fail.

So, I've rolled my own polyfill and uploaded it here.
You also have a test here

There's not much to explain, it will redefine the property with a new accessor property. The get/set function used for the accessor are closures that trap the old descriptor if it also was an accessor one, or the value itself if it was a data descriptor. This new set will take care of invoking the handler provided to the watch function, and later on setting the returned value. Probably the most interesting part is the trick used to enable the unwatch functionality. We "decorate" the setter with a _watchHelper object, that will store the "type" of the initial property, and the initial descriptor if it was an accessor one, so that we can restore it when requested by unwatch.

No comments:

Post a Comment