Var vs Let vs Const In Javascript

Someone entering the world of javascript for the first time may be confused about the 3 different ways to define variables. var, let and const all seem to do roughly the same thing, so which one is actually correct to use? And why do we have all 3 in the first place?!

I wanted to write this guide as a really simple way to understand all 3, without having to read through RFC’s or really get into the nitty gritty as there’s actually a very simple explanation for which ones to use (And the one to not use!).

Pre 2015

You may be interested to know that before 2015, there was only the keyword “var” in javascript to define variables. I do want to add that in some transpilers, such as Coffeescript or early Typescript, there were different ways to define variables that didn’t strictly involve using the keyword “var”. But by the time they were compiled down to javascript, they themselves were using var under the hood anyway.

In 2015, ES6 was released and we were introduced to let and const in plain javascript. What I mean by “plain” javascript is that using the keyword let or const in a browser without something like typescript/coffeescript or a transpiler like Babel was a-ok.

Var Pitfalls

So now that we know let and const were introduced in 2015, the question becomes why they were even needed? Well let’s look at some examples.

var myVariable = "ABC";
var myVariable = 123;

Any beginner programmer will likely look at the above and think “Well, you’ve re-used the same variable twice, that should be an error. Then no less, the first time you used it, it was a string, then the second time an integer, so double errors please!”. And you would be wrong.

Var in Javascript allows you to re-use the same variable name twice, without an issue. On top of this, it allows you to assign different types to the same variable without a hitch. The latter is maybe not so much of a problem if you’re coming from something like PHP that allows similar problems, but the former is a big problem.

Let’s look at another problem.

myVariable = 5;
console.log(myVariable);
var myVariable;

You may think that this code is going to have big problems. I’m trying to use a variable before I’ve even declared it. But again, Javascript needs to be special with a feature called “hoisting”. What it means is that a javascript variable declaration is always “hoisted” to the top of it’s scope and can be used before it’s even been declared. This can lead to very unintended consequences and confusing behaviour.

As an example :

var myVariable = 5;
if(myVariable == 1)
{
    var myVariable = 2;
}
console.log(myVariable);

What will this example print? You may think it will print 5. As the initial declaration sets myVariable to 5, then only if it’s 1 will it enter the next block of code. But again, because Javascript hoists the inner declaration, this example will actually print 2.

Another example may look like so :

for (var i = 0; i < 5; i++){
  console.log(i);
}
console.log(i); //We might expect this to errors!

What we would expect in most other languages is that the second log would error because the variable declaration is within the loop. Incorrect! Hoisting again pulls the declaration to the top of the scope.

What you’ll find is that the mix of hoisting and being able to override existing declarations in Javascript without issue can often lead to very difficult to find bugs in code.

Using let

And of course, that’s where the keyword “let” comes in.

This now becomes an error :

let myVariable = "ABC";
let myVariable = 123;

But it’s important to note that this does not error even though we are changing the variable type :

let myVariable = "ABC";
myVariable = 123;

let is also scoped to (generally) be unique within curly braces. As an example :

for (let i = 0; i < 5; i++){
  console.log(i);
}
console.log(i);//Throws an error as I is not defined

I would note that using the let keyword gives you this sort of “optional” cascading affect where you can override in a child scope, without affecting the parent. As an example :

let i =1;
if(i < 5) {
	console.log(i);
}
console.log(i);

This prints “1 1” as the variable i was available inside the child scope.

However this code also has no problem compiling

let i =1;
if(i < 5) {
	let i = 2; //new line
	console.log(i);
}
console.log(i);

This prints “2 1”. Where the second initialization of i is set to 2 and printed, but it doesn’t affect the parent i.

In essence, let gives us plenty of the flexibility of var, but without the hoisting and without being able to re-declare a variable with the same name in the same scope.

Using const

Const has many of the same restrictions as the let keyword, but with a few more added on for good measure.

The const keyword does not allow you to re-assign a value to it, even if it’s the same type.

const myVariable = "ABC";
myVariable = "XYZ";//Error

Because of this, you also can’t define a const variable without assigning a value to it.

let myVariable; //No problem
const myConstVariable;//Error

Our example earlier where we were able to re declare a let variable inside a child scope also doesn’t work with const.

const i =1;
if(i < 5) {
	const i = 2; //error
	console.log(i);
}
console.log(i);

In this case, const is actually available in child scopes also, but it is not able to be “re-declared”.

Const is the most restrictive variable declaration type, but it allows us to be certain that after being declared, the value will never change.

So Which Should I Use?

Generally speaking, you should not be using var unless in extreme circumstances where you actually want hoisting (read : never).

So the choice comes down to let or const. Use const if you want to ensure that the value will never change. In general, it’s worth getting in the habit of using const as your default declaration as 9 times out of 10, the value actually won’t change. Then, only when you run into a roadblock where the value may actually need to be changed, switch the declaration to let.

Leave a Reply

Your email address will not be published. Required fields are marked *