We're live-coding on Twitch! Join us!

In JavaScript, hoisting is a term used to denote the movement of variable and function declarations to the top of their scope during execution of the scope.

This can be a confusing topic for the unitiated since this is a unique feature that you don't see in many other languages. Declarations will be brought to the top of the execution of the scope.

Basic Example

Let's take a look at some examples.

// assign a value of 2 to x
x = 2;     

// declare variable named x 
var x;      

console.log(x); // logs 2

How does this happen? You may have thought that after the second line (var x;), that the value of x would then become undefined. Let's take a look at how the JavaScript engine actually sees the above code:

// variable declaration was hoisted to the top! 
// x is undefined at this point
var x;      

// assign a value of 2 to x
x = 2;      

console.log(x); // logs 2

Variable declarations are hoisted to the top of the scope (global in this case) and the code runs from there.

Only Declarations are Hoisted (Not Assignments)

Here's another example. When we console.log(x), you may want to think that the value of x at that point would be 40. However, we get undefined. The var x = 40 line should be hoisted right?

console.log(x); // undefined
var x = 40;

Let's talk about what gets hoisted.

Variable declaration is hoisted. Assignment doesn't happen until later.

Notice above, that x value is undefined. This indicates that x has been declared but has not been initialized before the console statement is executed:

During execution, JavaScript arranges the above code like so:

// declaration is hoisted. NO ASSIGNMENT YET
var x;

console.log(x); // undefined

// now the assignment happens
var x = 40;

console.log(x); // 40

It simply means that x was hoisted to the top of the scope before even being run by the flow. Once the variable x has been hoisted on the top of the scope, the code continues to run synchronously executing any further instructions on x.

In ES2015 widely known as ES6, two new variables types were introduced, let and const. Quite similar to var but to ensure backward compatibility with previous versions or JavaScript, var was kept. Here we shall look at the similarities of the variable types and their differences as well.

Let

Different from var, let is used when the variable and value is required solely in a block. No leaks whatsoever to the global scope. Here:

if (true) {
  // defined only in this block scope
  let x = 5
}

// x is not available in the global scope
console.log(x); // ReferenceError

In the function, the value of x is 5, whereas since the instance of x in the block scope is unavailable to the global scope, trying to log the value of x returns a reference error.

Hoisting takes place when declaring variables using let but since the variables are not accessible before its initialization, it is assumed that hoisting doesn’t occur. This is known as the Temporary Dead Zone. Here:

function foo() {
  console.log(y); // ReferenceError
  let y = 5;
}

foo()

Unlike in var where the value of y would be undefined, the value of y here throws a Reference Error because y is hoisted at the top of the scope but is not accessible unless the lexical binding of the variable has been evaluated.

In JavaScript, the same variable cannot be initialized twice with let:

let x = 2;
let x = 3; // Syntax Error: Identifier 'x' has already been defined

This however would work since we are able to reassign the value of let x. We're allowed to re-assign, just not re-declare.

let x = 2;
x = 3;

Using var, we are able to re-declare.

var x = 2; // x = 2
var x = 4; // x = 4

Const

const, unlike let is used to assign values to variables that cannot be re-assigned throughout the code. These variables are block scoped, can’t be re-declared in the same scope and are inaccessible before being initialized just like let. Here:

const num = 5;
const num = 7; // SyntaxError: identifier 'num' has already been declared

and

num = 10; // TypeError: Assignment to constant variable

Note: const variables are mutable when dealing with arrays and objects because technically we are not re-assigning the variable a new value but only changing the containing elements.

const person = {
  name:  'chris',
  level: 'pro',
  age:   '25'
}; 

person = "chris" // TypeError: Assignment to constant variable 

but the following will work:

const citizen = {
  name:  'chris',
  level: 'pro',
  age:   '25'
};

citizen.name = "william"

console.log(citizen.name) // william

In arrays we can write:

const farm = [];
farm.push('rice', 'beans', 'maize', 'brocolli');

console.log(farm); // ['rice', 'beans', 'maize', 'brocolli']

whereas,

const farm = [];
farm       = ['rice', 'beans', 'maize'] // TypeError: Assignment to constant variable

Hoisting Functions

Hoisting with functions works a little differently than variables. Functions are hoisted and made available.

Take the following example:


doSomething();  // this works!

function doSomething() {
  console.log('im doing things!');
}

The function doSomething() is hoisted above where we actually use it. To JavaScript, the above looks like:

// hoisted to the top
function doSomething() {
  console.log('im doing things!');
}

doSomething();  // this works!

Conclusion

We have been able to clearly demonstrate the movement of variables to the top of their scope which is known as Hoisting in JavaScript. Also, we have seen the hoisting behaviour of ES6 varibale types, let and const.

A proper understanding of this concept goes a long way to help in effective code development.

Like this article? Follow @codebeast on Twitter