Hoisting is a behavior in JavaScript where variable and function declarations are moved to the top of their containing scope during the compilation phase, before the code is executed. This means you can use variables and functions before they are declared in the code.
However, only the declarations are hoisted, not the initializations or assignments.
-
Declaration Before Execution:
- JavaScript "hoists" the declarations of variables and functions to the top of their scope.
- This makes them accessible before their actual line of declaration in the code.
-
Partial Behavior:
- Only the declarations are hoisted, not the assignments or initializations.
-
Applicable to Variables and Functions:
var
(function-scoped) is hoisted.let
andconst
(block-scoped) are hoisted but are not initialized (remain in the "temporal dead zone").- Function declarations are fully hoisted.
Variables declared with var
are hoisted and initialized with undefined
.
console.log(a); // Output: undefined
var a = 10;
console.log(a); // Output: 10
The code above is interpreted like this by the JavaScript engine:
var a;
console.log(a); // undefined
a = 10;
console.log(a); // 10
Variables declared with let
and const
are hoisted but are not initialized. They remain in the temporal dead zone (TDZ) from the start of the block until the declaration is encountered.
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 20;
The JavaScript engine hoists b
but does not initialize it:
// Temporal Dead Zone
let b;
console.log(b); // ReferenceError
b = 20;
Function declarations are fully hoisted, meaning you can call them even before they appear in the code.
sayHello(); // Output: Hello, world!
function sayHello() {
console.log("Hello, world!");
}
Function expressions (using var
, let
, or const
) are hoisted differently. Only the variable declaration is hoisted, not the function definition.
console.log(sayHi); // Output: undefined
var sayHi = function () {
console.log("Hi there!");
};
sayHi(); // TypeError: sayHi is not a function
console.log(sayHi); // ReferenceError: Cannot access 'sayHi' before initialization
const sayHi = function () {
console.log("Hi there!");
};
Type | Hoisted? | Initialized? | Access Before Declaration |
---|---|---|---|
var |
Yes | Yes, with undefined |
Allowed (returns undefined ) |
let |
Yes | No (in TDZ) | Not Allowed (ReferenceError) |
const |
Yes | No (in TDZ) | Not Allowed (ReferenceError) |
Function Declaration | Yes | Fully | Allowed |
Function Expression (var ) |
Yes | No | Allowed but as undefined |
Function Expression (let or const ) |
Yes | No | Not Allowed |
-
Declare Variables at the Top:
- Always declare variables at the beginning of their scope.
-
Use
let
andconst
:- Prefer
let
andconst
overvar
to reduce unexpected behaviors.
- Prefer
-
Understand Temporal Dead Zone (TDZ):
- Be mindful of the TDZ when using
let
andconst
.
- Be mindful of the TDZ when using
-
Define Functions Before Calling:
- Even though function declarations are hoisted, defining them before calling improves code readability.
Hoisting is a fundamental concept in JavaScript that affects how variables and functions are declared and accessed. While it provides flexibility, understanding its nuances and limitations is essential for writing predictable and bug-free code. Use modern practices like let
, const
, and clear structure to mitigate potential issues related to hoisting.