0
0
Javascriptprogramming~15 mins

Function hoisting behavior in Javascript - Deep Dive

Choose your learning style9 modes available
Overview - Function hoisting behavior
What is it?
Function hoisting in JavaScript means that function declarations are moved to the top of their containing scope before the code runs. This allows you to call functions before they appear in the code. However, only function declarations are hoisted, not function expressions or arrow functions. Understanding this helps avoid errors and unexpected behavior.
Why it matters
Without function hoisting, you would have to define every function before using it, which can make code less flexible and harder to organize. Hoisting allows developers to write cleaner code by separating function definitions from where they are called. Without it, many programs would throw errors if functions were called too early, causing frustration and bugs.
Where it fits
Before learning function hoisting, you should understand basic JavaScript syntax, functions, and variable declarations. After mastering hoisting, you can learn about scopes, closures, and asynchronous JavaScript, which build on how functions and variables behave in memory.
Mental Model
Core Idea
JavaScript moves function declarations to the top of their scope before running code, so you can call them anywhere in that scope.
Think of it like...
It's like writing a play where the actors rehearse their lines backstage before the show starts, so when the scene begins, they can perform their parts anytime without delay.
Scope Start
│
├─ Function Declaration A (hoisted)
├─ Function Declaration B (hoisted)
├─ Code Execution Starts
│   ├─ Call Function A (works)
│   ├─ Call Function B (works)
│   └─ Other code
└─ Scope End
Build-Up - 7 Steps
1
FoundationWhat is a function declaration?
🤔
Concept: Introduce the basic way to define a function using a declaration.
In JavaScript, a function declaration looks like this: function greet() { console.log('Hello!'); } This defines a function named greet that prints a message.
Result
You have a named function ready to be called anywhere after its definition.
Knowing what a function declaration looks like is essential because only these are hoisted fully in JavaScript.
2
FoundationWhat is a function expression?
🤔
Concept: Show the difference between function declarations and expressions.
A function expression assigns a function to a variable: const greet = function() { console.log('Hello!'); }; Unlike declarations, this function is anonymous and stored in greet.
Result
You have a function stored in a variable, but it behaves differently in hoisting.
Distinguishing expressions from declarations is key because expressions are not hoisted the same way.
3
IntermediateHow function declarations are hoisted
🤔Before reading on: do you think you can call a function before its declaration in code? Commit to yes or no.
Concept: Explain that function declarations are moved to the top of their scope before code runs.
JavaScript moves all function declarations to the top of their scope during compilation. For example: sayHi(); // Works even though sayHi is declared later function sayHi() { console.log('Hi!'); } This works because the function is hoisted.
Result
Calling sayHi before its declaration prints 'Hi!' without errors.
Understanding this explains why some functions can be called before they appear in the code, preventing confusion.
4
IntermediateFunction expressions are NOT hoisted
🤔Before reading on: do you think calling a function expression before its definition works? Commit to yes or no.
Concept: Clarify that function expressions behave like variables and are not hoisted as functions.
Consider: sayHello(); // Error: sayHello is not a function const sayHello = function() { console.log('Hello!'); }; Here, sayHello is undefined at the call time because only the variable declaration is hoisted, not the function assignment.
Result
Calling sayHello before assignment causes a TypeError.
Knowing this prevents runtime errors when using function expressions too early.
5
IntermediateHoisting with var, let, and const variables
🤔Before reading on: do you think variables declared with let or const are hoisted like var? Commit to yes or no.
Concept: Explain how variable declarations affect function expressions and hoisting behavior.
Variables declared with var are hoisted and initialized as undefined, but let and const are hoisted differently: console.log(a); // undefined var a = 5; console.log(b); // ReferenceError let b = 5; Function expressions assigned to var behave differently than those assigned to let or const.
Result
var variables exist before assignment but are undefined; let/const cause errors if accessed too early.
Understanding variable hoisting clarifies why some function expressions cause errors depending on how they are declared.
6
AdvancedHoisting in nested and block scopes
🤔Before reading on: do you think function declarations inside blocks are hoisted outside the block? Commit to yes or no.
Concept: Explore how hoisting behaves inside blocks and nested scopes.
In modern JavaScript (strict mode), function declarations inside blocks are hoisted only within that block: { function insideBlock() { console.log('Inside'); } insideBlock(); // Works } insideBlock(); // Error: not defined This differs from older behavior where some engines hoisted them to the outer scope.
Result
Functions declared inside blocks are only accessible inside those blocks.
Knowing this prevents scope leakage bugs and helps write predictable block-scoped code.
7
ExpertWhy hoisting can cause subtle bugs
🤔Before reading on: do you think hoisting always makes code easier to read and debug? Commit to yes or no.
Concept: Reveal how hoisting can lead to confusing bugs and how to avoid them.
Because functions and variables are hoisted, code can run in unexpected orders: console.log(foo); // undefined var foo = 'bar'; function foo() { return 'baz'; } Here, the function declaration is hoisted above the var, but the var assignment overwrites it, causing confusion. Also, mixing function declarations and expressions can cause shadowing and unexpected results.
Result
Code may behave unpredictably if hoisting interactions are misunderstood.
Understanding hoisting's complexity helps write clearer code and avoid hard-to-find bugs.
Under the Hood
JavaScript engines parse code in two phases: creation and execution. During creation, the engine scans for function declarations and variable declarations, placing function declarations in memory with their full definitions and variables as undefined. This setup is called hoisting. When execution starts, functions are ready to be called anywhere in their scope, but variables only have their declarations, not assignments yet.
Why designed this way?
Hoisting was designed to allow flexible code organization and backward compatibility with older scripting languages. It lets developers write code in a natural order without worrying about declaration placement. Alternatives like requiring declarations before use would limit coding style and readability. However, this design trades off some predictability, which modern JavaScript tries to improve with block scoping and strict mode.
Code Parsing Phase
┌─────────────────────────────┐
│ Scan code top to bottom     │
│ Identify function declarations ──▶ Store full function in memory
│ Identify variable declarations ──▶ Store variable as undefined
└─────────────────────────────┘

Execution Phase
┌─────────────────────────────┐
│ Run code top to bottom       │
│ Functions callable anytime   │
│ Variables have undefined until assigned
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Can you call a function expression before its definition without error? Commit to yes or no.
Common Belief:Function expressions are hoisted just like function declarations.
Tap to reveal reality
Reality:Only the variable declaration is hoisted, not the function assignment, so calling it early causes errors.
Why it matters:Assuming expressions are hoisted leads to runtime errors and broken programs.
Quick: Are variables declared with let hoisted the same way as var? Commit to yes or no.
Common Belief:let and var variables behave the same in hoisting.
Tap to reveal reality
Reality:let variables are hoisted but not initialized, causing a temporal dead zone error if accessed early.
Why it matters:Misunderstanding this causes confusing ReferenceErrors that are hard to debug.
Quick: Do function declarations inside blocks become available outside the block? Commit to yes or no.
Common Belief:Functions declared inside blocks are hoisted to the outer scope.
Tap to reveal reality
Reality:In modern JavaScript, they are block-scoped and not accessible outside the block.
Why it matters:Assuming otherwise causes scope errors and unexpected behavior.
Quick: Does hoisting always make code easier to understand? Commit to yes or no.
Common Belief:Hoisting always improves code readability and reduces bugs.
Tap to reveal reality
Reality:Hoisting can cause subtle bugs and confusion if developers don't understand its rules.
Why it matters:Ignoring hoisting's complexity leads to fragile code and maintenance headaches.
Expert Zone
1
Function declarations are hoisted with their entire body, unlike variables which are only hoisted as undefined placeholders.
2
In strict mode, block-scoped function declarations behave differently than in non-strict mode, affecting hoisting and scope.
3
The order of hoisting between functions and variables with the same name can cause shadowing and overwrite issues.
When NOT to use
Avoid relying on hoisting for code clarity; instead, declare functions before use. Use function expressions or arrow functions with const/let for predictable scoping. For complex scopes, prefer modules or classes to manage visibility explicitly.
Production Patterns
In production, developers often place all function declarations at the top or use modern ES6+ syntax with const and arrow functions to avoid hoisting confusion. Linters and code style guides discourage calling functions before declaration to improve readability and maintainability.
Connections
Variable hoisting
Related concept within JavaScript that explains how variables are moved to the top of their scope.
Understanding variable hoisting clarifies why function expressions behave differently from declarations.
Scope and closures
Builds on hoisting by explaining how functions remember variables in their scope even after execution.
Knowing hoisting helps understand when and where functions and variables exist in memory, which is key to closures.
Compiler phases in programming languages
Hoisting is an example of a compile-time behavior where code is reorganized before execution.
Recognizing hoisting as a compile-time step connects JavaScript behavior to general compiler design principles.
Common Pitfalls
#1Calling a function expression before it is defined causes errors.
Wrong approach:sayHello(); const sayHello = function() { console.log('Hi'); };
Correct approach:const sayHello = function() { console.log('Hi'); }; sayHello();
Root cause:Misunderstanding that only declarations are hoisted fully, while expressions are not.
#2Accessing let or const variables before declaration causes ReferenceError.
Wrong approach:console.log(name); let name = 'Alice';
Correct approach:let name = 'Alice'; console.log(name);
Root cause:Not knowing about the temporal dead zone for let and const variables.
#3Assuming functions declared inside blocks are available outside.
Wrong approach:{ function greet() { console.log('Hi'); } } greet();
Correct approach:{ function greet() { console.log('Hi'); } greet(); }
Root cause:Confusing block scope with function scope and hoisting rules.
Key Takeaways
Function declarations in JavaScript are hoisted with their full definitions, allowing calls before their code appears.
Function expressions and arrow functions are not hoisted as functions; only their variable declarations are hoisted, often as undefined.
Variables declared with var are hoisted and initialized as undefined, but let and const have a temporal dead zone causing errors if accessed early.
Hoisting behavior differs inside blocks and strict mode, affecting function visibility and scope.
Understanding hoisting prevents common bugs and helps write clearer, more predictable JavaScript code.