When to use `const`, `let` and `var`

What it used to be like (Var)

Before the introduction of ES6 code like this was perfectly common:

var animalType = 'dog';
var animalName = 'fido';

console.log('Your animal, ' + animalType + ', is called ' + animalName);

Which if you were lucky would return "Your animal, dog, is called fido". (In good old Internet Explorer it'd probably say something like can not call log of undefined).

But this was somewhat problematic when it came to how they were scoped, how they can be redeclared and something called hoisting.

Let me quickly explain what I mean by hoisting because I feel that it's name doesn't do it justice.

Imagine you're playing with a deck of cards, and you want to sort them in a specific order. Hoisting is like your friend who helps you sort the cards by first picking all the numbered cards (variables) and placing them at the top of the deck. But, instead of writing the numbers on the cards, your friend just leaves them blank (undefined). As you go through the deck, you'll write the numbers on the blank cards when you reach their original position.

In JavaScript, hoisting is when the program takes all the variable declarations (like the numbered cards) and moves them to the top of their scope (beginning of the deck). However, it only moves the declarations, not the actual values (leaving the cards blank). So, when you come across a variable in your code, it's already been declared (the card is in place), but it might not have a value yet (the card is still blank). This can sometimes cause confusion or unexpected results. That's why it's important to be aware of hoisting when you're writing code.

When using var you can do this:

console.log(myVar); // This will output undefined
var myVar = 'foo';
console.log(myVar); // This will output foo

No error will be returned though, JavaScript will only tell you that the value was undefined. (Not true with let and const!)

The key points to keep in mind with var is that they are:

  • Scoped in the function scope.
  • Can be redeclared.

If I wanted to with var I could do this:

var myVar = 1;
var myVar = {'name': 'fido'};
var myVar = ['1', 2, 4];

And it'll all work fine and dandy. Needless to say though that this is incredibly confusing to understand - especially in a larger codebase.

Scoping is also an issue here as the variable is scoped to the function.

function greet() {
  var message = "Hello!";
  console.log(message); // Output: Hello!
}

greet();
console.log(message); // Error: message is not defined

This is fine, but what if you have a loop or a conditional in there? The scope gets murky.

Debugging a codebase like this often results in these sort of situations:

A very angry person using a computer that is on fire

Which is simultaneously bad for your health, your project's health and your computer's health.

Which brings us to the introduction of let and const.

Const and Let

Since about 2015 we've been able to use these keywords to provide more clarity and predictability to our variable declarations.

What they both have in common is that they are now block scoped, which means that:

if(true) {
    const foo = 'bar';
    console.log(foo); // Outputs bar
}

console.log(foo); // foo is not defined

A block is like a loop, a conditional or a function.

It's especially handy for loops where you'd like to confine that variable inside that block of code.

But what's the difference?

When to use let and when to use const

The main difference between let and const is that you can change the value of let once it's been declared. You can't do that with const.

So this works:

let favouriteColour = 'blue';

function whatsMyFavouriteColour() {
    console.log(favouriteColour);
}

whatsMyFavouriteColour(); // blue.
favouriteColour = 'green';
whatsMyFavouriteColour(); // green.

Where as this:

const favouriteKid = 'Marley';

function whatsMyFavouriteChild() {
    console.log(favouriteKid);
}

whatsMyFavouriteChild(); // Marley.
favouriteKid = 'Carbuncle'; // TypeError: Assignment to constant variable.
whatsMyFavouriteChild(); // We don't get here.

So there are three points of learning here:

  1. You can change your mind with let.
  2. You can't change your mind with const.
  3. You really shouldn't have a favourite child (you horrible person).

I tend to always use const and if I really really want to change the value then I'll change it to let. To be honest though I view that decision with suspicion as it's probably a code smell (you should too).

Hope this helps!