Tuesday, October 10, 2006

Javascript Variables

Introduction
It amazes me how long I have been coding little bits and copy/pasting scripts in Javascript without really knowing how it is really working. Javascript is a deceptive language. It just comes with the browser. You use little one or 2 liners to make a roll-over, open a window, change statusbar text. Then you try something more complex. Weird things happen. You work around (more like 'stumble around') bugs.

Javascript is pretty different. It pays to find a good reference and approach the language in a Computer Science kind of way. Don't be a doofus web designer like me and just stumble around.

Interesting bit

There aren't really any global variables. Child functions just have access to their parent scopes.

So this:
var a_global_variable = "Hello World";

function a_function() {
alert(a_global_variable);
}

doesn't really access a global variable. It's really like this (you just don't see it):
function virtual_root_function() {
var local_root_variable = "Hello World";

function a_function() {
alert(local_root_variable);
}
}

All those global variables, classes, and functions are attached to an object. I'm pretty sure it's the window object.

Loops don't have their own scope & Variable declarations are moved to the top

Javascript doesn't give a loop its own scope. It moves all variable declarations to the top of the function. For example:
function my_function() {
var local1 = "hello";

for (var i=0; i<10; i++) {
var y = i;
}

var j = 0;
while (j < 100) {
var k = j + 2;
j = k + 1;
}

alert(i);
alert(k);
}


is the same as (and becomes at runtime)

function my_function() {
var local1 = "hello";
var i = 0;
var y;
var j = 0;
var k;

for (i=0; i < 10; i++) {
y = i;
}

while (j < 100) {
k = j + 2;
j = k + 1;
}

alert(i);
alert(k);
}


That's why you don't get an error when alerting i and k. Since the second snippet is what acutally gets executed i and k are actually in scope of the function the whole time. There is not loop scope. You could alert on i and k before the loops as well. You'll get undefined for a value though since they aren't assigned anything until the loop starts.

Undeclared variables

Javascript is very forgiving. So much so that if you don't declare a variable, but still access it, the variable is declared for you. But it may not be in the scope that you think. Try this:

function my_function1() {
am_i_local = "Am I local to my_function1?";

}

function my_function2() {
alert(am_i_local);
}

my_function1();
my_function2();


Surpised? I was. The am_i_local variable is first accessed and assigned in my_function1 but is still accessible to my_function2. Sounds like a global. Add var in front of am_i_local and see what happens. You will get an error when my_function2 is called. A var statement declares the variable locally in my_function1 making it non-existant in my_function2's scope.

Okay, so what about undeclared variables in nested functions? Take a look at this:

function my_function1() {
var inner1 = function() {
am_i_inner = "Do I exist only in inner1?";
}
var inner2 = function() {
alert(am_i_inner);
}

inner1();
inner2();
}

function my_function2() {
alert(am_i_inner);
}
my_function1();
my_function2();


I get 2 alerts and no errors. So, undeclared variables get a global scope, not just the parent scope. If you add var to am_i_inner you'll get errors. I'm not sure which global scope, but I'd assume they are in the same scope as other global variables. In fact you can walk the global object, which I believe is window and see that am_i_inner is a property of it. Just add this to the end of the script:

for (p in this) {
document.writeln(p + ": " + this[p] + "<br />");
}


So you see, everything I said is true (or appears to be). There aren't really any globals. Everything you do is really just nested in a parent object which looks likes it's the Window object. Javascript is forgiving and declares the variables that you forget to declare as "global". Really it's doing the same thing with the functions declare. For example:

function my_function() {
alert("Hello World!";
}

this.my_function = function() {
alert("Hello World!");
}


Both function declarations do the same thing.


Disclaimer:
For all I know I am blowing southern hot air. So, until someone instructs me otherwise, this is how I understand Javascript variables and scope. You'll want to learn a bit about Javascript closures to gain a deeper understanding of Javasript's behavior.

No comments:

Post a Comment