What is hoisting in JavaScript and How it works?
Introduction for Hoisting in JavaScript
Hoisting in JavaScript: When diving into JavaScript, one of the most intriguing concepts We’ll encounter is hoisting. This unique behavior often puzzles beginners, but understanding it is crucial for writing efficient and bug-free code. In this three-page guide, we’ll explore what hoisting is, how it works, and the nuances between different types of declarations.
What is Hoisting?
JavaScript hoists variable and function declarations to the top of their containing scope (either the function scope or the global scope) during the compilation phase, before code execution. This behavior allows you to use variables and functions before you declare them in the code.
During the compilation phase, the JavaScript engine allocates memory for all variables and functions, effectively “hoisting” their declarations. For variables declared with var, only the declaration is hoisted, not the initialization, so they are accessible but have the value undefined until assigned.
JavaScript fully hoists function declarations, moving both the name and the body to the top. This allows you to call these functions before you declare them in the code. However, while JavaScript hoists variables declared with let and const, it does not initialize them. This leads to a Reference Error if you try to access these variables before their declaration in the code.
Function expressions are not hoisted, as only the variable declaration is moved, not the function assignment. Understanding hoisting helps in writing predictable and bug-free JavaScript code.
To better understand this concept, let’s delve into the specifics of variable and function hoisting.
Variable Hoisting
JavaScript hoists only the declaration of variables, not their initialization. If you reference a variable before you initialize it, JavaScript will return undefined.
JavaScript code
console.log(x); // undefined
var x = 5;
console.log(x); // 5
In this example, var x; is hoisted to the top, but the assignment x = 5; remains in place. Thus, x is undefined when the first console.log(x); is executed.
How Variable Hoisting Works
The JavaScript engine parses the code in two phases: the creation phase and the execution phase.
Creation Phase: During this phase, the JavaScript engine scans through the code to find variable and function declarations. For each declaration, it allocates memory space and sets the initial value.
JavaScript sets the initial value of var declarations to undefined. It does not set an initial value for let and const declarations during this phase (I’ll explain more about this later). During the execution phase, JavaScript executes the code line by line. You can now use variables declared with var that it hoisted during the creation phase, though their initial value remains undefined until you assign them a value.
Example of Variable Hoisting in Action
JavaScript code
console.log(message); // undefined
var message = “Hello, world!”;
console.log(message); // “Hello, world!”
Creation Phase: The declaration var message; is hoisted to the top of its scope. The engine allocates memory for message and initializes it to undefined.
During the execution phase, the first console.log(message); outputs undefined because JavaScript has declared the variable but has not yet assigned it a value. After the code executes message = “Hello, world!”;, it assigns a value to the variable, and the second console.log(message); outputs “Hello, world!”.
This example demonstrates how the JavaScript engine handles variable declarations and why understanding hoisting is important to avoid unexpected behaviors.
Common Pitfalls of Variable Hoisting:
Variable hoisting can lead to several common pitfalls, especially for developers who are new to JavaScript:
Unintended Undefined Values: As shown in the examples above, using a variable before it is initialized can result in undefined values, which might not be the intended behavior.
JavaScript code
console.log(num); // undefined
var num = 10;
console.log(num); // 10
Re-declaration Issues: Re-declaring a variable with var in the same scope can lead to confusion and bugs.
JavaScript code
var a = 1;
var a = 2;
console.log(a); // 2
Understanding these pitfalls helps in writing cleaner and more predictable JavaScript code. In the next page, we will explore function hoisting and the differences between var, let, and const in more detail.
Function Hoisting
Function declarations hoist entirely, including their body, allowing you to call functions before they are declared in the code.
JavaScript code
greet(); // “Hello, World!”
function greet() {
console.log(“Hello, World!”);
}
Differences Between var, let, and const in Hoisting
var
JavaScript hoists variables declared with `var` to the top of their enclosing function or global scope and initializes them with `undefined`.
JavaScript Code
console.log(a); // undefined
var a = 10;
let and const
JavaScript also hoists variables declared with `let` and `const`, but unlike `var`, it does not initialize them. They exist in a “temporal dead zone” from the start of the block until it encounters the declaration. Accessing them before declaration results in a Reference Error.
JavaScript code
console.log(b); // Reference Error: Cannot access ‘b’ before initialization
let b = 20;
console.log(c); // Reference Error: Cannot access ‘c’ before initialization
const c = 30;
Function Expressions and Arrow Functions
Both function expressions and arrow functions behave differently from function declarations in terms of hoisting. JavaScript hoists only the variable declaration, not the assignment.
Function Expressions
JavaScript code
console.log(foo); // undefined
foo(); // Type Error: foo is not a function
var foo = function() {
console.log(“Hello!”);
};
Arrow Functions
Arrow functions follow the same hoisting rules as function expressions.
JavaScript code
console.log(bar); // undefined
bar(); // Type Error: bar is not a function
var bar = () => {
console.log(“Hello!”);
};
Remember:
Moreover JavaScript hoists variables declared with var and initializes them with undefined. It hoists variables declared with let and const but does not initialize them, leading to a temporal dead zone. It hoists function declarations entirely. However, it treats function expressions and arrow functions like variable declarations and does not hoist them.
Understanding these nuances will make you a more proficient JavaScript developer, ready to tackle complex coding challenges with confidence.
Conclusion
Hoisting in JavaScript is a fundamental concept in JavaScript that can affect how your code behaves. Understanding that variable and function declarations move to the top of their scope helps you avoid unexpected behaviors and write more predictable, maintainable code.