Dynamically access private members in closures
I recently came across the following situation: I had a module pattern and I wanted to access all the private members dynamically with a single privileged method.
Just in order to give you a little more context, here’s what it could have looked like if I wanted to access all the public members of the returned object:
var MODULE = (function(){ var x=0, y=2, z=5; return { prop1: 10, prop2: "Hello", get: function(arg){ return this[arg]; } }; }()); MODULE.get("prop1"); // returns 10 MODULE.get("prop2"); // returns "Hello" MODULE.get("get"); // returns function get
But I wanted to access x, y and z just as dynamically as prop1, prop2 and the get function in the example above.
The obvious and trivial solution to that problem could have been the following:
A single private object
Actually, that was the first thing that came to my mind when I was thinking about this problem.
A single private object containing all the private variables I’d like to access dynamically.
So now we can create a single privileged function and return a private variable from the private object based on the passed parameter.
Speaking in code, have a look at the following snippet:
var MODULE = (function(){ var privateVarStore = { x: 0, y: 2, z: 5 }; return { getPrivateVar: function(name){ return privateVarStore[name] } }; }()); MODULE.getPrivateVar('x'); // returns 0 MODULE.getPrivateVar('y'); // returns 2 ...
That just works fine; good for us. But I was wondering whether there’s another way of accessing the private variables dynamically. And .. who would have thought.. it turned out there actually is.
But… well let me show you
Solving it the evil erm.. eval way
var MODULE = (function(){ var x=0, y=2, z=5; return { getPrivateVar: function(name){ return eval(name); } }; }()); MODULE.getPrivateVar('x'); // returns 0 MODULE.getPrivateVar('y'); // returns 2 ...
Interesting, isn’t it? But there’s no evil magic behind it, let me explain what’s happening in the snippet above.
We have the module pattern again, an anonymous function that executes itself, creates a closure therefore we have a state, and finally returns an object with a privileged method accessing variables of the created state. And we have an eval function call in the privileged method. eval takes a string as parameter. This string will be, based on whether it’s a valid expression, statement, or not, evaluated or executed. It executes it in the scope where eval is called, and that’s the little trick here to dynamically get the private variable.
This looks more dynamic than the first approach, BUT it’s a really bad solution. Why? because eval is still evil though it looks nice here.
At first, when you use eval (in most cases you really don’t have to.) you should be concerned about security! Anyone could pass his malicious code to your getPrivate function and it will be executed. But that’s not the biggest problem.
In order to prevent executing malicious code we could use a so called whitelist for our private members that should be accessible.
In terms of code, here’s a snippet:
... // dynamically accessible variables var whitelist = ['x','y','z']; // passed input is in whitelist? yes: return evaluated variable.. return whitelist.indexOf(input) > -1 ? eval(input) : undefined;
Problem solved – told ya, that’s not the biggest problem ;-)
The way bigger problem is that, everytime you use eval it invokes the JavaScript interpreter in order to evaluate/execute the passed string, which is especially bad if you want to access variables dynamically at least more than once. Yeah, I know JavaScript engines these days are more or less able to cache even code from eval, but nevertheless it’ll always be slower than the alternatives to eval.
For example if you have 10 private variables and you want to access them all dynamically several times by passing a parameter to a privileged function you can see how evilly slow it gets.
Conclusion
The two techniques described above both show a solution for dynamically accessing private members in a closure, by having only a single privileged function to access them. Though the eval solution was interesting and looked a bit nicer, the single private object approach’s performance compared to the eval approach’s performance is way better. I wouldn’t recommend using the eval approach in production.
Do you know another/better solution? Would you rather use the eval solution? If so, why? Let me know and write a comment!