Recursion
Recursion is a technique in which a function calls itself. A big task is reduced to the same task but slightly smaller, and so on until it becomes trivial. Recursion is handy for walking nested structures: folders with subfolders, comments with replies, menus with submenus.
A function calls itself
A recursive function calls itself in its body with a different argument. Here is a countdown:
function countdown(n) {
if (n === 0) {
return;
}
console.log(n);
countdown(n - 1);
}
countdown(3);
// 3
// 2
// 1Each call prints a number and passes a number one smaller to the next call.
The base case
The condition under which the function stops calling itself is called the base case. In the example above it is n === 0: on reaching zero, the function simply ends. Without a base case the recursion would never finish. That is why you start writing a recursive function with it: first solve the simplest version of the task, then reduce the rest to it.
Returning a result
A recursive function can return a value. The sum of the numbers from 1 to n can be described like this: it is n plus the sum of the numbers from 1 to n - 1:
function sumTo(n) {
if (n === 1) {
return 1;
}
return n + sumTo(n - 1);
}
console.log(sumTo(4)); // 10The call sumTo(4) becomes 4 + sumTo(3), then 4 + 3 + sumTo(2) and finally 4 + 3 + 2 + 1.
Factorial
The classic example of recursion is the factorial: the product of all numbers from 1 to n. The factorial of 5 is 5 * 4 * 3 * 2 * 1:
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120The call stack
While a nested call is working, the outer one waits for its result. JavaScript keeps the waiting calls in the call stack — a list where new calls are placed on top and removed when they finish. The stack has a limited size — usually a few thousand calls — so very deep recursion will not work.
Recursion or a loop
Any recursion can be replaced with a loop and vice versa. For simple counting a loop is clearer and does not use up the stack:
let result = 1;
for (let i = 2; i <= 5; i++) {
result *= i;
}
console.log(result); // 120Recursion is chosen when the data itself is recursive — like a folder tree or nested comments.
Common mistake
If you forget the base case, or the argument does not move towards it, the function calls itself forever. The stack overflows, and the program stops with an error:
function countdown(n) {
countdown(n - 1); // no exit condition
}
countdown(3); // RangeError: Maximum call stack size exceededBefore running a recursive function, check two things: is there a base case, and does the argument get closer to it with every call?