loading...

Hoisting

rukshanuddin profile image Rukshan Uddin ・4 min read

What is hoisting? Hoisting is a relatively new concept, which you will not find anything about in documentation prior to ES6. According to MDN:

Hoisting is a term you will not find used in any normative specification prose prior to ECMAScript® 2015 Language Specification. Hoisting was thought up as a general way of thinking about how execution contexts (specifically the creation and execution phases) work in JavaScript. However, the concept can be a little confusing at first.

Ok, so that is a little confusing. To put it simply, hoisting is a mechanism, that since ES5 will move variables to the top of its scope during "compilation" (placed in quotes, since Javascript in considered a compiled language) before code execution. Changes in how hoisting works were made with the ES6 release of Javascript as well, and I will document how it works.

No matter where functions and variables are declared, they are moved to the top of their scope (global or local).

This will let a few things occur in Javascript, including allowing you to call functions before they've been written in your code.

How it works

ES5

Global Variables

In ES5 thanks to the magic of hoisting, we could do this:

console.log(myVar); // Output: undefined

var myVar = "ES5 hoisted me!";

Instead of getting ReferenceError: myVar is undefined for the console.log(myVar) we got undefined.

Why did it return undefined?

Why didn't it return "ES5 hoisted me!"?


Did it not hoist myVar?

All valid questions at this point. The interpreter will view the code as follows:

var myVar; // myVar gets hoisted to top of scope

console.log(myVar); // myVar is not yet defined

var myVar = "ES5 hoisted me!"; // value not seen by the previous console.log()

While ES5 has hoisted myVar to the top of the scope, it has not been initialized yet. The reason it is returning undefined is because only var myVar gets hoisted, not the initialization value of "ES5 hoisted me!" during the compilation phase. We need to make sure to initialize our variables before we call them:

var myVar = "ES5 hoisted me!";
console.log(myVar); // Output: ES5 hoisted me!

Function Scoped Variables

function myFunction() {
    console.log(myVar);
    var myVar = "Hoisting is the bees knees!";
}

myFunction();

Based on our knowledge of hoisting thus far, it is safe to assume that the scope of myVar is myFunction() and that function would return undefined. The interpreter sees it as:

function myFunction() {
    var myVar; // myVar gets hoisted to top of function
    console.log(myVar); // myVar is undefined at this point
    var myVar = "Hoisting is the bees knees!"; // console.log() does not see this value of myVar
}

myFunction(); // Output: undefined

Like the previous example, to prevent this all we need to do is initialize the variable before calling it.

function myFunction() {
    var myVar = "Hoisting is the bees knees!";
    console.log(myVar);
}

myFunction(); // Output: Hoisting is the bees knees!

Strict Mode

What is strict mode? With ES5 we have been given a way to be more mindful of how we declare variables. From MDN()

JavaScript's strict mode is a way to opt in to a restricted variant of JavaScript, thereby implicitly opting-out of "sloppy mode". Strict mode isn't just a subset: it intentionally has different semantics from normal code.

Strict mode for an entire script is invoked by including the statement "use strict"; before any other statements.

We can get a lot of benefits from using strict mode. Strict mode will:

  • Change errors to throw errors.
    • Helps to remove "silent" Javascript errors.
  • Strict mode repairs mistakes
    • Makes it easier for JavaScript engines to perform optimizations.
    • Identical code will sometimes execute faster in strict mode.
  • Strict mode forbids certain JavaScript syntax.
  • When relatively “unsafe” actions are taken, it prevents or throws errors.
    • (Such as gaining access to the global object).
  • It restricts features that are unclear or poorly thought out.
  • Strict mode makes it easier to write “secure” JavaScript code.

ES6

let

console.log(myVar);

let myVar = "ES6 hoisted me!";

Let's take the first example but use let instead of var. If we were going by the logic we had learned in the previous examples, we would assume that the console.log() would be undefined. Instead, we get something else:

console.log(myVar);

let myVar = "ES6 hoisted me!";

//Uncaught ReferenceError: myVar is not defined

What ES6 does is gives us a ReferenceError. ES6 will not let us use an undeclared variable. The let keyword means the variable's scope is bound to the block in which is it declared and not the function in which it is declared. It also means we need to explicitly declare let keyword variables before they are called.

let myVar;

console.log(myVar); // Output: undefined

myVar = "ES6 hoisted me!";

This time we won't get a ReferenceError, but our output will be undefined.

const

The const keyword is very much like let except one key difference. MDN defines it as the following:

Constants are block-scoped, much like variables defined using the let keyword. The value of a constant can't be changed through reassignment, and it can't be redeclared.

Just like with let, const keyword variables are hoisted to the top of the block.

console.log(myVar);

const myVar = "ES6 hoisted me!";

//ReferenceError: Cannot access 'myVar' before initialization

We will get ReferenceError just as we did with the let keyword. It works the same with const in functions:

function hoistMe(user){
    console.log(result)
    const result = `${user}` + `has been hoisted`
}

hoistMe("Jonny")

We will ge an error:

function hoistMe(user){
    console.log(result)
    const result = `${user}` + `has been hoisted`
}

hoistMe("Jonny") //Uncaught ReferenceError: Cannot access 'result' before initialization

We will also get errors for using a constant before declaring and initializing it.

The differences between var, let, const

The key difference between var, let and const as it relates to hoisting is that let and const remain uninitialized at execution while var declared variables are initialized with a value of undefined

Posted on by:

rukshanuddin profile

Rukshan Uddin

@rukshanuddin

Student @Flatiron School. Fullstack program. Full-time. Nov. Cohort.

Discussion

markdown guide