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

Comments on this entry are closed.

  • Anonymous

    Please, keep them coming. Very good reading.

  • mikepk

    Thanks! I’m glad people are finding them useful.

  • Frank Manno

    Mike,

    One thing that’s confusing me is this sentence:


    In a dynamically scoped language, all the functions might return the global variable, 100.

    One thing that was obvious to me from the start was that the function was going to return the value of the counter passed to the “GenerateFunction()” function. The part about dynamically scoped languages returning 100 is what I found confusing.

    I know it’s totally off-topic, but could you give me an example of such a case? I’m sure once I see it it will be evident to me, but off the top of my head, I can’t think of anything.

  • mikepk

    That’s good because it means your thinking like javascript. :)

    In a dynamically scoped language, the function doesn’t have any scope ‘dragged’ with it from where it was defined. (the outer x, the argument, wouldn’t be part of the function).

    It’s tough to describe a counter example because dynamically generating functions is not a natural thing to do in more common languages.

    Here’s an example I found from wikipedia. (you can try this in the shell)
    var x = 0;
    function f() { return x; };
    function g() { var x=5; return f() };
    alert(g());

    What happens in a ‘dynamically’ scoped language is that the call to g() creates a stack where a local x is defined. Then the inner call to f() creates a stack with no x definition. When the x variable is resolved, the return value is going to be 5 (and not 0) the first frame containing a definition of x.

    That same code in a lexically scoped language would return ’0′ because the global x scope was what was in effect when the f() function was defined. The inner local x (in g()) would be ignored.

    Hopefully that makes more sense. I’ll try to think of a better way to describe it.