Demystifying Function Declarations Within Conditional Blocks

How Hoisting Works in Conditional Terrains

In the two previous posts in this series about hoisting, we talked about how function declarations - using the function keyword - are hoisted along with their definitions. This means we can call such a function BEFORE its code even appears, and it will execute.

Now we will delve into the nuances related to hoisting function declarations within conditional blocks. The path our function declaration might take is based on the environment in which we operate.


In many languages, when you declare a function inside a conditional block (like an if statement), it's conditionally created, i.e., the function is only declared if the block is executed.

JavaScript behaves differently (of course!) when it comes to function declarations (using the function keyword) inside conditionals.

Here's a simple example:

if (false) {
    function testFunction() {
        console.log("This is a test function.");
    }
}
testFunction();

Expectation: Since the condition is false, the code inside won't run, and thus the function won't be declared.

The reality of JavaScript: it depends!

In some environments, calling testFunction() after this block might work, because of hoisting.

Here's how this behavior varies depending on the JavaScript environment:

  1. ES5 and non-strict mode: The function declaration is hoisted out of the block and to the top of the enclosing function or global scope, irrespective of the conditional. This means testFunction would be available both before the block's start and after its end, throughout the enclosing function or global scope.

  2. ES6 (ES2015) and later in strict mode: Block-level function declarations are now defined per the ES6 specification, which means the function is block-scoped, just like let and const. So in this case, trying to call testFunction outside the block will throw an error because the function was not hoisted outside of the block.

This is a subtle yet important distinction, and the reason why we often see recommendations to avoid using function declarations inside blocks (instead, use function expressions or arrow functions).

Main Takeaway

While traditional function declarations are hoisted to the top of their scope, when used inside conditional blocks, their behavior can vary based on the ECMAScript version and mode (strict vs. non-strict).

Resources

  1. MDN Documentation on Functions Declared within Block Scopes

  2. Blog post: The Curious Case of JavaScript Hoisting

  3. Blog post: The Temporal Dead Zone