Var vs Let in Javascript

So recently I've been updating my javascript skills with a little node action and I came across the a few things that I hadn't noticed before in javascript. Both of these revolve around the let keyword and the var keyword.

The Deal With var

Everyone knows you should put var in front of your keywords when doing javascript. I mean it's basically folk wisdom at this point. I mean you just do it right?

What I found out is what it actually does, is this: what the compiler actually does is put the variable at the top of the function scope

Here's an example:

var awesome, things

for (var i=0; i < 10; i++){
  \tvar lessThanawesome = i * 5 
    console.log(i, lessThanAwesome)

If you were to actually run this code, you'd get this strange error

Uncaught ReferenceError: lessThanAwesome is not defined

The issue is with your variable assignment. var is hoisted to the top of the scope (outside your for loop) and is initialized before var i is assigned. ... which leads to our awkward error.

Fix it with es5

If we wanted to fix this, we would need to initialeze the lessThanAwesome variable outside the scope and then use it inside the loop.

var awesome, things, somewhatMoreAwesome

for (var i=0; i < 10; i++){
  \tvar somewhatMoreAwesome = i * 5 
    console.log(i, somewhatMoreAwesome)

Getting Let Down

So var can be a bit unexpected. But new in ES6, there is now the ability to have variables that are scoped to the block. If you want to do that, you need to let var go and get in with let.

Here's the following code with the new let syntax:

var awesome, things, awesome

for (var i=0; i < 10; i++){
  \tvar awesome = i * 5 
    console.log(i, awesome)

Caveat Emptor

There are a few other differences to watch for when using the fancy new let keyword.

can't let this go

First, if you use let at the top level of a function, it will not not create a property on the global object. What this means is that you will not be able to access this.var.

Consider the following example (borrowed from MDN):

var x = 'global';
let y = 'global';
console.log(this.x); // returns 'global'
console.log(this.y); // returns undefined

Temporal Deadzones

let won't allow you to define the same variable twice in the same scope.

if (x) {
    let foo;
  let foo; // TypeError thrown.

This means that switch statements will get angry as well, since there is only 1 underlying scope for the block

switch (x) {
    case 0:
    let foo;
  case 1:
    let foo; // TypeError for redeclaration.