Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Reading time: 30 minutes | Coding time: 10 minutes
Either you have started learning Javascript or working with it for sometime, you must have came across the term hoisting.
Hoisting is a behaviour in JavaScript in which all variable and function declarations are moved to the top of the code which results in certain code behaviour which we will understand in detail in this article.
Lets look at an example. In this we will create a function and then call it.
function greet(name) {
console.log('Hey, '+name);
}
greet('Saksham');
As expected when we call our greet
function, passing a string 'Saksham'
. We will get the message logged on to the console.
Hey, Saksham
But what will happen if we call our function before we actually declare it ?
greet('OpenGenus');
function greet(name) {
console.log("Hey, "+name);
}
Surprisingly, Hey, OpenGenus
is logged to the console.
Hey, OpenGenus
This happens because of Hoisting.
So basically what is happening here ?
Generally, people explain hoisting as variable and function declarations being moved to the top of your code.
While this is what appears to be happening, but this is not in fact what happens. It's important to understand exactly what is going on because one thing for sure code does not move from its position. There is no magic which takes your code to the top of the file.
What actually happens is that our function and variable declarations are added to the memory during the compile phase.
In the above example, because our function declaration was added to the memory during compile time, we're able to access and use it.
Lets look an example for variables.
Usually we declare a variable, initialize it and then attempt to use it.
var a = 10;
console.log(a);
// 10
This gives a normal expected output 10
.
But what if we declare our variable at the bottom of our code ?
a = 10;
console.log(a);
var a;
// 10
It still outputs 10. Okay, lets do one more variation.
This time we declare and initialize our variable after the console.log
line and lets see what happens.
console.log(a)
var a = 10;
// undefined
Finally, we did it, we broke the expected outcome. We expected 10
but this time we got undefined
.
but Why ?
Because Javascript only hoists declarations.
Initializations are not hoisted
If we declare and initialize a variable, say var a = 10;
, only the var a;
portion (the declaration) is going to be hoisted. The a = 10;
(the initialization) is not hoisted and therefore not added to memory.
In one the examples above, when we declare a variable but don't initialize it, the variable is automatically set as undefined
. So lets look back at our final example. In the code below, only the var a;
will be hoisted:
console.log(a)
var a = 10;
// undefined
Actually, the above code gives same result as writing it like this:
var a;
console.log(a)
a = 10;
// undefined
It still as expected outputs undefined
.
ES5
A variable declared with the help of var
keyword gets one of the two types of scope:
- functional scope
- global scope
Global scoped variables
Lets see how global scoped variables behave-
console.log(a)
var a = 10;
// undefined
This example as we know outputs undefined
.
And we know that var a;
gets hoisted and behaves likes this-
var a;
console.log(a)
a = 10;
// undefined
Function scoped variables
From what we have understood till now, variables within a global scope are hoisted to the top of the scope. Now let's look at how function scoped variables are hoisted.
function result() {
console.log(a)
var a = 10;
}
result();
As you have guessed, the output again is undefined
. This is the way it looks for interpreter-
function result() {
var a;
console.log(a)
a = 10;
}
result();
as you can see a
is inside a function scope, so it is hoisted inside the function itself instead of very start of the code.
ES6
ES6 also known as ECMAScript 2015 brought some changes to ES5. Two new keywords were introduced for declaring variables - let
and const
.
let
Variables which are declared with the help of let
keyword get block scope instead of function scoped. It means that the scope of a variable is the block in which it is declared and not the function in which it is declared.
Let's start by looking at the let
keyword's behavior:
console.log(a);
let a = 10;
Can you guess what will be the output this time?
It gives an error:
// ReferenceError: a is not defined ...
In ES6
we can not use any variable without declaring it and if we try it, it gives an error. This forces us to declare the variable first and then use it.
The following example will output undefined
instead of a Reference error
.
let a;
console.log(a);
a = 10;
const
In ES6 immutable variables
were introduced with the help of const
keyword, Immutable variables are variables whose value cannot be modified once assigned.
With const
, the variable is hoisted to the top of the block similarly as let
does.
Now let's check immutability of variables and see what happens if we try to reassign the value attached to a const
variable.
const MAXVAL = 100;
MAXVAL = 200; // Let's reassign the value of MAXVAL
console.log(MAXVAL);
// Output: TypeError: Assignment to constant variable.
Let's now check how const
affects variable declarations.
console.log(a);
const a = 10;
// ReferenceError: hoist is not defined
Again it outputs Reference error
similar to let
keyword.
The same situation occurs when using const
within functions.
Now, what if we declare a const
and define after using it ? Lets see -
const a;
console.log(a);
a = 10;
// SyntaxError: Missing initializer in const declaration
This shows that a constant variable must be both declared and initialised before using and only once.
The basic crux of this whole explanation is that:
JavaScript hoists any variable which is declared be it with var
,let
or const
. The difference in this case is how it initialises them. Variables declared with let and const remain uninitialised
at the beginning of execution but in case of variables declared with var, they are initialised
with a value of undefined.