Function Hoisting: Declarations vs Expressions
MedFunction declarations and function expressions behave very differently with hoisting. Function declarations are fully hoisted (both name and body), allowing you to call them before their definition. Function expressions follow variable hoisting rules - var function expressions are hoisted as undefined, while let/const function expressions are in the TDZ.
Interactive Visualization
1console.log(x); // ???2var x = 5;3console.log(x); // ???
Key Points
- Function declarations: fully hoisted (name + body)
- Function expressions: follow variable hoisting rules
- var function expressions: hoisted as undefined
- let/const function expressions: TDZ error if called early
- Arrow functions are expressions, not declarations
- Named function expressions are different from declarations
Code Examples
Function Declaration - Fully Hoisted
// Can call BEFORE definition! sayHello(); // "Hello!" - Works! function sayHello() { console.log("Hello!"); } // The entire function is hoisted to the top // This is why it works!
Function declarations are fully hoisted - both the name and the function body move to the top
Function Expression with var
// console.log(sayHi); // undefined // sayHi(); // ❌ TypeError: sayHi is not a function var sayHi = function() { console.log("Hi!"); }; sayHi(); // "Hi!" - Works after assignment // JavaScript sees: // var sayHi; // Hoisted declaration // console.log(sayHi); // undefined // sayHi(); // undefined is not callable! // sayHi = function(){}; // Assignment happens here
var function expressions are hoisted as undefined, so calling them before assignment throws TypeError
Function Expression with let
// sayHey(); // ❌ ReferenceError! TDZ let sayHey = function() { console.log("Hey!"); }; sayHey(); // "Hey!" // Same TDZ behavior as any let variable
let function expressions are in TDZ until the declaration line
Arrow Functions - Always Expressions
// arrowFunc(); // ❌ ReferenceError! TDZ const arrowFunc = () => { console.log("Arrow!"); }; arrowFunc(); // "Arrow!" // Arrow functions are always expressions // They follow variable hoisting rules
Arrow functions are always function expressions, never declarations
Named Function Expression
const factorial = function fact(n) { // 'fact' is available inside for recursion return n <= 1 ? 1 : n * fact(n - 1); }; console.log(factorial(5)); // 120 // console.log(fact); // ❌ Error! 'fact' is not available outside // The name 'fact' is only available inside the function
Named function expressions allow self-reference but the name is not available outside
Common Mistakes
- Calling function expressions before their definition
- Thinking arrow functions are hoisted like declarations
- Using function declarations when conditional creation is needed
- Expecting named function expression names to be available outside
Interview Tips
- Clearly distinguish declarations vs expressions
- Remember: function declarations = fully hoisted, expressions = variable hoisting
- Arrow functions are always expressions
- Named function expressions help with debugging and recursion