Skip to content
ByteStepStart with recursion

Recursion: how a function calls itself

Free, no account

When one function calls another, the first stops where it is, the second runs, and the first carries on from exactly where it paused. Recursion is that, with one change: the function it calls is itself.

Which raises two questions at once. If it keeps calling itself, what makes it ever stop? And if four copies are running at the same time, each with a different n, how does any of them remember which n was theirs? Both answers are below. Press play.

1function factorial(n) {
2 if (n <= 1) return 1
3 const smaller = factorial(n - 1)
4 return n * smaller
5}

Call tree

every call, and who called it

4

Call stack

what each one is holding

  1. factorial(4)line 1
    n = 4

1 frame

We start with factorial(4). Nothing has been worked out yet. It is a question waiting for an answer.

1/10
Detail
10 steps

What is happening, why it stops, and how each call keeps its own values.

What is actually happening

A call that is too big to answer outright hands a smaller version of the same question to a fresh copy of itself, and then waits. That copy does the same. Sooner or later a copy gets a question small enough to answer with no help at all. That is the base case, and it hands its answer straight back. Every waiting call then wakes in turn, finishes its own bit of work, and passes its answer up.

So nothing is worked out on the way down. The descent only breaks the problem into smaller pieces. The answer is built on the way back up.

Why it stops

Every recursive function has two branches, and it needs both. The recursive case is the one that calls itself, always on a smaller input than it was given. The base case is the one that answers directly, with no call at all.

The input shrinking is what guarantees you reach the base case. Remove the base case and nothing ever stops the descent; stop shrinking the input and you never arrive at it. Either mistake produces the same symptom, which is why they are worth separating in your head.

How each call remembers its own n

When a call is interrupted it needs somewhere to keep the values it was working with, so they are still there when it resumes. That somewhere is a stack frame: a small block holding this call's n, and the point in the code to carry on from.

Frames are kept on the call stack, which is a stack in the ordinary sense: added to and removed from one end only. Look at the frames beside the animation while it runs. Four calls in flight means four frames, each holding a different n at the same moment. They are not sharing one variable and taking turns. Each call got its own.

That is the whole answer to “how does it remember?”. It does not have to remember. Nothing ever overwrote it.

Where the answer goes

When a call finishes it hands back a return value, and that value goes to exactly one place: the call that was waiting for it, which resumes on the very line where it paused. Nothing is broadcast and nothing jumps back to the start.

Watch the highlighted line as you step. With factorial, line 3 makes the call and line 4 does the multiplication. Line 4 cannot run until line 3 has produced a value, and that is the whole reason the work happens on the way back up.

Now switch to countdown and the order flips. It prints before it calls itself, so all of its work happens on the way down and the return journey does nothing at all. Same shape, opposite timing.

Know someone stuck on this? Send it to them.

A classmate, a study group, someone learning this on their own at midnight. The link opens the lesson set up exactly as you have it, the same function and the same number, and runs from the first step so they watch the whole thing build rather than landing in the middle of it.

Next in this course

The call stack, and what “stack overflow” means

The same frames you just watched, but with a ceiling, and what happens when a program reaches it.

Start there →