
JavaScript Hoisting: Variables, Functions, and More

In JavaScript, understanding hoisting is fundamental to writing reliable and predictable code. This unique feature (some might argue it's a "quirk") affects how variables and functions are initialised and accessed during the execution of a script.
In this article, I intend to explore what hoisting is, how it works with variables and functions, and best practices for managing hoisting within modern JavaScript.
What is Hoisting?
Hoisting is JavaScript's default behaviour of moving variable and function declarations to the top of their containing scope during the compilation phase. During the first step, the JavaScript interpreter processes variable and function declaration, but does not execute any of the code until the second step. This means that you can use variables and functions in your code before declaring them, albeit with some caveats.
For example:
console.log(myVar); // undefinedvar myVar = 'Hello';In this example, JavaScript "hoists" the var declaration to the top of its scope, but its value assignment remains in place. As a result, the variable is accessible before its declaration, but it returns undefined.
Hoisting in Variables
var and Hoisting
Variables declared with var are hoisted to the top of their scope. However, only the declaration is hoisted, not the initialisation.
Take this code for example:
console.log(greeting); // undefinedvar greeting = 'Hi!';The JavaScript engine will interpret this code like this:
var greeting;console.log(greeting); // undefinedgreeting = 'Hi!';let and const
Variables declared with let and const are also hoisted, but they remain in a "temporal dead zone" (TDZ) until their declaration is encountered.
console.log(message); // ReferenceError: Cannot access 'message' before initialisationlet message = 'Hello!';The temporal dead zone ensures that you cannot access the variable before it is declared, which eliminates one of the common pitfalls associated with var, and means that we get a ReferenceError instead of undefined.
Hoisting in Functions
Function Declarations
Function declarations are fully hoisted, meaning you can call the function before it is defined in your code.
For example:
sayHello();function sayHello() { console.log('Hello, world!');}Although perhaps not best practice, this is possible because the entire function is hoisted to the top of its scope.
Function Expressions
Function expressions, including arrow functions, are not fully hoisted. Only the variable declaration is hoisted, not the function itself:
sayHello(); // TypeError: sayHello is not a functionvar sayHello = function () { console.log('Hello, world!');};The JavaScript engine interprets this as:
var sayHello;sayHello(); // TypeErrorsayHello = function () { console.log('Hello, world!');};Best Practices for Managing Hoisting
1. Use let and const Instead of var
Avoid var in modern JavaScript (there really is very little reason you would ever use var) to prevent unexpected behaviour due to hoisting. Stick to let and const for block‑scoped variables.
const name = 'Sophie';let age = 30;2. Declare Variables and Functions at the Top of Their Scope
Explicitly declaring variables and functions at the beginning of their scope reduces the potential for hoisting‑related confusion. It also makes it much easier to read, especially for the developer who comes to your code after you!
function processData() { let data; // Logic goes here}3. Initialise Variables Immediately
Wherever possible, declare and initialise variables in a single step to avoid accessing uninitialised values.
let user = 'John';Wrapping up
Hoisting is an essential aspect of JavaScript's behaviour that can sometimes lead to unexpected results, especially in relatively new or inexperienced developers. Understanding how hoisting works with variables and functions is key to writing predictable and maintainable code. By using modern features like let and const, and following best practices, we can minimise the risks associated with hoisting.
Key Takeaways
What is hoisting?
JavaScript moves declarations (not initialisations) to the top of their scope during compilation.Variables:
varis hoisted, but its initialisation is not;letandconstremain in a temporal dead zone until declared.Functions:
Function declarations are fully hoisted, but function expressions are not.Best practices:
Useletandconst, declare variables and functions at the start of their scope, and initialise variables immediately.
Hoisting is a quirk of JavaScript, but with a clear understanding and modern practices, we can avoid its pitfalls and write cleaner, more reliable code.
Related Articles

Closures in JavaScript: The Key to Lexical Scope. 
Function Declarations vs. Function Expressions vs. Arrow Functions. Function Declarations vs. Function Expressions vs. Arrow Functions

The Power of text‑wrap: pretty. The Power of
text‑wrap: pretty
Implementing a Trie in TypeScript: Solving 'Implement Trie (Prefix Tree)'. Implementing a Trie in TypeScript: Solving 'Implement Trie (Prefix Tree)'

Creating Interactive User Interfaces with HTML, CSS, and JavaScript. Creating Interactive User Interfaces with HTML, CSS, and JavaScript

Array.from() and Array.of() in JavaScript. Array.from()andArray.of()in JavaScript
Optimising Website Performance with HTML, CSS, and JavaScript. Optimising Website Performance with HTML, CSS, and JavaScript

Prepending PHP to a Page in Gatsby. Prepending PHP to a Page in Gatsby

The CSS overflow Property. The CSS
overflowProperty
Default Parameters in JavaScript: A Guide. Default Parameters in JavaScript: A Guide

Detecting and Dealing with Website Theft. Detecting and Dealing with Website Theft

CSS visibility: Hiding Elements Without Affecting Layout. CSS
visibility: Hiding Elements Without Affecting Layout