🔹 What is Recursion?
Recursion is a technique where a function calls itself to solve a problem by breaking it into smaller subproblems of the same type.
We use recursion when a problem can be broken into smaller copies of itself. The function keeps calling itself until it reaches the simplest form — called the base case — and then starts returning results.
🧠 Explanation:
You solve the big problem by solving a smaller version of it.
This keeps happening until you reach the smallest problem (called the base case), which can be solved directly.
💡 Real-Life Analogy:
Imagine you ask a person:
"How many people are in front of you in this line?"
They ask the next person... and so on, until the last person says “Zero.”
That’s the base case. Each person adds 1 to the answer and passes it back.
Two Parts of Recursion
1. Base Case
In recursion, a base case is a condition that tells the function when to stop calling itself.
Every time a recursive function calls itself, the computer creates a new Function Execution Context and puts it on the call stack.
A Function Execution Context is like a container that stores all the information needed to run that specific function call—such as the values of variables and where to return after the function finishes.
The call stack keeps track of all these unfinished function calls, so the computer knows which one to finish next.
The base case prevents infinite recursion by stopping the function from calling itself forever, which avoids a stack overflow error.
2. Recursive Case
The recursive case is the part of the function where the function calls itself with a smaller or simpler input.
This helps break down the original problem into smaller problems, moving it closer to the base case.
Without the recursive case, the function wouldn’t repeat the process needed to solve bigger problems step by step.
Together, the recursive case and base case work to solve the problem safely and efficiently.
function countDown(n) {
if (n === 0) return; // Base Case
console.log(n);
countDown(n - 1); // Recursive Case
}
countDown(3)
🔹 How Recursion Works inside Call Stack
- The function keeps calling itself with smaller inputs.
- Each new call adds a new Function Execution Context with that input to the call stack.
- Once the base case is reached, the recursion stops going deeper.
- Then, the function calls start finishing one by one, unwinding the call stack in reverse order.
- This process allows the program to solve the problem step by step as it returns from each call.
💡 Example: countDown(3)
countDown(3)
-> countDown(2)
-> countDown(1)
-> countDown(0) // base case reached
Simple Examples
📉 Print 5 to 1:
function printDescending(n) {
if (n < 1) return;
console.log(n);
printDescending(n - 1);
}
📈 Print 1 to 5:
function printAscending(n, i = 1) {
if (i > n) return;
console.log(i);
printAscending(n, i + 1);
}
Reverse a String
function reverse(str) {
if (str === "") return "";
return reverse(str.slice(1)) + str[0];
}
⚠️ Infinite Loop: Simple Explanation
1️⃣ What is an Infinite Loop?
An infinite loop happens when your code keeps running forever and never stops.
It can make your program freeze or crash.
2️⃣ Infinite Loop with Loops
Example:
while (true) {
console.log("Hello");
}
- The condition true is always
true
, so the loop never ends. - It will print “Hello” forever.
3️⃣ Infinite Loop with Recursion (Infinite Recursion)
function printNamaste() {
console.log("Namaste");
printNamaste(); // Function calls itself without a base case
}
printNamaste();
The function calls itself again and again without stopping.
It keeps printing “Namaste” forever.
This will crash the program because it uses too much memory (stack overflow).
4️⃣ Why Are Infinite Loops Bad?
- They make your program get stuck and stop working.
- They use a lot of computer memory and power.
- They are hard to fix if you don’t know where the loop is.
5️⃣ How to Stop Infinite Loops
- For recursion, always have a base case — a condition to stop.
- For loops, make sure the loop condition will become false someday.
- Test your code with small numbers or steps.
⚠️ Stack Overflow
If there's no base case, the function keeps calling itself endlessly — eventually causing a stack overflow error.
💥 Why does this happen?
Each recursive call is added to the call stack (a special memory area).
Without a base case or if it’s never reached, recursion runs indefinitely.
This exhausts the stack memory, causing your program to crash with a "maximum call stack size exceeded" error.
📦 The Stack Has a Limit
The call stack has limited space.
It can only hold a certain number of function calls at a time.
If a function keeps calling itself without stopping, it keeps adding new calls to the stack.
Eventually, the stack runs out of space.
When this happens, the program crashes with a stack overflow error.
🧪 Common causes of stack overflow in recursion:
- ❌ Missing a base case
- ❌ Incorrect base case condition (e.g., using
if (n < 0)
instead ofif (n == 0)
) - ❌ Recursive calls that move away from the base case (e.g.,
recurse(n + 1)
instead ofrecurse(n - 1)
)
✅ How to avoid it:
- Always define a clear base case to stop recursion.
- Ensure each recursive call progresses towards the base case.
- Test your function with small inputs first.
- Use debugging tools or print statements to follow the recursion flow.
When to Use Recursion
✅ Use recursion for:
- Tree-like structures (e.g., DOM, file folders)
- Nested or hierarchical data (e.g., comments)
- Mathematical problems (factorial, Fibonacci)
- Backtracking problems (e.g., maze solving, subsets)
❌ Avoid recursion when:
- A simple loop can solve the problem more efficiently
- Stack size limitations could cause overflow errors
Recursion vs Loop
Feature | Recursion | Loop |
---|---|---|
Calls | Function calls itself | Repeats using for or while loops |
Memory | Uses call stack (higher memory use) | More memory efficient |
Best for | Nested or tree-like data | Straightforward, linear tasks |
Readability | Cleaner for complex/nested problems | Easier for simple tasks |
Performance | Slower due to function call overhead | Generally faster |
Base case | Must have a base case to stop | Stops when loop condition fails |
Risk | Can cause stack overflow | No stack overflow risk |
Debugging | Harder due to multiple call frames | Easier to debug |
Use case examples | Tree traversal, backtracking | Counting, summing, iteration |
Tail call support | Optimized in some languages | Not applicable |
Top comments (0)