What do you think the output of this function will be?

var mindBoggler = function() {  
  for(var i = 0; i <= 3; i++){
    setTimeout(function(){
      console.log(i);
    }, 1000);
  }
};

mindBoggler();  

You're probably thinking

(1 second)
0  
(1 second)
1  
(1 second)
2  
(1 second)
3  

But the actual output is

(1 second)
4  
4  
4  
4  

How would we fix this to get our desired output?

Lets focus on why it doesn't count correctly first.

The reason for this is that setTimeout gets added to the Javascript Event Loop. This event loop only executes once Javascript finishes its current execution.

By the time Javascript finishes the current script, i is set to 4.

You might think that a way to fix this would be to pass in a variable to the setTimeout function, like so:

var mindBoggler = function() {  
  var log = function(){
      console.log(i);
  };
  for(var i = 0; i <= 3; i++){
    setTimeout(log(i), 1000);
  }
};

mindBoggler();  

Your output would be

0  
1  
2  
3  
(1 second)

But this doesn't actually work, because it calls the function immediately when setTimeout is being invoked!

It doesn't actually wait at all.

What is actually happening: (since log(i) returns undefined)

for(var i = 0; i <= 3; i++){  
  log(i);
  setTimeout(undefined, 1000);
}

Which is not what we want!

So the next logical step is to think, well if the above function returns undefined because we aren't returning anything for it to invoke, why don't we just return another function?

This is basically what a closures is!

By creating a function that returns another function, it will hold on to all varaibles in the outer scope that are being used!

var mindBoggler = function() {  
  var log = function(i){
    return function(){
      console.log(i);
    };
  };
  for(var i = 0; i <= 3; i++){
    setTimeout(log(i), 1000);
  }
};

mindBoggler();  

The output is

(1 second)
0  
1  
2  
3  

but that still doesn't output the time in 1000 second intervals.

That's because the for loop is creating the 4 setTimeout almost instantly in a for loop. A simple way to fix this is to just set the wait ms to 1000*i

var mindBoggler = function() {  
  var log = function(i){
    return function(){
      console.log(i);
    };
  };
  for(var i = 0; i <= 3; i++){
    setTimeout(log(i), 1000*i);
  }
};

mindBoggler();  

The above would output:

(1 second)
0  
(1 second)
1  
(1 second)
2  
(1 second)
3  

But lets refactor our code now that we know how to use closures. Lets also use setInterval instead!

var mindBoggler = function() {

  var log = function(){
    var i = i || 0;

    return function(){
      console.log(i);

      if(i === 3){
        clearInterval(interval);
      }

      i++;
    };
  };

  var logger = log();

  var interval = setInterval(logger, 1000);
};

mindBoggler();  

You can see the closure is created with log() returning a function to logger. Every time the function is called, it increments the var i. Because i is created outside of the returned function, it is a closure!