Friday 6 January 2012

Access to closure variables 2

For some reason some days ago an old idea about which I had written time ago came to my mind again. Getting access to the free vars of a closure from outside. At that time I said that was not possible in JavaScript, but now I felt like toying around with the idea a bit.

Well, it seems odd that in such a dynamic language where you can get access to the function name, your caller, the parameters, the string representation of a function... you're not given a way to access the vars trapped by a closure. It's a matter of getting access from one running function to the vars of the function where it was declared (declared, not called, this is something that sometimes led me to some confusion, closures trap variables from the function where it was declared, not from the calling function). If we know how closures are implemented in JavaScript, we know that we would need to get access to the internal [[Scope]] property, but it seems to be only accessible to the interpreter, not to us, it's a bit the same as with the [[Prototype]] property (well, [[Prototype]] is more or less accessible now by using the new Object.getPrototypeOf(object) or the the non-standard accessor __proto__). I did some googling-binging to confirm my impressions, and on one side they were confirmed, but at the same time this search also brought up the (partial) solution

The idea is simple, instead of trying to "hack" into the closure, let's go the other way, being the designer of the closure who must decide if he wants some of its variables accessible, and in that case make them accessible. For that, all we need is to create a second closure trapping that same variable and returning it. Let's see a simple example:


var printAndCount1 = function(){
 //our closure "factory"
 var counter = 0;

 

//our "main" closure
 var closureFunction = function(msg){

  print(msg);

  counter++;

 };


//closure used to have access to the trapped var 
closureFunction.getCount = function(){

  return counter;

 };

 

return closureFunction;

}();


printAndCount1("msg1");

print("called: " + printAndCount1.getCount() + " times");

Simple, right? Now, we cold want to generalize this a bit and have a function that gives access to any trapped var that we ask for, the almighty eval comes to our rescue:

closureFunction.getClosureVar = function(varName){

  return eval(varName);

 };

Finally, we could have a sort of general function that we could hook on any closure creating scenario. When we call eval the code being evaled runs just in the same scope where the call is done, this means that if we declare a function inside the eval call, it will trap the scope of the function where eval is being called, so we could do something like this:

var getClosureVar = "function(varName){ return eval(varName);}";

var printAndCount1 = function(){//our closure "factory"
 var counter = 0;

//our "main" closure
 var closureFunction = function(msg){

  print(msg);

  counter++;

 };

//create the closure used to have access to trapped variables
 eval("closureFunction.getClosureVar2 = " + getClosureVar + ";");

 

 return closureFunction;

You can find the code here. In it, you can find some minor "improvement" (use the function.toString() thing...)

No comments:

Post a Comment