# JS scope of member functions

I was writing a program that used a bit of recursion with objects, and it wasn't working at all. After debugging I realized that JS's evil scope was playing nasty tricks.

To spare you guys a wall of text code, I wrote a smaller program:

//Class definition and framework:
TestClass=function(label,level){
this.label=label;
this.level=level;

}

TestClass.prototype.recur=function(){
r=Math.random(); //initialise a local variable
document.write(this.label+":"+r+"<BR/>");
if(this.level==0){return;} //exit after this if level==0, we don't want to blow up the call stack
x=new TestClass("inner1",0)
x.recur();
document.write(this.label+":"+r+"<BR/>"); //Check if r has changed
y=new TestClass("inner2",0)
y.recur();
document.write(this.label+":"+r+"<BR/>"); //check if r has changed
}

//Run this:
a=new TestClass("outer",1);
a.recur();


Output:

outer:0.5542382076382637
inner1:0.7689833084587008
outer:0.7689833084587008
inner2:0.24465859192423522
outer:0.24465859192423522


As one can see, the value of r in the outer function has changed. From this, I see that JS joins the scope of a function with a function (recursively) called in itself. This seems slightly icky and illogical.

My own solution to this was to make every locally initialized variable a member variable. In this example, I would replace all instances of r with this.r.

Then, since I like my objects to be clean, I wrote a garbage collector. Final code would be somewhat like:

//Class definition and framework:
TestClass=function(label,level){
this.label=label;
this.level=level;

}
TestClass.allowedProperties=["label","level"] // do NOT blow these up during garbage collection
TestClass.prototype.recur=function(){
this.r=Math.random(); //initialise a local variable
document.write(this.label+":"+this.r+"<BR/>");
if(this.level==0){return;} //exit after this if level==0, we don't want to blow up the call stack
x=new TestClass("inner1",0)
x.recur();
document.write(this.label+":"+this.r+"<BR/>"); //Check if r has changed
y=new TestClass("inner2",0)
y.recur();
document.write(this.label+":"+this.r+"<BR/>"); //check if r has changed
}

//Garbage collector:
TestClass.prototype.cleanup=function(){
for(x in this){
if(TestClass.allowedProperties.indexOf(x)==-1){
delete this[x];
}
}
}

//Run this:
a=new TestClass("outer",1);
a.recur();
a.cleanup();


This manages the job reasonably well, and cleans up after itself. But I feel that this is a rather inelegant way to do it. Is there a better, elegant way to deal with this form of evil javascript scoping?

• x = foo is global, var x = foo is local – Raynos Apr 14 '12 at 7:27

Thou shalt always use var to declare a variable.
• Strange. I'm self-taught, so this may have slipped me... Though I distinctly remember var global-ifying stuff. :/ – Manishearth Apr 15 '12 at 8:23
• Wikipedia's ECMAScript_syntax article has a good description of JavaScript's scoping issues. There are several things that are non-intuitive, and yes, depending on where you place the var statement, it can create a global variable. – Ross Patterson Apr 15 '12 at 12:29