[js] Closures versus Functional Scoping

I was recently asked a very simple JavaScript question: what is a closure?

Of course, I answered it (correctly, might I add) as “it means capturing a variable inside a function”. I was asked for an example, so I said, “Well, first I’d like to show a common mistake of closures when using loops.” I gave the common looping mistake example:

var someArrayOfThings = /* [blah blah blah objects blah blah] */;
for (var i = 0, len = someArrayOfThings.length; i < len; i++) {
   var item = someArrayOfThings[i];
   // some function here to access item
}

There was some huffing about this. Maybe the developer didn’t understand where I was going, or didn’t care. Unfortunately, I wasn’t asked to explain why it would cause an error. I should have given the example from MDN verbatim.

So, this guy gave me the following ‘example’:

var a = 1;
function a() {
  var a = 0;
  test = function() { alert(a); }
  test();
}
a();

Him: What does this do?

Me: Uh… nothing.

Him: No, you’re wrong.

Me: Uh… I’m pretty sure I’m right.

Him: No, I’m sure you’re wrong. This will alert 0. Always.

So sure? Try it yourself.

Why I was right.

  • “Functional scoping” !== “closure”
  • Hoisting redefines ‘a‘ from function to number, not the other way around.
  • Did he mean to define ‘test‘ as a global?

This guy wasn’t even talking about a ‘closure’, he was displaying functional scoping. I can understand the misconception between the two. A ‘closure’ occurs when a function closes the functional chain over some variable available at a greater scope, making that variable look like part of the function.

For instance:

var message = "outside";
var first = function() {
    var message = "inside";
    var second = function() { alert(message); }
    return second();
};
    
first(); // alerts "inside"

View on jsfiddle.net

In this example, the functional scope of the second function has access to the message which holds “inside”. This is exactly the same concept as the developer was getting at. However, just calling the function, as in his example, doesn’t close the outer function chain. Yes, variables captured inside functions will hold the value of the variable at the level of scope of when the function was declared. However, in his example he’s just calling (or he thinks he is, I’ll get to that later) one function to another:

call a -> 
  set local a to zero -> 
    define 'inner function' -> 
      call inner function -> 
        alert a from outer scope

As you can see, there is no ‘capturing’ of any variables. You could just as easily write this up without the added complexity of an inner function.

In my example, the execution goes more like this:

parse first -> 
  create second function -> 
    capture message "inside" -> 
      compile second function to alert("inside") ->
        call newly compiled function

If you’re familiar with C++, this is similar to a function pointer. In C#, it’s almost like a compiled expression. Your function is actually encapsulating the data created by the closure.

Then again, I consider this all common sense about JavaScript.

On to the fundamental incorrectness of the not-mine example

So, I asked, “Both variables and the function are a?” “Yes” “Then, I’m sure it won’t do anything!” (Ok, I just want to drive that home!) Then I said, “If you rename the function, then yes… it will alert 0.”

See for yourself!

Function definition versus function declaration.

Here is an obviously very little known fact about JavaScript. You can declare a function in two general ways in JavaScript:

// function definition
var myFunction = function() { alert("My function!"); }

// function declaration
function myFunction() { alert("My function!"); }

I rarely ever use the second form of declaring a function.

In the function definition (first) example, only the variable is hoisted to the top of the current scope. ‘myFunction’ will always refer to your function. If you reassign myFunction to an integer, it’s an integer. If you’ve previously defined it as an integer and reassign to a function, it’s a function. This is the commonly expected behavior and is why you should declare all of your variables at the top of every function.

In the function declaration example, the entire function is hoisted!! This is done because JavaScript allows you to call methods which haven’t physically been defined yet. So, the code the developer wrote for me and insisted was correct is actually parsed like this by JavaScript standards:

function a() {
  var a = 0;
  test = function() { alert("a");}
  test();
}
var a = 1;
a();

If you don’t believe me, run the first example on jsfiddle and this example. If you look in your browser’s console, you should see the same error for both bits of code. e.g. in Chrome 15:

Uncaught TypeError: number is not a function

As you can see, JavaScript implicitly raises all function declarations to the top of your scope! BE CAREFUL WITH THIS.

In contrast, had this developer written the function in my preferred way, I would have said, “It will alert 0, but you shouldn’t be assigning the function to a global variable!” So, in the future, it’s my way or the highway.

I highly recommend that every developer who writes JavaScript code read JavaScript: The Definitive Guide by David Flanagan. You will learn everything about the language you’ll ever need to know. You’ll learn quirks like the function-hoisting I’ve described here.

Even if you’re like me, and you’ve been using JavaScript since 1998 or 1999, you’ll learn a LOT. I’ll admit, I used to hate JavaScript with a fiery passion. It wasn’t until 2006 or so when jQuery appeared and made JavaScript cool again that I started to really dig into it. Anyway, read the book!

Related Articles