MPJ has a great video over at funfunfunction on var, let, and const. I wanted to explore his examples further with the help of the PythonTutor.com website which allows us to step through code execution in the JavaScript interpreter to further visualize what’s really happening.

EC5 and EC6

In EC5 and all earlier versions of JavaScript, there was only one variable type: var. But with EC6 we now have two additional variables types, let and const, which improve things greatly.

So what’s wrong with var? The main issues are:

  • it is function scoped
  • because of hoisting in JavaScript function and variable declarations are “hoisted” to the top of the scope before the JavaScript interpreter runs the rest of your code, which leads to unintended results.

Take for example a simple for loop that counts from 0-2:

for (var i = 0; i < 3; i++) {
  console.log(i)
}
/* Output:
0
1
2
*/

What happens when we add a statement after the loop?

for (var i = 0; i < 3; i++) {
  console.log(i)
}
console.log('after loop', i)
/* Output:
0
1
2
after loop 3
*/

Wat?! In most programming languages, i would be scoped to just the for loop and would not be available outside of it. But in JavaScript, var only has one scope: function scope.

If we use the awesome PythonTutor.com website, we can step through the JavaScript interpreter and understand what’s really happening here.

Click the Back and Forward buttons through the 12 steps and notice that there’s only one Global frame and scope. i is available everywhere.

To prove that var is function scoped, let’s make our for loop a function and see what happens:

function counter() {
  for (var i = 0; i < 3; i++) {
    console.log(i)
  }
  console.log('after loop', i)
}
counter()
/* Output:
0
1
2
*/

Nothing has changed because everything is still within our counter function. But what if we move the 'after loop' console.log statement outside of the function:

function counter() {
  for (var i = 0; i < 3; i++) {
    console.log(i)
  }
}
counter()
console.log('after loop', i)
/* Output:
ReferenceError: i is not defined
*/

The variable scope for i is just the function counter. When we try to access it in our ‘after loop’ the JavaScript interpreter complains.

Step through the example below to see what happens after the last step:

As a result of behavior like this, JavaScript programmers have historically used IIFE’s (Immediately-invoked function expression) to execute code within its own scope. There is also good description of IIFE’s over on Stack Overflow.