AppDevRocks

January 21, 2019 in

ES6: Defining Variables (let, const)

With the release of ES6 (or ES2015, whichever you prefer) in 2015, we were given two new ways to define variables: let and const. To understand what value these provide, we'll take a look at the original way to define variables with var and its problems, then we can see how let and const overcome these.

Defining variables with var

Since the beginning of JavaScript, var has been the standard way to declare variables. Let's look at some of the strange behaviors you might have encountered when using var.

Variable Hoisting

Variable hoisting is an interesting behavior in JavaScript which you've probably run into without even realizing. Take a look at this:

console.log(myName); // this should produce an error, right?
var myName = "Nick"; // …since the variable is declared after

You'd probably expect that console.log(myName) to throw an error (since it's defined after), but what you actually get is undefined (the same as if you'd defined the variable without a value.) Here's how the code is actually executed, using variable hoisting:

var myName; // the declaration is moved to the top
console.log(myName);
myName = "Nick"; // …but the assignment stays where it was

Block-Scoping (or Lack of)

A "block" in JavaScript is any code inside of curly braces ({}). Let's take a look at how var behaves within blocks:

var height = 1080,
    isPortrait = true;

if (isPortrait) {
  var height = 1920;
  console.log(height); // this prints 1920
}

console.log(height); // this also prints 1920

You might have expected the last console.log(height) to produce 1080, since we're redefining height inside of the block and the console.log is outside of the if block. At least the variable declaration inside of the if block should have thrown an error since that variable was already defined. However, because var isn't block-scoped, it will refer to the variable defined outside of the block even when referenced inside the block. Additionally, JavaScript will ignore if you try to redeclare the variable.

Defining variables with let

Now, let's explore how let can help us overcome some of the issues associated with using var.

No More Hoisting

Unlike with var, the hoisting behavior doesn't happen with let. This leads to more logical and predictable code:

console.log(myName); // now, this throws an error
let myName = "Nick"; // …since the variable is declared after

This forces us to declare our variables first, before attempting to use them:

let myName = "Nick"; // declare our variable first
console.log(myName); // now, we can access it

Temporal Dead Zone

Remember back when we looked at hoisting with var? The variable declarations were always moved to the top, while the value assignments stayed where they are. Since we don't have that now with let, we're left with an area of code before the variable declaration known as a "Temporal Dead Zone":

/*
Any area of code before the declaration of the variable
is a "temporal dead zone" in reference to that variable.
In other words, that variable doesn't exist here.
*/
let myName = "Nick"; // oh good, we're out of the temporal dead zone

In reality, it's just a big name for a super-simple concept: you can't access a variable until you define it.

Real Block-Scoping

As you saw with var, it completely ignores when we try to redeclare a variable inside of a block, but watch what happens with let:

let height = 1080,
    isPortrait = true;

if (isPortrait) {
  let height = 1920; // variable is scoped to this block
  console.log(height); // this prints 1920
}

console.log(height); // we're out of the block, this prints 1080

This strict behavior of let leads to more predictable, more readable, and easier to debug code, by avoiding the forgiving behavior of defining variables with var.

Defining variables with const

const has all the same characteristics of let, but with one main difference: you can't reassign its value. However, as we'll see below, its value can still change, under certain circumstances.

Is it Really Constant?

This name seems to suggest that when you define a variable with const you'll have an unchangable, constant value (like in other languages), but as you work with const, you'll find that isn't always the case.

What const does is prevent you from reassigning the value (or reference) of the variable. If you use a primitive, like a string or a number, any changes to this value actually causes JavaScript to create a new value and reassign the reference.

const systemName = "Nintendo Entertainment System",
    releaseDate = 1985;

// let's try to "reassign" these values

systemName = "Sega Genesis" // this will throw an error
releaseDate = 1989 // …and this will too

However, when you're working with objects (remember arrays and functions are objects too), which are reference-based, you'll find that as long as you don't reassign the variable, you can still make changes to the properties.

const system = {
  name: "Nintendo Entertainment System",
  releaseDate: 1985,
};

// let's try to "reassign" the properties of our variable

system.name = "Sega Genesis" // totally acceptable
system.releaseDate = 1989 // …and so is this

/*
Our "system" object now looks like this:
{
  name: "Sega Genesis",
  releaseDate = 1989,
}
*/

As you can see, we can change the properties of an object, since we're not reassigning (or repointing) the variable; it's still referring to the same place in memory. Just to dig in a little more, let's try to reassign the object:

const system = {
  name: "Nintendo Entertainment System",
  releaseDate: 1985,
};

// What happens if we try to reassign the object as a whole?

// this will totally throw an error…
system = {
  name: "Sega Genesis",
  releaseDate: 1989,
}

This behavior is something you'll want to be aware as you're working with const. You might expect an object's values to be the same as when you declared them, and be surprised when they're not.

So… Which One Should I Use?

My rule of thumb: always use const, unless you absolutely need to change the value, then use let, but never use var. I've read about some use cases where using var would be beneficial, but I believe the downsides to using var far outweigh any potential benefit. Using let and const exclusively will give you more stable code and help prevent a lot of unexpected side-effects.


Continue the Discussion

© 2020 Nick Gagne. All rights reserved.