DEV Community

Abimanyu P
Abimanyu P

Posted on

JS Functions & Its Hoisting Rules

JavaScript Hoisting and Types of Functions

Functions are one of the most important parts of JavaScript. They allow us to group a block of code into a reusable unit that can be executed whenever it is needed.

JavaScript provides different ways to create functions. Some common types are function declarations, function expressions, arrow functions, and IIFEs. Although all of them are functions, they behave differently in some situations, especially when hoisting is involved.

What is Hoisting in JavaScript?

Hoisting is the behavior of JavaScript where certain declarations are processed before the code is executed line by line.

For example:

console.log(name);

var name = "Abimanyu";
Enter fullscreen mode Exit fullscreen mode

The output is:

undefined
Enter fullscreen mode Exit fullscreen mode

This happens because the var declaration is processed before execution. Conceptually, it is similar to:

var name;

console.log(name);

name = "Abimanyu";
Enter fullscreen mode Exit fullscreen mode

The important thing to notice is that only the declaration is processed early. The assignment happens at its original position.

Hoisting does not mean JavaScript physically moves the code to the top. It describes what happens during the creation phase of the execution context before the code starts executing.

The same idea applies to functions, but the behavior depends on how the function is defined.


What is a Function?

A function is a reusable block of code that performs a particular task.

function greet() {
    console.log("Hello");
}

greet();
Enter fullscreen mode Exit fullscreen mode

Here, greet() is a function. Once defined, it can be called whenever required.

JavaScript allows us to create functions in different ways. The way we define a function also affects how hoisting works.


1. Function Declaration

A function declaration is the traditional way of defining a function.

greet();

function greet() {
    console.log("Hello");
}
Enter fullscreen mode Exit fullscreen mode

This works even though greet() is called before the function declaration.

The output is:

Hello
Enter fullscreen mode Exit fullscreen mode

This happens because function declarations are fully hoisted. During the creation phase, JavaScript makes the entire function available, including its function body.

So, conceptually, JavaScript already has access to:

function greet() {
    console.log("Hello");
}
Enter fullscreen mode Exit fullscreen mode

before it starts executing the code.

Hoisting rule

Function declarations are fully hoisted, so they can normally be called before their declaration.

This is one of the biggest differences between a function declaration and the other function types discussed below.


2. Function Expression

A function expression is a function assigned to a variable.

const greet = function() {
    console.log("Hello");
};
Enter fullscreen mode Exit fullscreen mode

Here, greet is not a function declaration. It is a variable that stores a function.

This distinction is important for hoisting.

For example:

greet();

const greet = function() {
    console.log("Hello");
};
Enter fullscreen mode Exit fullscreen mode

This results in a:

ReferenceError
Enter fullscreen mode Exit fullscreen mode

The reason is that const declarations are hoisted, but they remain in the Temporal Dead Zone (TDZ) until execution reaches their declaration.

The function expression itself is also not available before that point.

If var is used instead:

greet();

var greet = function() {
    console.log("Hello");
};
Enter fullscreen mode Exit fullscreen mode

the result is:

TypeError: greet is not a function
Enter fullscreen mode Exit fullscreen mode

This time, var greet is initialized with undefined during hoisting. The function is assigned to greet only when execution reaches the assignment.

Hoisting rule

A function expression is not hoisted as a callable function. Its behavior depends on the variable used to store it.

var   → undefined before assignment
let   → TDZ
const → TDZ
Enter fullscreen mode Exit fullscreen mode

3. Arrow Function

An arrow function provides a shorter syntax for creating functions.

const add = (a, b) => {
    return a + b;
};

console.log(add(10, 20));
Enter fullscreen mode Exit fullscreen mode

Output:

30
Enter fullscreen mode Exit fullscreen mode

Arrow functions are also commonly stored inside variables. Because of this, they do not receive the same function hoisting behavior as a function declaration.

For example, if an arrow function is stored in a const variable and accessed before its declaration, JavaScript produces a ReferenceError.

add(10, 20);

const add = (a, b) => {
    return a + b;
};
Enter fullscreen mode Exit fullscreen mode

The reason is not that arrow functions have some completely separate hoisting rule. The important point is that add is a const variable containing a function.

Therefore, the variable's rules apply:

const arrow function → TDZ → ReferenceError
let arrow function   → TDZ → ReferenceError
var arrow function   → undefined → TypeError
Enter fullscreen mode Exit fullscreen mode

Hoisting rule

Arrow functions themselves are not hoisted as callable functions. Their behavior depends on the variable declaration used to store them.

This is why:

function greet() {}
Enter fullscreen mode Exit fullscreen mode

and:

const greet = () => {};
Enter fullscreen mode Exit fullscreen mode

should not be treated as identical when discussing hoisting.


4. IIFE

IIFE stands for Immediately Invoked Function Expression.

It is a function expression that is executed immediately after it is created.

(function() {
    console.log("Hello");
})();
Enter fullscreen mode Exit fullscreen mode

Output:

Hello
Enter fullscreen mode Exit fullscreen mode

Normally, a function is defined first and called separately:

function greet() {
    console.log("Hello");
}

greet();
Enter fullscreen mode Exit fullscreen mode

With an IIFE, the function is executed immediately as part of the expression.

The final () invokes the function:

(function() {
    console.log("Hello");
})();
Enter fullscreen mode Exit fullscreen mode

IIFEs were commonly used to create a separate scope for variables and prevent them from interfering with other parts of a program.

Hoisting rule

An IIFE is a function expression, not a function declaration. Therefore, it does not receive the full hoisting behavior of a function declaration.

It executes when JavaScript reaches the expression:

(function() {
    console.log("Hello");
})();
Enter fullscreen mode Exit fullscreen mode

There is normally no separate function name that you can call before the IIFE.

The key idea is:

IIFE → function expression → executes when the expression is reached.


Conclusion:

The most important distinction is between a function declaration and a function stored in a variable.

// Function declaration
function greet() {}
Enter fullscreen mode Exit fullscreen mode

The function itself is hoisted.

Whereas:

// Function expression
const greet = function() {};
Enter fullscreen mode Exit fullscreen mode

and:

// Arrow function
const greet = () => {};
Enter fullscreen mode Exit fullscreen mode

store the function in a variable, so the variable's declaration rules determine what happens before the declaration is reached.

Top comments (1)

Collapse
 
jonrandy profile image
Jon Randy 🎖️

A function expression is a function assigned to a variable

Unfortunately not correct. Function expression and assigning a function to a variable are two different things.