mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2025-12-19 18:18:27 -05:00
feat(curriculum): add interactive examples to recursion and call stack lesson (#63679)
Co-authored-by: Huyen Nguyen <25715018+huyenltnguyen@users.noreply.github.com>
This commit is contained in:
@@ -5,55 +5,69 @@ challengeType: 19
|
||||
dashedName: what-is-recursion-and-how-does-it-work
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Let's learn how recursion works in JavaScript.
|
||||
# --interactive--
|
||||
|
||||
Recursion is a complicated feature that allows you to call a function repeatedly until a base-case is reached. Unlike a traditional loop, recursion allows you to handle something with an unknown depth, such as deeply nested objects/arrays, or a file tree. But you can also use it for more basic tasks, such as counting down from a given number.
|
||||
|
||||
Let's construct a function to do exactly that. We’ll call our function `recursiveCountdown`, and it needs to accept a number. We’ll have it print this number to the console:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const recursiveCountdown = (number) => {
|
||||
console.log(number);
|
||||
};
|
||||
|
||||
recursiveCountdown(5);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Now if we call this and pass the number 5, we’ll see the number print to our terminal. But nothing else happens – and the number 5 certainly isn’t a countdown.
|
||||
|
||||
Before we start building the recursive portion of our function, we need to establish our base case first. If you don’t have a base case established, your code will run until it exceeds your memory allocation and crashes.
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const recursiveCountdown = (number) => {
|
||||
if (number < 1) {
|
||||
return;
|
||||
}
|
||||
console.log(number);
|
||||
};
|
||||
if (number < 1) {
|
||||
return;
|
||||
}
|
||||
console.log(number);
|
||||
};
|
||||
|
||||
recursiveCountdown(5);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
For our base case, we want the countdown to stop if the number is less than 1. When we hit that base-case, we can return to break out of the function execution.
|
||||
|
||||
Now that we’ve safely prepared a base-case, we can set up the recursion. The key point that makes a function recursive is that it calls itself in its execution. In this case, we want to call the function after we print the number. But in order to count down, our new number needs to be one less:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const recursiveCountdown = (number) => {
|
||||
if (number < 1) {
|
||||
return;
|
||||
}
|
||||
console.log(number);
|
||||
recursiveCountdown(number - 1);
|
||||
};
|
||||
if (number < 1) {
|
||||
return;
|
||||
}
|
||||
console.log(number);
|
||||
recursiveCountdown(number - 1);
|
||||
};
|
||||
|
||||
recursiveCountdown(5); //
|
||||
recursiveCountdown(5);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
This would log the numbers 5, 4, 3, 2, and 1 to the console.
|
||||
|
||||
We do get our five numbers! But what if we wanted to count up instead? Rather than writing an entirely new function, we can swap the order of our log and our recursive call:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const recursiveCountdown = (number) => {
|
||||
if (number < 1) {
|
||||
@@ -66,25 +80,31 @@ const recursiveCountdown = (number) => {
|
||||
recursiveCountdown(5);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
This would log the numbers 1, 2, 3, 4, and 5 to the console.
|
||||
|
||||
But why does that work? Well, to understand this you need to understand the call stack. The call stack is how JavaScript tracks and resolves function calls. The stack functions as a last-in-first-out queue of sorts. To understand this better, let’s add some logging to our function:
|
||||
|
||||
:::interactive_editor
|
||||
|
||||
```js
|
||||
const recursiveCountdown = (number) => {
|
||||
console.log(`Function execution started for number: ${number}`);
|
||||
if (number < 1) {
|
||||
console.log(`Base case reached, begin resolving stack`);
|
||||
return;
|
||||
}
|
||||
console.log(`Calling recursiveCountdown with number: ${number - 1}`);
|
||||
recursiveCountdown(number - 1);
|
||||
console.log(`Function execution completed for number: ${number}`);
|
||||
};
|
||||
console.log(`Function execution started for number: ${number}`);
|
||||
if (number < 1) {
|
||||
console.log(`Base case reached, begin resolving stack`);
|
||||
return;
|
||||
}
|
||||
console.log(`Calling recursiveCountdown with number: ${number - 1}`);
|
||||
recursiveCountdown(number - 1);
|
||||
console.log(`Function execution completed for number: ${number}`);
|
||||
};
|
||||
|
||||
recursiveCountdown(5);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
We’ve added four key statements here. The first log runs when a function call begins executing. The third log runs just before the recursive function is called. And the fourth log runs when the function execution has ended. The result is:
|
||||
|
||||
```md
|
||||
|
||||
Reference in New Issue
Block a user