Exploring ECMAScript 2015 (ES6): Block-Scoped Variables with let and const

JavaScript has traditionally been function-scoped. That means variables declared with the var keyword are accessible in the body of the function where they are contained. Every time you call a function it introduces a new scope, and variables defined in that scope are accessible. These variables stick around as long as that scope does—until the function finishes executing, and is garbage collected.

function muppet() {  
  var k = 'kermit';

  console.log(k); // 'kermit'
}

console.log(k); // undefined  

When you are new to JavaScript you might come to the intuitive conclusion that variables declared inside an if statement or a for loop would be limited to the scope of their code blocks, but that is not the case.

function muppet() {  
  if (true) {
    var k = 'kermit';

    console.log(k); // 'kermit'
  }

  console.log(k); // 'kermit'

  for (var i = 0; i < 6; i++) {
    console.log(i); // 0, 1, 2, 3, 4, 5
  }

  console.log(i); // 6
}

This happens because var is function-scoped not block-scoped. Variables declared with var will be hoisted to the top of the nearest function, and will remain part of that scope until the function finishes executing.

ECMAScript 2015 introduces the let keyword as a block-scoped alternative to var. Block-scope means the variable only exists within the innermost block—if and switch statements, and for and while loops.

function muppet() {  
  if (true) {
    let k = 'kermit';

    console.log(k); // 'kermit'
  }

  console.log(k); // undefined

  for (let i = 0; i < 6; i++) {
    console.log(i); // 0, 1, 2, 3, 4, 5
  }

  console.log(i); // undefined
}

One thing to note is that variables declared with the let keyword are NOT hoisted according the spec. Best practices have us declaring our variables at the beginning of their respective scope anyway so this shouldn't be much of a problem, but it is something you should be aware of.

Block-scope allows for better organization of our code by declaring variables at the top of their respective block rather than their parent function. This keeps the variable declaration and use closer together so it is easier to understand the context. It also allows garbage collection to collect the variable as soon as the block finishes executing instead of hanging around until the function finishes executing.

ECMAScript 2015 also introduces the const keyword as another way to declare variables. Like let, const is block-scoped. The different between const and both let and var is variables defined with const are read-only constants. This means once a variable has a value assigned with const it can not be changed.

const MUPPET = 'kermit';  
console.log(MUPPET); // 'kermit'

MUPPET = 'gonzo'; // error  
console.log(MUPPET); // 'kermit'  

The spec also says you can not declare a variable with const without assigning a value.

const MUPPET; // error  

Variables declared and assigned with const could be useful when writing JavaScript following the functional programming paradigm. Functional programming has an emphasis on immutability, and const is immutable by its nature.

Going forward, it looks to me like let can be a general replacement for var anywhere ECMAScript 2015 is supported, because block-scope is more intuitive and practical and allows for more performant code. The introduction of const is a great for all read-only variables, and specifically immutable variables used in functional programming.

Further Reading

Tyler Walters

Written by Tyler Walters

Tyler Walters is a software engineer in Phoenix, Arizona. He is married to a beautiful woman and has three incredible daughters. He is interested in game development, writing, beer, and hot wings.