pierrespring.com

geek, punk, pussy …

Of Function Scope and Lexical Scoping

Initially I meant to write an article entitled “Dirty looping in JavaScript”. The tagline of this soon to be written article was the following:

Due to Lexical Scoping and the way variables are declared and assigned values in JavaScript we have to be a bit careful when using loops.

As I was writing about loops in JavaScript I noticed that the problem was rather with Function Scope than with Lexical Scoping. And not being sure what the exact difference between Function Scope and Lexical Scoping was, I dropped my initial article in order to ask (and hopefully answer) the following questions:

What is Lexical Scoping? And how does it relate to Function Scope?

To me, Scoping is the ruleset used to lookup variable values. Especially the ones that are not declared within the current Scope. Only when you exactly know how Scoping works in your language, can you be sure about the value a variable has at any given place in your code. It is very important to understand how this is implemented in your language of choice.

Wikipedia defines Scope as follows:

Typically, scope is used to define the extent of information hiding—that is, the visibility or accessibility of variables from different parts of the program.

In JavaScript we have Function Scope and Lexical Scoping.

Function Scope means that any variable which is defined within a function is visible within that entire function. This is quite different form Block Scope, in which a variable scope is limited by the block a variable is declared in. A block is usually what you find between {curly braces} or loop variables. Block Scope is used in most of the programming languages that are currently popular. Think of a for(;;){} loop:

var i = 1;
for (var i = 0; i<10; i++){}
alert(i);
// block scope    -> 1
// function scope -> 10

Pretty simple, right. Now we know what Function Scope is. But what is Lexical Scoping?

Lexical Scoping defines how variable names are resolved in nested functions. Other names of Lexical Scoping are Static Scoping or Closure. It means that the scope of an inner function contains the scope of a parent function. Let’s have a look at the following example:

var text = 'Look at me';

var parent_function = function () {

  var inner_function = function () {
    var scream = '!!!';
    alert(text + ', ' + reason + scream);
  }
 
  var reason = "I'm an attention whore";
  var scream = '!';
 
  alert(text + scream);
  inner_function();
};

parent_function();
// alerts the two following strings, in this order:
// "Look at me!"
// "Look at me, I'm an attention whore!!!"

Look at what happens when the inner_function is called. It needs to alert all three of the following variables: text, reason and scream.

The first variable that needs to be looked up is text. This variable is neither declared in the scope of the inner_function nor in the scope of parent_function. So it takes the globally declared text.

The second variable the alert() in the inner_function needs is reason. This variable is not declared within the inner_function. Hence it is looked for in the enclosing parent_function scope where it finds the truth about my nature. "I'm an attention whore".

The 3rd variable inner_function needs to alert() is scream. It is declared within inner_function and parent_function. The alert is called in the scope of inner_function, hence it is resolved to '!!!'.

That’s almost all you have to know about Lexical Scoping. The scope of an inner function contains the scope of a parent function.

If you bare with me for a little more, you will know it all. There is a little more to it, and that little more is what makes Lexical Scoping so powerful: inner functions contain the scope of parent functions even if the parent function has returned.

Let’s look at the following example:

var adder = function (total) {

  // the following function is returned
  // and assigned to adder
  var inner_function = function (summand) {
    total += summand;
    alert(total);
  }
 
  return inner_function;
 
}(0); // <- we call the annonymous function
      //    and assign the returned function to adder

adder(2); // -> 2
adder(3); // -> 5

This is possible, because in JavaScript functions are first class objects. That means that you can pass functions as arguments or they can be returned from a function. They can also be assigned to a variable or stored in an object. Anyway, the inner_function that is returned is assigned to the variable adder. And when you call adder, that is the inner_function, it has access to total due to Lexical Scoping, even though the function that had the total. total itself was declared in the scope of a function that has returned a long time ago.

Get it? How sexy is that? Simple yet beautiful!

And that’s it. You know everything there is to know about Lexical Scoping: inner functions contain the scope of parent functions even if the parent function has returned.

Tags: , ,

6 Responses to “Of Function Scope and Lexical Scoping”

  1. Yoan says:

    Played with __parent__ already? http://liip.to/__parent__

  2. That’s super cool. It’s cool to try these examples just in the chrome debugger. I guess scoping is how jQuery does all its chaining stuff. I always wondered how that worked. Despite actionscript’s similarities I don’t think it has this type of scoping built in(at least in AS3). Thanks for the run down.

  3. Daniel says:

    JavaScript doesn’t have block scope, the only way to declare new scope is with function or the `let` keyword. In your `for` loop example, you re-declare the var i which is the same as the one declared above it.

  4. Jakob says:

    Thank you for this article, it helped me a lot!

  5. Eden says:

    Let’s do a little thought experiment:

    Imagine a language (it doesn’t matter whether or not such a language exists) that provides for the scope of an inner function to encompass the scope of its outer function BUT, by whatever means, DOES NOT provide for that inner function still to have access to the outer scope once the outer function has returned.

    In that case, you would have Lexical Scoping but not Closure.

    For this reason, I contend that, whereas “Lexical Scoping” is synonymous with “Static Scoping”, neither term is synonymous with “Closure”, however, Lexical/Static Scoping is a PREREQUISITE for Closure.

  6. Michael says:

    Your explanation worked perfectly for me.
    Thx!!