Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

dynamic getter and setters - a possibility

I am trying to solve a problem that came to my mind lately. Let's say we would want and would know how to make a point in having dynamic getters and setters in javascript, more like those in php (__get, __set). But as javascript does not have a catch-all property the only thing we could do is to provide a list of possible keys and iterate to add getters and setters on those only, and hope none other will ever come.

But the problem is not by far solved. So the next approach that came to my mind was to use a nasty hack with try and catch, so anytime a name would be undefined in an object to use the catch as a getter (at least) and then resume the code, hard and maybe pointless thing to do. But from here came my second problem, in an use such as this :

console.log(g.someundefinedproperty); 

the result would have been a call to console.log showing undefined with no exception to be ever thrown. And then it came to me: what if I would use the original window.undefined getter and setter, after all it must be called every time I screw up and misspell a word or something.

So I tried

Object.defineProperty(window, 'undefined', {
    get : function ()
    {
         // functional code, including getting the caller and figuring out
         // where we are, and what we have to do... easy :D

         console.log('works');
    },
    set : function ()
    {
         // some couple more fine hacks here
         console.log('this too');
    }
});

But unfortunately the undefined property of window is configurable : false. Other hacks tried were cloning the window object except the undefined and the inner window property. And on the new object to define the new undefined (please take note of the irony) and then window = mybetterwindow;

As this did not rose any issue my hopes were high, but yet again the system failed me as window can't be overwritten, by design. I made a guess it has it's own getter and it's reinstanciate itself based on the prototype found in window.prototype or even better Window.prototype (note the uppercase).

As my final step in this experiment I had redefined undefined on this prototype hitted run. To no avail, nothing was changed... I tryed creating a new Window(), but Window is not a constructor, fail!

As I have run out of ideas I find myself here writing this pleading for help. If you have any ideas how to solve the dynamic getters and setters problem, (the existencial problem of life, universe and everything else), in a way which does not modify in any way the... way I use the objects (and as bonus it doesn't need to break a hole in the fabric of time and space) or the syntax, I entreat you to speak or forever be silent :).

like image 778
helly0d Avatar asked Dec 12 '12 22:12

helly0d


2 Answers

But unfortunately the undefined property of window is configurable: false

This is true only since EcmaScript 5.1. Before, it was overwritable.

what if I would use the original window.undefined getter and setter, after all it must be called every time I screw up and misspell a word or something.

No, it would not have worked. There is a difference between the undefined value and the global variable "undefined". The variable is not evaluated each time a undefined value is encountered (e.g. in typeof (void 0)), only when you use it explicitly (such as in g.someprop === undefined).

Any ideas how to solve the dynamic getters and setters problem?

There is only one solution: Proxies. Unfortunately, it is only a harmony draft and currently only supported in Firefox' Javascript 1.8.5.

See also Is there an equivalent of the __noSuchMethod__ feature for properties, or a way to implement it in JS?, Detect when a new property is added to a Javascript object? or How to detect when a property is added to a JavaScript object? which implements a polling solution (checking for changes via setInterval).

For a clean solution, you currently have to use an explicit getter function, which you pass the property name (g.get("someundefinedproperty")).

like image 92
Bergi Avatar answered Sep 30 '22 20:09

Bergi


What you're trying to accomplish (a global getter for any undefined property) is outside the scope of cross-browser JavaScript.

The closest functionality would be using __defineGetter__ to add a particular property to all objects:

var o = Object.prototype;
o.__defineGetter__("testo", function() { return "yo in testo"; });
alert({}.testo);
alert((new Date()).testo);

​ http://jsfiddle.net/NLCvs/2/

This may be useful if you can predict the name of possibly undefined properties ahead of time. Even so it's quite hacky and bad form to add an accessor to all objects for a property that might be undefined.

A better option is to refactor code when an undefined property may be accessed:

function getter(o, n) {
 return typeof o[n] == 'undefined' ? 'some default value' : o[n];
}
var obj = { hello: 'world' };
alert(getter(obj, 'hello'));
alert(getter(obj, 'an_undefined_property'));

An even better option is to use a mixin to set any default properties you will need to access, for instance via jQuery.extend

var defaults = {
 required: 'this property is required'
};
var my_object = {
 something_else: 'this is something else'
};
var o = jQuery.extend({}, defaults, my_object);

// o.required === 'this property is required'
// o.something_else === 'this is something else'
like image 35
leepowers Avatar answered Sep 30 '22 21:09

leepowers