Understanding Hoisting in JavaScript.

Victor Ofoegbu
codeburst
Published in
4 min readDec 9, 2017

--

People complain that there are lots of traps while writing JavaScript code.

Developers are smart people and they’re constantly trying to create tools that make JavaScript debugging easy.

This post clarifies the most basic confusions about how JavaScript uses variables and functions you provide it.

Let’s take a look at this code.

var x = 12;
(function () {
console.log(x);
var x = 13;
}());
//undefined

You might want to think the answer above would be 13 or 12. Actually, it’s undefined. I’ll tell you why, let’s just dive in.

Scope in JavaScript.

There are three levels of scope in JavaScript.

  1. Global scope: Pretty much every variable you declare on your window object. You can use it anywhere in your program. In JavaScript, any variable you declare without a let, var , or const goes to the global scope.
var x = 10;
function changeX(){
x = 12; //this changes the value of x in the global scope.
}
changeX();
console.log(x);
//12

2) Function scope: When you define a function, all variables from the global scope are available to it. It also has access to all variables declared inside of it, so far they are not declared inside another function.

In JavaScript, only functions create new scope. At least before our next point.

3) Block scope: Introduced in the latest version of JavaScript (ES6). Variables are only available in block code (within curly braces {}). Meaning that we can create new scope without functions. But we must use the let keyword to declare those variables. In fact, you should also use let to declare all of your variables. let’s see this example.

let x = 10;
for(let x = 0; x < 2; x++){
console.log(x);
}
console.log(x);
// 1
// 2
// 10

In this example, x in the for loop doesn’t tamper with the value of xin the global scope. The let keyword can be traced down to Mathematics expressions where working with a new mathematical idea would require changing variables.

I remember saying let the value of X be bla bla. I’m sure you do too…

How JavaScript Hoists.

JavaScript runs code in two steps.

Declaration phase:

All variables and functions declared within a scope are mapped to their identifiers so they can be easily found during execution proper.

Initializations and assignments are not hoisted in JavaScript. Only declarations are. That’s very important to note.

Execution phase:

Identifiers to all declared variables and functions are available and program is run line by line.

Let’s go back to our first example

var x = 12;
(function () {
console.log(x);
var x = 13;
}());
//undefined

One would expect that the console.log(x) statement should use x from the global scope or even use x from the inner scope. But JavaScript proofs us wrong

This all boils down to the fact that JavaScript declares all everything in the background.

When we do var x = ++x , JavaScript breaks that to var x and x = ++x and moves (hoists) only the declaration to the top of the function. The code above is equivalent to

var x = 12;
(function () {
var x;
console.log(x);
x = ++x;
}());
//undefined

So when console.log(x) runs, our Immediately Invoked Function Expression (IIFE) only has x declared. We can confirm this with this code below

var x = 12;
(function () {
console.log(x);
var x = 13;
console.log(x);
}());
//undefined

Now, the second console.log(x) statement runs with the value of xas 13.

Functions

Function declarations are hoisted also. But we can’t say for sure. Let’s look at this example.

logSomething();function logSomething(){
console.log(11);
}
// 11

Straight forward right? Still JavaScript hoisting here. We can call the logSomething() function before declaring it. This takes us to our next point.

Only declarations are hoisted

This is not something new in this post, let me show you how this applies to functions.

logSomething();var logSomething = function logSomething(){
console.log(11);
}
//uncaught TypeError:logSomething is not a function.

This shouldn’t suprise you if you get the difference between function declarations and expressions.

In our above example, the logSomething variable is hoisted to the top of the program scope. When execution begins, the program only knows logSomething as a declared variable, the function expresion body is not hoisted.

The code above is equivalent to this:

var logSomething;logSomething();logSomething = function logSomething(){
console.log(11);
}
//uncaught TypeError:logSomething is not a function.

Preventing scope problems

We’re used to the JavaScript environment. Sure we can avoid some of these little potholes by…

  1. Declaring all variables at the top of our functions.
  2. Avoid using var .
  3. Make use of one let or const per function.
let one, two, three, four;vs let one;
let ...

3. Always declare and define all functions before using them.

That would be all for now.

And sure, those tips aren’t enough to prevent scope related problems. I’ll love to hear yours.

If you think this post was helpful, you might want to share with friends and colleagues. They’ll find them helpful too.

I would love some claps on this posts too. It helps me know how helpful these posts are.

--

--

Product-Focused Software Engineer. Learning to design & build digital experiences