Is it possible to access private variables in a module pattern dynamically?
Asked Answered
C

2

11

Is there a way to have a public function from the module-pattern accessing private variables dynamically? test1 shows what I mean with "access dynamically" but with public variables

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(){
            // ??
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2

I ended up with creating a single private variable (an object) storing my private variables so I was able to access them like that

 privateVarStore[privateVarName]

But is there another solution for that?

Clue answered 25/12, 2011 at 4:26 Comment(0)
L
10

DEMO

Yes.

Sorry to disappoint Adam Rackis but you can do it with (the evil) eval:

var x = (function(){
    var x=0, y=2, z=5;

    return {
        toast: 123,
        test1: function(arg){
            return this[arg];
        },
        test2: function(a){
            return eval(a)
        }
    };
}());

console.log(x.test1("toast")); // 123
console.log(x.test2("y")); // should return 2  -> does return 2

This is one of those few exceptions where eval should be used.

EDIT, as per Hans B PUFAL suggestion (comment), you can and should validate the parameter in test2 as follows:

test2: function(a){
    return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined;
}
Latitudinarian answered 25/12, 2011 at 5:36 Comment(6)
To avoid security issues it would be advisable to add a validation that the parameter to test2 is indeed a simple variable : return /^[$_a-z][$_a-z0-9]*$/i.test (a) ? eval(a) : undefined;Havenot
@HansBPUFAL: Great idea! I'll be sure to add itLatitudinarian
+1, but can I suggest an alternative validation idea: if you define an object that lists which of the private variables can be accessed via the public function, like var accessList = {"x":true,"y":true}; then in function test2(a) you can say return accessList[a] ? eval(a) : undefined; - the advantage being that not only does this provide security as to what strings can be passed to eval, it allows you to define other truly private variables that can't be accessed via test2().Anabal
@Anabal - I had to read that a few times, but that's a really cool ideaGerick
@Latitudinarian how about if the eval method is not already attached. I couldn't attach it later. I need access for crawling a webpage and get access to a variable. Chrome inspector has access when debugging and pausing. I might be able to communicate with inspector, do something similar but is it possible without?Shari
@momomo I don't know how that would be possibleLatitudinarian
G
7

No (at least not without resorting to eval, per qwertymk's answer).

y is not a property of x (consider naming this object something better than x to avoid confusion with the local variable x). y is a local variable over which x's methods have formed a closure.

Any of x's methods may access y, but not by saying this.y, but rather by accessing y directly.

Again, y is not a property of your object x. It's just a local variable in the function that created x, thereby causing x's methods to form a closure over it.

So, to get test2 to return y, just do:

test2: function(){
    return y;
}

To create a method allowing you to access private variables, consider something like this:

var x = (function () {
    var privateMembers = { x: 0, y: 2, z: 5 };

    return {
        getPrivate: function (name) {
            return privateMembers[name];
        },
        toast: 123,
        test1: function (arg) {
             return this[arg];
        },
        test2: function () {
           // ??
        }
    };
})();

And then

alert(x.getPrivate("y")); //alerts 2

Check out this fiddle

Gerick answered 25/12, 2011 at 4:28 Comment(6)
how would you recommend Tim to solve the missing code in test2()?Favrot
great answer, but that was my alternative solution (creating a single private object in order to access my private variables in the public function), I was wondering whether there is another (more beautiful) way for doing that?Clue
@Tim - not that I can think of. Personally, I think the above way is more beautiful :)Gerick
One could say that test2 is a getter for y. Conventionally, it might be named getY.Sunken
@TimFriedrich - Steve's comment above is a good one. Depending on what you really intend to do with test2, consider renaming.Gerick
Ping @SteveJorgensen - on the aboveGerick

© 2022 - 2024 — McMap. All rights reserved.