In this blog, we’ll acquaint how the famed hoisting mechanism occurs in JavaScript. Before we dive in, let’s get to grips with what hoisting
is.
In JavaScript, an important aspect of working with variables
and functions
is hoisting
. If you’re looking for a detailed description of this aspect, then you’re in the right place. Let’s begin.
Hoisting
Hoisting
is a JavaScript mechanism where variables
and function
declarations are moved to the top of their scope before code execution.
Inevitably, this means that no matter where functions
and variables
are declared, they are moved to the top of their scope regardless of whether their scope is global or local.
Note : JavaScript only hoists declarations, not the initializations.
Hoisting variables
ES5 - Var
In ES5, when you declare a variable using the var
keyword, the scope of the variable is global
if you declare it outside of a function or local in case you declare it inside a function.
The following is the JavaScript lifecycle and indicative of the sequence in which variable declaration and initialization occur.
Declaration –> Initialization –> Usage
var myName = 'Mahijendra'
console.log(myName)
// Mahijendra
Pretty straightforward, I declared a variable, initialized some value to it, and then logged it in the console.
Global Variables
According to the above statement, if I were to move my variable declaration to below the console.log()
statement, it should work just fine. But that’s not the scenario. Let’s see why that is.
console.log(myName)
//undefined
var myName='Mahijendra' // myName has been hoisted in this step.
We expected the result of the log to be: ReferenceError: myName is not defined
, but instead, its output is undefined
.
Why has this happened?
JavaScript has hoisted
the variable declaration. This is what the code below looks like to the interpreter:
var myName;
console.log(myName); // Output: undefined
myName="Mahijendra" ;
However, in contrast, assigning a value to an undeclared variable implicitly creates it as a global variable
when the assignment is executed. This means that all undeclared variables are global variables
.
To demonstrate this behavior, have a look at the following:
function example() {
a = 30;
var b = 10;
}
example();
console.log(a);
/*
Accessible as a global variable outside example() function
Output: 30
*/
console.log(b);
/*
Since it was declared, it is confined to the example() function scope.
We can't `console.log() it out outside the example() function.
Output: ReferenceError: b is not defined
*/
The Window Object
The window
object is supported by all browsers. It represents the browser's window.
All global JavaScript objects
, functions
, and variables
automatically become members of the window
object.
Global variables are properties of the window object.
Global functions are methods of the window object.
I'll show you guys an example later on in the below sections of how a window
object is going to work.
Function scoped variables
As we’ve seen above, variables within a global scope are hoisted to the top of the scope. Next, let’s look at how function scoped variables are hoisted.
function john() {
console.log(message);
var message ='Hier to the iron throne!'
}
john();
Take a guess and see what your output might be?
If you guessed, undefined
you’re right. If you didn’t, worry not, we’ll soon try to adapt knowledge in this topic below.
This is how the interpreter views the above code:
function john() {
var message;
console.log(message);
message ='Hier to the iron throne!'
}
john(); // Ouput: undefined
So in the above code, the variable declaration var john
whose scope is in the function john()
, is hoisted to the top of the function.
So to dodge this downfall, we would make sure to declare and initialize the variable before we use it:
function john() {
var John='Hier to the iron throne!';
console.log(message);
}
john(); // Ouput: Hier to the iron throne!
ES6
Let
ES6 provides a new way of declaring a variable by using the let keyword. The let
keyword is similar to the var keyword, except that the variables it declares are block-scoped:
In JavaScript, blocks are denoted by curly braces { } , for example the if-else
, for
, do-while
, while,try-catch
and so on:
if(condition) {
// inside a block
}
See the following example:
let x = 1;
if (x == 1) {
let x = 20;
console.log(x); // 20: reference x inside the block
}
console.log(x); // 1: reference at the begining of the script
Because the let
keyword declares a block-scoped
variable, the x
variable inside the if block is a new variable and it shadows the x
variable declared at the top of the script. Therefore, the value of x
in the console is 20.
When the JavaScript engine completes executing the if block, the x
variable inside the if block is out of scope, therefore, the value of the x
variable that following the if block is 1.
Let’s start by looking at the let
keywords behaviour.
console.log(example); // Output: ReferenceError: hoist is not defined ...
let example = 'champions leauge'; //the variable has been hoisted
Like before, for the var keyword, we expect the output of the log to be undefined. However, since the es6 let doesn’t take kindly on us using undeclared variables, the interpreter explicitly spits out a Reference error.
This ensures that we always declare our variables first.
However, we still have to be careful here. An implementation like the following will result in an ouput of undefined
instead of a Reference error
.
let example;
console.log(example); // Output: undefined
example = 'champions leauge';
Hence, err on the side of caution, we should declare then assign our variables to a value before using them.
JavaScript let and global object
When you declare a global variable using the var
keyword, you are adding that variable to the property list of the global object
. In the case of the web browser, the global object is the window.
See the following example:
var a = 10;
console.log(window.a); // 10
However, when you use the let
keyword to declare a variable, that variable is not attached to the global object as a property. Here is an example:
let b = 20;
console.log(window.b); // undefined
Const
The const
keyword was introduced in es6 to allow immutable variables. That is variables whose value cannot be modified once assigned.
With const
, just as with let, the variable is hoisted to the top of the block.
Let’s see what happens if we try to reassign the value attached to a const
variable.
const a = 3;
a = 2; // Let's reassign the value of a
console.log(a); // Output: TypeError: Assignment to constant variable.
How does const alter variable declaration? Let’s take a look.
console.log(football); // Output: ReferenceError: hoist is not defined
const football = 'champions leauge';
Much like the let
keyword, instead of throwing an undefined
, the interpreter saves us by explicitly throwing a Reference error
.
Hoisting Functions
JavaScript functions
can be classified as the following:
- Function declarations
- Function expressions -Arrow functions
Function declarations
Like variables, the JavaScript engine also hoists the function declarations. It moves the function declarations to the top of the script. For example:
let x = 2,
y = 1;
let result = multiply(x,y);
console.log(result);
function multiply(x, y) {
return x + y;
}
In this example, we called the multiply()
function before defining it. The above code is equivalent to the following when it gets hoisted.
function multiply(a, b){
return a + b;
}
let x = 2,
y = 1;
let result = multiply(x,y);
console.log(result);
Function expressions
Function expressions
, however, are not hoisted
.
let x = 2,
y = 3;
let result = multiply(x,y);
console.log(result);
var multiply = function(x, y) {
return x * y;
}
// output: TypeError: multiply is not a function
As we can see above, the variable declaration var multiply
is hoisted
but it’s an assignment to a function is not. Therefore, the interpreter throws a TypeError
since it sees expression
as a variable
and not a function
.
Arrow Functions
The following example changes the multiply
function expression to the arrow function:
let x = 2,
y = 1;
let result = add(x,y);
console.log(result);
var add = (x, y) => x + y;
// output : TypeError: add is not a function
The code also issues the same error as the function expression example because arrow functions
are syntactic sugar
for defining function expressions.
Similar to the functions expressions
, the arrow functions
aren’t hoisted.
Conclusion
Please feel free to leave any questions, comments, suggestions, or concerns below.
If this article was helpful,Tweet it
Thank you very much for reading!