jmnf 6: lexical scoping

javascript magic-ninja-foo episode 6: More on scope.

I'm going to return briefly to the concept of scope in javascript. Once you begin writing more advanced code in js, especially object oriented code, you'll begin to hit some of the strange nuances of scope in the language.

The principal concept to understand is that javascript is lexically rather than dynamically scoped. Sounds fancy but essentially what it means is that a function's scope/namespace (closures, see episode 3) is created where the function is *defined* in the code rather than where it's executed.

Consider the following:

function GenerateFunction(x) {
   var newFunc = function() { return x };
   return newFunc;
}
/*create 4 new functions*/
var fncArray = [""];
for(var i=0; i<4; i++) {
   fncArray[i] = GenerateFunction(i);
}
/*global x*/
var x=100;
/*execute those new functions
  from the global namespace*/
for(var i=0; i<4; i++) {
   alert("function "+i+" returned "+fncArray[i]());
}

The question from this code that leads to a lot of confusion is "what value of x will be returned by each of the functions in the array?" In a dynamically scoped language, all the functions might return the global variable, 100. In javascript however, where the function is defined is important. Remember that the act of defining a function is actually a runtime statement creating objects.

When this code is executed the return values are

function 0 returned 0
function 1 returned 1
function 2 returned 2
function 3 returned 3

Most of these articles are related and by now the regular reader may have already noticed that this behavior is very similar to the trick I showed for generating 'functions with state'. Again understanding the inner workings of javascript can help clear up the fog when the language is described as lexically scoped.

Using the 'execution object' description from before, it should be clear that every call to 'generateFunction' is creating a new 'execution object'. The x argument to the function becomes a property of that object. Then we are returning an object reference (the reference to the newly defined inner function object) which prevents the garbage collector from zapping the execution object. This shows that each definition of the function 'newFunc' has it's own scope and namespace based on where the 'function XX()' statement was executed.

Note: I'm currently busy trying to create new materials for this blog to show why YAJAF! is the coolest javascript framework/library available. This article is a little shorter than some of the others, short but important. Stay tuned for more articles on manipulating scope, dynamic code, polymorphism, and encapsulation.

Next Episode