“let” Is The New “var”

ECMAScript 2015 introduced a new way to declare a variable: let.

var foo = 'bar'; // ye olde variable declaration
let herp = 'derp' // new hotness (hot newness?)

Why did we need a new way to declare variables? This seems really strange until you know the reason, at which point you’ll probably never want to use var again.

The reason is that Javascript variable scope was weird: When you declare a variable with var, its scope is the enclosing function, not the enclosing block.

An example can help:

function getCustomerNames(customers) {
  var names = [];

  for (var c = 0; c < customers.length; c++) {
    var fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

The scope of the variables c and fullName here is the function getCustomerNames, not the blocks in which those things are contained. Those variables can be seen outside of the for loop in which they’re defined. They enter scope before the loop even runs!

The function really runs as if I had written things this way:

function getCustomerNames(customers) {
  var names = [],
      c,
      fullName;

  for (c = 0; c < customers.length; c++) {
    fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

Function scope can create some sneaky bugs, especially for experienced programmers who’re new to JS. Those folks would be inclined to assume that JS scoping is block-centric, like C/C++/C#/Java.

In fact, some Javascript folks recommended writing all your var declarations at the top of a function, to reflect their actual scope.

let introduces block scoping to Javascript. If I change the var statements to let statements in my original example:

function getCustomerNames(customers) {
  let names = [];

  for (let c = 0; c < customers.length; c++) {
    let fullName = c.firstName + ' ' + c.lastName;
    names.push(fullName);
  }

  return names;
}

The scopes of c and fullName are now their containing blocks, not the whole function. Those variables aren’t visible outside the for loop. The code operates as a C-family programmer would likely expect it to.

But why did we need a new thing? Why not just fix var? Because changing how var works would break a lot of existing code. Introducing let as an alternative allows new code to use block-scoped variables while leaving legacy code working as it has.