DEV Community

loading...
Cover image for The last article you will ever need to read to understand hoisting in JavaScript

The last article you will ever need to read to understand hoisting in JavaScript

albert_hadacek profile image Albert Hadacek Updated on ・3 min read

With the ECMAScript 2015 specification JavaScript received two new keywords for working with bindings. Namely, let and const which basically replaced the classical var in most of today’s code. In this article, we are gonna dive deep and discover the differences between the above mentioned keywords and discover how hoisting works in JavaScript.

What the heck is hoisting?

It is basically a mechanism that JavaScript uses to “move” your variables and declarations to the “top” of your code. It is important to understand, that only the declarations are moved up. The assignments themselves stay. Therefore we can use functions, that are declared (using the function declaration) at the end of the file, on line one, but variables declared using var are assigned to ‘undefined’ by default.

console.log(hi) // 'ƒ(){}'
console.log(bye) // 'undefined'
hi() // "hi"
bye() // Reference error
function hi() {
  console.log("hi")
}
var bye = function() {
  console.log("bye")
}
Enter fullscreen mode Exit fullscreen mode

With consts and lets we get a Reference Error if we access them before declaration as they are placed in the so-called Temporal Dead Zone, which means that they are hoisted (a common misconception), but they are not initialized to any default value if we access them before the declaration.

How traditional vars actually work

First, we are gonna go through the lifecycle of the variable declared using the keyword var.

var name // Declaring name with the default value of undefined.
console.log(name) // 'undefined'
console.log(age) // Also prints 'undefined' because of hoisting
var age
Enter fullscreen mode Exit fullscreen mode

Weird? Maybe, but quite easy to wrap your head around. The main issue with vars is that they are not block-scoped but their scope corresponds with their execution context which is either represented by their enclosing function or the global context. That might cause unwanted behavior.

var isNight = true
if(isNight) {
  var midnightSnack = "ice cream"
}
console.log(midnightSnack) // "ice cream"
Enter fullscreen mode Exit fullscreen mode

The above behaviour is something we want to avoid as mignightSnack is effectively available in the global scope.

Vars also cause issues with asynchronous code within a loop as the var i is not recreated (as it's global) during each iteration and when the asynchronous calls finally leave the callback queue and reach the stack, variable i is already 3.

for(var i = 0; i < 4; i++) {
  setTimeout(function(){ 
    console.log(i) 
  },0)
}
// 3 3 3 
Enter fullscreen mode Exit fullscreen mode

How let and const differ from var

Before diving into the differences between const and let we need to understand how these two behave in comparison to vars.

Firstly, as mentioned before, let and const are not initialized to ‘undefined’ if we access them before the declaration. Yet, after the declaration, let actually becomes “undefined”.

let name
console.log(name) // "undefined"
console.log(age) // Reference Error
let age
Enter fullscreen mode Exit fullscreen mode

Secondly, lets and consts are block-scoped, which basically means that they only are unavailable outside of the block where they were declared (loops and conditions).

let isNight = true
if(isNight) {
  const midnightSnack = "ice cream"
}
console.log(midnightSnack) // Reference error
Enter fullscreen mode Exit fullscreen mode

This also changes the behaviour of the asynchronous for loop we saw before.

for(let i = 0; i < 4; i++) {
  setTimeout(function(){ 
    console.log(i) 
  },0)
}
// 1 2 3
Enter fullscreen mode Exit fullscreen mode

Here, a new scope is created during each iteration as well as the let i, so the declared function closes over three different instances of i.

The difference between let and const

Now, we understand the differences between let + const and var but how let and const differ?

let age;
console.log(name) // "undefined"
const name; // Syntax Error
Enter fullscreen mode Exit fullscreen mode

Firstly, consts have to be declared and initialized at the same time and as the name suggests they can’t be reassigned. On the other hand, we can just declare and reference lets, also we can reassign them.

let age = 18
age = 19
const name = "John"
name = "Peter" // Type Error
Enter fullscreen mode Exit fullscreen mode

Working with reference values

One thing that might be confusing is, that we can actually alter the value of const.

const arr = [1,2,3]
arr.push(4)
console.log(arr) // [1, 2, 3, 4]
const obj = {}
obj.name = "John"
console.log(obj.name) // "John"
Enter fullscreen mode Exit fullscreen mode

Const does not make mutable types like arrays or objects immutable. It only prevents reassigning. If we want to achieve immutability we can use the Object.freeze() method.

Discussion (2)

pic
Editor guide
Collapse
aroman012 profile image
Alejandro Roman

Thank you for your explanation! I have struggled with this concept before.

Btw, in this sample code you provided:

var isNight = true
if(isNight) {
  let midnightSnack = "ice cream"
}
console.log(midnightSnack) // "ice cream"
Enter fullscreen mode Exit fullscreen mode

Perhaps you meant to say var midnightSnack instead of let midnightSnack?

Collapse
albert_hadacek profile image
Albert Hadacek Author

Ohh yeah, thanks, fixed