Hoisting is JavaScript’s behavior of processing variable and function declarations before executing code line by line — understanding it explains a lot of otherwise-confusing behavior around when things become available.
// Function declarations are fully hoisted - usable before their definition
sayHello(); // works fine
function sayHello() { console.log('Hello'); }
// var is hoisted but only the declaration, not the assignment
console.log(x); // undefined, not an error
var x = 5;
// let/const are hoisted too, but land in the "temporal dead zone"
// until their actual declaration line - accessing them early throws
try {
console.log(y); // ReferenceError: Cannot access 'y' before initialization
let y = 10;
} catch (e) { console.log(e.message); }
// Function expressions are NOT hoisted the same way
try {
sayGoodbye(); // TypeError: sayGoodbye is not a function
var sayGoodbye = function() { console.log('Goodbye'); };
} catch (e) { console.log(e.message); }
The practical takeaway: declare variables at the top of their scope and functions before use, regardless of hoisting rules — relying on hoisting behavior to make code work is a maintenance liability even when it’s technically valid.