Javascript: Scope and Learning Something New Everyday.

Course for me it doesn’t take much to learn something new, but let’s not get into that.

So pop quiz, and one that doesn’t involve a hostage and shooting.

jQuery(document).ready
(
  function()
  {
    for(var loopCounter = 0; loopCounter < 3; loopCounter++)
    {
      var tempThing = loopCounter;
      alert('in' + tempThing); 

      jQuery(".someButton").click
      (
        function()
        {
          alert('out' + tempThing);
        }
      );
    }
  }
);
....
  <button class="someButton">click!</button>

What happens when you click that button? Well for one it will alert three times but what will it print out?

The first alert (in the loop) does what you would expect. It gives 0, 1, 2. But what about the button click? Well that’s a little different. It gives 2, 2, 2… Wait what? The f— is that? That makes no real sense.

Given that this was C#, it would output 0, 1, 2 because we would know that every loop the tempThing field is a new field. Sure it has the same name in code, but every iteration would create a new space in memory for a new tempThing. And then with closures, a reference would be made to that tempThing so that when the method actually runs, the values are what they should be. Javascript does something a little different. Go figure, right? Can’t do anything like anyone else… anyone else being C#.

Now what does happen is it does give you the correct value of tempThing. What you didn’t know (Assuming you didn’t know because if you are reading this you either are really bored or don’t know… or both) is that tempThing is global to that method. Turns out variables are global to the current scope no matter if in a loop or not. tempThing, no matter where in that function is created/instantiated/ect is the same tempThing through out the method. So what’s happening is that the first time in the loop it’s being created and every iteration after it’s just being updated with the current loopCounter value.

How do you solve this? Well you have to make a method to create a method to set the value. AWESOME!!111

jQuery(document).ready
(
  function()
  {
    for(var loopCounter = 0; loopCounter < 3; loopCounter++)
    {
      alert('in' + tempThing); 

      jQuery(".someButton").click
      (
        createReturnMethod(loopCounter)
      );
    }
  }

);

//This is used to create a new method scope so that
//tempThing is unique to each call.
function createReturnMethod(loopCounter)
{
  var tempThing = loopCounter;

  return function(event)
  {
    alert('out' + tempThing);
  };
}

As you can see, I created a method to create a method to be run on click. Because tempThing is now in the second method’s scope, it will be different for every time this method is called. Magic!

Here’s a thought, if only you can prevent forest fires then you really should get on that. People have lost a lot of money because of your slacking.