Well, in this blog, we will illustrate the differences between var
, let
and const
. We'll also discuss why we should avoid var
and prefer const
.
In ES5, we had only one way of declaring variables using var
. But with ES6 we now have three to declare a variable namely var
, let
and const
.
1. var
Firstly let us see how var
works:
for (var i = 0; i < 10; i++) {
console.log(i);
}
In most programming languages, the scope of i
will be inside the body of loop
only. The value of i
can be accessible within the body of for loop
.
Let us see what happens if we console the value of variable i
after the loop.
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log("After loop ", i); //This prints 10. 😳 Why is that?
We can see that we are able to access the variable i
even outside the loop
, which is very intuitive when coming from another programming language. No one would expect the variable i
to survive outside the loop
.
Why does that happen🤔? The reason is that there is only one type of variable scope in ES5, which is a function scope.
To illustrate the above statement, let us wrap the above code inside a function and execute the function.
function counter() {
for (var i = 0; i < 10; i++) {
console.log(i);
}
console.log("After loop ", i); //still prints 10 🤥
}
counter();
Let us move the console.log() to outside of the loop and see what happens.
function counter() {
for (var i = 0; i < 10; i++) {
console.log(i);
}
}
console.log("After loop ", i); //It throws an error this time: Reference error: i is not defined. 🤤
counter();
This time it throws an error Refrence error: i is not defined
and it is because the scope of var
is within the f unction scope . The variable i
will be available only within the function counter and if called from outside the function it will throws and error.
In order to avoid this type of error, Some developers used the concept of Immediately Invoked Function Expression (IIFE).
This is how IIFE looks like.
(function () {
for (var i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log("After loop ", i);
Most of the Javascript developer does not know about IIFE.
IIFE is a function that is declared and called immediately.
People do this to keep the variables that are inside the IIFE to pollute the rest of the code. It creates lots of cohesive block of safe-heaven.
Javascript variables are hoisted
What do Javascript variables are hoisted
means?
Well, it means that they are hoisted to the top of their function.
What Javascript compiler or interpreter does is it will go through the code, and it will find variable declaration and push them up to the top of the function.
70% of javascript developers do not know the concept of hoisting.
Upon compiling the below code it still works. A the variable i
of for loop
is hoisted to top of the function.
(function () {
var i; //It pushes the variable to top of the function.
for (i = 0; i < 10; i++) {
console.log(i);
}
})();
Keep note it doesn't matter how many lines of code are there in between, it will still move the variable declaration to the top of the function.
There is also a horrible aspect of hoisting. Let's say you forgot the variable declaration. as shown in below code
(function () {
for (i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log("After loop ", i); // This prints 10. What the heck just happened??😧
Why does it prints 10
? This happened because the javascript interpreter has put the variable declaration out of the function this time.
If there is no variable declaration inside a function the interpreter will keep going up the function chain all upto global/window object. And then if it finds it then it will place the variable in the global/window object.
var i;
(function () {
for (i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log("After loop ", i);
-
This is of course horrible because you can accidently declare a global variables.
-
This is why we are encouraged to always use
use strict
statement, it prevents us from accidentally declaring a global variable.
"use strict";
(function () {
for (i = 0; i < 10; i++) {
console.log(i);
}
})();
console.log("After loop ", i);
This time the above code will throw an error RefrenceError: i is not defined.
"use strict";
var i = 9999;
(function () {
for (var i = 0; i < 10; i++) {
console.log(i); // this prints 1 2 ...10
}
})();
console.log("After loop ", i); // This prints 9999
Even though we are using the same variable name, it prints 9999 because the inner var i = 0
is scoped to the function only.
This time let's remove var from inside the function and see what happens
"use strict";
var i = 9999;
(function () {
for (i = 0; i < 10; i++) {
console.log(i); // this prints 1 2 ...10
}
})();
console.log("After loop ", i); // This prints 10
It prints 10, this is because i
inside function is reassigning the outside variable i
. As mentioned above it will check if variable i
is defined in function, if it doesn't found it then it will move up to the global/window. As it finds the variable i
then it will be re-assigned. That is the reason why it is logging out 10.
Always remember the concept of hoisting. Hoisting is nothing but moving the variable declaration to the top of the function or global/window object.
2. let
Now let us demonstrate the same example using let
.
"use strict";
var i = 9999;
for (let i = 0; i < 10; i++) {
console.log(i);
}
console.log("After for loop", i); // This prints 9999. It works.
We can see from the example code above that let
is not behaving like var
. And the above code works as expected.
The reason why it worked is that let
introduces block scoping
. The variable let i = 0
of for loop
will be available only inside the body of for loop
.
The block scoping of let
is also valid for if/else, switch etc.
"use strict";
var i = 9999;
for (let i = 0; i < 10; i++) {
console.log(i);
}
if (true) {
let i = 1000;
}
console.log("After for and if", i); // This still prints 9999.
From the code snippet we can see that the the scope of variable i
is scoped with in for loop
and if
respectively.
Just like var
we can re-assign let.
let i = 10;
i = 57;
console.log(i); // Prints 57
let
is block scope whilevar
is function scope.
A lot of people say that let
is the new var
and I agree with that.
3. const
const
is a variable just like let
which cannot be re-assigned. To demonstrate this, let me show you an example.
const i = 10;
i = 57;
console.log(i);
The code above throws an error TypeError: Assignment to constant variable.
Let's look at an example below
const x = {
y: 10,
};
x.y = 15;
console.log(x); // Prints {y: 15}
We can see that we are able to update the property of x
. Now let us try to assign a new object to constant variable x
.
const x = {
y: 10,
};
x = { z: 11 };
console.log(x); // This time it throws an error
The code snippet above throws an error because we are re-assigning a constant variable.
var vs let vs const
Whole blog summarized in a table.
Scopes | var | let | const |
---|---|---|---|
Stored in global scope | true |
false |
false |
Function Scope | true |
true |
true |
Block Scope | false |
true |
true |
Can be re-assigned | true |
true |
false |
Can be re-declared | true |
false |
false |
Can be hoisted | true |
false |
false |
Conclusion
- Always use
const
if you do not want to change the variable.- Whenever you are using
let
first ask yourself if you are really changing the variable or do you really need to change it. If the answer is yes then uselet
else useconst
.- Always use 'const'. If you REALLY need to change state, use 'let'. 'var' is dead.
var
should always be avoided because of hoisting.
In this blog we have learnt about
- Why to avoid
var
. - What
hoisting
in javascript is. - What Immediately Invoked Function Expression (IIFE) is and how to use it.
- How to decide between using let and const.
💌 If you’d like to receive more tutorials in your inbox, you can sign up for the newsletter here.
Discussions