DEV Community

Abdusanadzoda Abdulaziz
Abdusanadzoda Abdulaziz

Posted on

Function Hoisting ✨

Intro

In my last post, we discussed about hoising and variable hoisting in detail. With the understanding of how variable hoisting works, let’s move on to function hoisting.

Test Your Knowledge

Can you tell what will the following three sayHello() result in, and more importantly, explain why?

sayHello()

function sayHello () {
  function hello () {
    console.log('Hello!')
  }

  hello()

  function hello () {
    console.log('Hey!')
  }
}
Enter fullscreen mode Exit fullscreen mode
sayHello()

function sayHello () {
  function hello () {
    console.log('Hello!')
  }

  hello()

  var hello = function () {
    console.log('Hey!')
  }
}
Enter fullscreen mode Exit fullscreen mode
sayHello()

var sayHello = function () {
  function hello () {
    console.log('Hello!')
  }

  hello()

  function hello () {
    console.log('Hey!')
  }
}

Enter fullscreen mode Exit fullscreen mode

Answers are Hey!, Hello!, and the third one actually results in a TypeError.

Don’t worry if you didn’t guess these right. There will be a few more quiz at the end, and by then, you’ll find yourself more comfortable with function hoisting.

Function Hoisting

Remember this example from variable hoisting?

console.log(x)
var x

// undefined
Enter fullscreen mode Exit fullscreen mode

The key here was that x was available before its declaration. The same logic applies to a function declaration.

sayHello()

function sayHello () {
  console.log('Hello!')
}

// Hello!
Enter fullscreen mode Exit fullscreen mode

In this example, I’m calling sayHello function before its declaration from line 3. Although it looks like I am calling a function that hasn’t even been declared, I can use it, and it prints out Hello!. This is thanks to function hoisting.

During the memory creation phase, the JavaScript engine recognised a function declaration by the function keyword and hoisted it — in other words, the JavaScript engine made the function available by putting it into the memory, before moving on. That’s why I could access the sayHello function prior to its declaration in the execution phase.

Alright, so what about this one? Can you tell what would the following code do?

sayHello()

var sayHello = function () {
  console.log('Hello!')
}
Enter fullscreen mode Exit fullscreen mode

Yep, that’s right — it results in TypeError, complaining that sayHello is not a function. Hmm… wait, what!?

In order to fully understand what’s happening behind the scene, we need to to know the difference between function declaration and function expression. Let’s spend a little bit of time on that first.

Function Declaration vs Function Expression

There are two ways to define a function with the function keyword in JavaScript — function declaration and function expression.

A function declaration starts with the function keyword, followed by the name of the function (sayHello), then a block of code to be executed when the function is called ({ console.log('Hello!') }).

function sayHello() {
  console.log('Hello!')
}

sayHello()

// Hello!
Enter fullscreen mode Exit fullscreen mode

On the other hand, a function expression allows you to define a function without a name and as part of non-functional code blocks. A typical usage of a function expression is to assign a function to a variable. Below, I’m defining an anonymous function, that is, function without a name, (function () { console.log(Hello!) }) and assigning it to a variable (var sayHello =), so I can refer to the function via sayHello later on.

var sayHello = function() {
  console.log('Hello!')
}

sayHello()

// Hello!
Enter fullscreen mode Exit fullscreen mode

If I were to call these functions after they are defined, I can call them in the same way via sayHello() and both print out Hello!. However, when the JavaScript engine first sees them, it treats them in very different ways.

Function Expressions are Not Hoisted

Let’s go back to example 2, which threw a TypeError: sayHello is not a function, and walk through what’s happening step by step from the JavaScript engine’s point of view.

sayHello()

var sayHello = function () {
  console.log('Hello!')
}
Enter fullscreen mode Exit fullscreen mode

During the memory creation phase, the JavaScript engine encounters the var keyword at line 3, at which point it expects a variable declaration to follow. Do you remember what the JavaScript engine does to a variable declaration? Yes, it hoists the variable with a value: undefined. And it doesn’t hoist the variable initiation.

Now… the TypeError starts to make sense. The variable declaration (var sayHello) was hoisted with a value undefined. However, the variable initialisation (= function () { console.log(Hello!) }) wasn’t hoisted. Therefore, when the execution reached line 1 and tried to call sayHello, it failed, because undefined is not a function! Only after the sayHello variable is assigned to a function expression during the execution at line 3, can we call the function by sayHello(). We can prove this with the following.

console.log(sayHello)

var sayHello = function () {
  console.log('Hello!')
}

sayHello()

// undefined
// Hello!

Enter fullscreen mode Exit fullscreen mode

Got it?

Please post any feedback, questions, or requests for topics. I would also appreciate 👏 if you like the post, so others can find this too.

Top comments (1)

Collapse
 
amt8u profile image
amt8u

Just curious : Why there are two ways to declare functions? We can achieve everything with function expressions. Whats the use case for having function declarations?