JavaScript Notes
Master JavaScript recursion with call stack diagrams, factorial, Fibonacci, tree traversal, base case rules, tail recursion, stack overflow prevention, and 8 interview Q&As.
Introduction
Recursion is a technique where a function calls itself to solve a smaller version of the same problem, until it reaches a simple case it can solve directly.
Recursion is essential for working with:
- Nested data structures (trees, graphs, nested arrays)
- Mathematical sequences (factorial, Fibonacci, power)
- Divide-and-conquer algorithms
- File system traversal
- DOM traversal
Many problems that feel complicated with loops become elegant and natural with recursion.
Real World Analogy
Recursion is like Russian nesting dolls (Matryoshka). You open a doll → inside is a smaller doll You open that doll → inside is an even smaller doll ... Until you reach the smallest doll that doesn't open (base case) Then you put them all back together in reverse. Each recursive call = opening a doll Base case = smallest doll Return values bubbling up = putting the dolls back together
Basic Example: Countdown
function countdown(n) {
if (n <= 0) { // BASE CASE
console.log("Done!");
return;
}
console.log(n);
countdown(n - 1); // RECURSIVE CASE – smaller n
}
countdown(5);5 4 3 2 1 Done!
Call Stack Diagram – Countdown
Factorial – Classic Recursion
n! = n × (n-1) × (n-2) × ... × 1
function factorial(n) {
if (n <= 1) return 1; // BASE CASE: 0! = 1, 1! = 1
return n * factorial(n - 1); // RECURSIVE CASE
}
console.log(factorial(5));
console.log(factorial(0));
console.log(factorial(1));120 1 1
Call Stack Trace for factorial(5):
factorial(5)
→ 5 * factorial(4)
→ 4 * factorial(3)
→ 3 * factorial(2)
→ 2 * factorial(1)
→ returns 1 ← BASE CASE
← 2 * 1 = 2
← 3 * 2 = 6
← 4 * 6 = 24
← 5 * 24 = 120Fibonacci – Two Recursive Calls
The Fibonacci sequence: 0, 1, 1, 2, 3, 5, 8, 13, 21... fib(n) = fib(n-1) + fib(n-2)
function fibonacci(n) {
if (n === 0) return 0; // BASE CASE
if (n === 1) return 1; // BASE CASE
return fibonacci(n - 1) + fibonacci(n - 2); // RECURSIVE CASE
}
console.log(fibonacci(6));
console.log(fibonacci(10));8 55
Recursion Tree for fibonacci(4):
fib(4)
/ \
fib(3) fib(2)
/ \ / \
fib(2) fib(1) fib(1) fib(0)
/ \ ↓ ↓ ↓
fib(1) fib(0) 1 1 0
↓ ↓
1 0
Values bubble up:
fib(2) = 1+0 = 1
fib(3) = 1+1 = 2
fib(4) = 2+1 = 3 ← wait... let's trace exactly:
fib(4) = fib(3) + fib(2)
= (fib(2)+fib(1)) + (fib(1)+fib(0))
= ((fib(1)+fib(0))+1) + (1+0)
= ((1+0)+1) + 1
= 2 + 1 = 3⚠️ Plain Fibonacci recursion has exponential time complexity O(2ⁿ) because it recalculates the same values. Use memoization to fix this.
Fibonacci with Memoization
55 102334155
Recursion on Arrays – Sum All Elements
15
Recursion – Flatten Nested Array
[1, 2, 3, 4, 5, 6, 7]
Power Function – Recursion on Math
function power(base, exp) {
if (exp === 0) return 1; // BASE CASE: x⁰ = 1
return base * power(base, exp - 1); // RECURSIVE CASE
}
console.log(power(2, 8)); // 2⁸
console.log(power(3, 4)); // 3⁴256 81
Recursion vs Iteration
120 120
| Iteration | Recursion | |
|---|---|---|
| Memory usage | O(1) – one loop variable | O(n) – n stack frames |
| Readability | More explicit | Often more elegant |
| Best for | Simple loops | Trees, nested structures |
| Risk | None | Stack overflow on deep calls |
| Performance | Usually faster | Overhead of function calls |
Stack Overflow – What Happens Without a Base Case
// DANGEROUS – no base case → infinite recursion → stack overflow
function infinite(n) {
console.log(n);
infinite(n + 1); // never stops!
}
// infinite(1); // → RangeError: Maximum call stack size exceededRangeError: Maximum call stack size exceeded
JavaScript has a call stack limit (usually ~10,000-15,000 frames). Every recursive call adds a frame. Without a base case, you hit the limit.
Common Mistakes
❌ Mistake 1: Missing or wrong base case
// WRONG – base case never reached for positive numbers
function countdown(n) {
console.log(n);
if (n === 0) return; // too late – should check BEFORE printing
countdown(n - 1);
}
// CORRECT – check before acting
function countdown(n) {
if (n < 0) return; // safe base case
console.log(n);
countdown(n - 1);
}
countdown(3);3 2 1 0
❌ Mistake 2: Not making the problem smaller
// WRONG – n never changes → infinite loop
function count(n) {
if (n === 0) return;
console.log(n);
count(n); // should be count(n - 1)!
}Every recursive call must move toward the base case.
❌ Mistake 3: Ignoring the return value
// WRONG – returns undefined because outer call ignores return
function sum(n) {
if (n === 0) return 0;
sum(n - 1) + n; // computed but not returned!
}
console.log(sum(5)); // undefined// CORRECT
function sum(n) {
if (n === 0) return 0;
return sum(n - 1) + n;
}
console.log(sum(5));15
❌ Mistake 4: Redundant computation without memoization
// SLOW for large n – same sub-problems computed repeatedly
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
// fib(50) takes billions of operations!12586269025
Real-World Recursion: Tree/Object Deep Count
6
Interview Questions
Q1. What is recursion in JavaScript?
Recursion is when a function calls itself with a smaller or simpler version of the problem, continuing until it reaches a base case that it can solve directly without another call.
Q2. What are the two essential parts of every recursive function?
- Base case – the stopping condition that returns a direct value without recursing
- Recursive case – the self-call with a simpler/smaller input that moves toward the base case
Q3. What is a stack overflow in the context of recursion?
A stack overflow occurs when a recursive function calls itself too many times without reaching the base case, exhausting the call stack's memory limit. JavaScript throws RangeError: Maximum call stack size exceeded.
Q4. How is the call stack involved in recursion?
Each recursive call adds a new frame to the call stack. The frames accumulate until the base case is reached, then they unwind as each call returns its value back up the chain.
Q5. When should you use recursion instead of iteration?
Use recursion when the problem has a naturally recursive structure — like tree traversal, nested data processing, or divide-and-conquer algorithms. For simple loops over flat data, iteration is usually more efficient.
Q6. What is memoization and how does it help recursive functions?
Memoization caches the results of expensive function calls so they are not computed again for the same inputs. It transforms exponential recursion (like naive Fibonacci) into linear time.
Q7. What is the difference between direct and indirect recursion?
- Direct recursion: Function A calls itself
- Indirect recursion: Function A calls Function B which calls Function A (mutual recursion)
Q8. Write a recursive function to find the maximum number in a nested array.
12
Key Takeaways
- ✅ Recursion = function calling itself with a smaller problem
- ✅ Every recursive function MUST have a base case (stops recursion)
- ✅ Every recursive call MUST move closer to the base case
- ✅ Each call adds a frame to the call stack — too deep = stack overflow
- ✅ Use memoization to optimize repeated sub-problems
- ✅ Recursion shines for trees, nested data, and divide-and-conquer
- ✅ Iteration is usually more memory-efficient for flat loops
- ✅ Always return the recursive result:
return fn(smaller)not justfn(smaller)
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Recursion Tutorial – Call Stack, Base Case & Recursive Patterns.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, functions, recursion, javascript recursion tutorial – call stack, base case & recursive patterns
Related JavaScript Master Course Topics