Question from "recursion in javascript review: factorials"


#1

This code works but I am still trying to fully understand recursion. So if I change this:

// Write a function to get the factorial of a number.
var factorial = function(int){
    if(int === 0){
        return 1;
    } else {
        int = int * factorial(int - 1);
        return int;
    }
};
    
factorial(6);

TO THIS:

// Write a function to get the factorial of a number.
var factorial = function(int){
    if(int === 0){
        console.log("Why does it log this twice? And where does the returned 1 go?");
        return 1;
    } else {
        int = int * factorial(int - 1);
        return int;
    }
};
    
factorial(6);

Why does it log the console command twice? Why do we need to return 1 if we have already returned the factorial, in this case 720? If you change "return 1" to "return 2" int changes from 720 to 1440, so does "return 1" actually mean "multiply int by 1"?

I could not find the section in the category list so here is a link to the section: https://www.codecademy.com/courses/javascript-lesson-205/0/1

review: factorials section is near the end.

Edit: Similarly, in the next section: "Protecting against errors and crashes" we write in a termination condition for the event that int is a negative number.

// Write a function to get the factorial of a number.
var factorial = function(int){
    if(int === 0){
        return 1;
    } else if(int < 0){
        alert("You chose a negative number");
        return;
    } else {
        int = int * factorial(int - 1);
        return int;
    }
};
    
factorial(6);

It works for the lesson criteria, but it always alerts an error message, even if you are running the function on a positive number. How can this be right? Seems like its ignoring the conditional and just running the code each time.


#3

The output of your second code is:

Why does it log this twice? And where does the returned 1 go?

So it only logs it once

Your third piece of code.. what error message? It runs successfully on my end


So.. it would seem that your questions have more to do with how you are running your code, than with the code itself!


#4

I tried the second piece of code in a different Codecademy editor and it only logged once. I tried the same code in the FreeCodeCamp editor and it is logging twice (the same as it was doing in my original Codecademy editor). Is there a better way I should be testing this?

The alert message in the third piece of code works properly in the FreeCodeCamp editor, so I'm not sure why it wasn't working in the original Codecademy editor.


#5

Run it in your browser or with nodejs



index.html

<!doctype html>
<head>
    <script>
var factorial = function(n){
    if(n === 0){
        return 1;
    } else if(n < 0){
        throw new Error("You chose a negative number");
        return;
    } else {
        n = n * factorial(n - 1);
        return n;
    }
};

alert(factorial(6));
alert(factorial(-6));
    </script>
</head>

Or use script's src attribute and put the code in a separate .js file


#6

Works fine. I'm relieved that the problem wasn't in the code, I guess. Although I'm still not sure how the base case works.
Why does return 1; work but return; gives a null?


#7

factorial 0 is 1
factorial 0 is not null, so returning null would be wrong


#8

When you use return; in the Codecademy editor, it produces a null. Why?


#9

What does return 1; do in this code? I'm just trying to understand how to think about it. If I were going to run the calcs by hand, what would I do when I got to return 1;?


#10

0 is the most basic case, it can't be made into a smaller problem. It's defined as 1.
For larger numbers the problem is split in two parts, the current number and the factorial of the next number


#11

Ok, so I tried to run the code by hand and here is my confusion. To me, it seems like it should be written like this:

var factorial = function(n){
    if(n === 1){
        return 1;
    } else if(n < 1){
        throw new Error("You chose zero or a negative number");
        return;
    } else {
        n = n * factorial(n - 1);
        return n;
    }
};

alert(factorial(6));
alert(factorial(-6));

But then factorial(0) returns the negative number alert. So I'm going to go read up on why factorial(0) = 1.


#12

1.

Why does it log the console command twice?

Read my answer, please:


2.

Why do we need to return 1 if we have already returned the factorial, in this case 720?

The return statement ends function execution and specifies a value to be returned to the function caller. So

factorial(6); // you call function first tome

// it means

// 1st call
var factorial = function(6) { 
    if(6 === 0){ // returns false
        console.log("Why does it log this twice? And where does the returned 1 go?");
        return 1;
    } else {
        // here you call function once more but in this time argument int = 6 - 1
        int = 6* factorial(6 - 1);
        return int; // this line is not executed while previous line didn't finish calling the function 6 times
    }
};

// 2nd call
var factorial = function(5) { 
    if(5 === 0){ // returns false
        console.log("Why does it log this twice? And where does the returned 1 go?");
        return 1;
    } else {
        // here you call function once more but in this time argument int = 6 - 1
        int = 5 * factorial(5 - 1); 
        return int; // this line is not executed while previous line didn't finish calling the function 5 times
    }
};
...

// 6th call
// when int = 0 and if(int === 0) returns true
var factorial = function(0) { 
    if(0 === 0){ // returns true
        console.log("Why does it log this twice? And where does the returned 1 go?");
        return 1; // ends recursive function execution and returns it value
    } else {
        // this part doesn't execute when int = 0
        int = int * factorial(int - 1); 
        return int;
    }
};

When recursion calling was stopped, only after that return int; ends execution for factorial() function. So, condition int === 0 tells for function when recursion calling should be stopped.


3

Why does return 1; work but return; gives a null?

When a return statement is called in a function, the execution of this function is stopped. If specified, a given value is returned to the function caller. If the expression is omitted, undefined is returned instead:

Accoring to this description we can rewrite your function:

var factorial = function (int) {  
  if (int === 0) {
    return 1;
  } else if (int < 0) {
    alert("You chose a negative number");
    return;
  }
 
  return int * factorial(int - 1);
};

console.log(factorial(6));

Sorry for very, very, VERY long post, but I hope it helps you.


#13

So if I understand this correctly, the first time the function returns a value is when int === 0. While its performing the first 5 calls its not actually returning anything its just filling in the int = int * factorial(int - 1); for each integer between the our argument and 0. And then once it reaches 0 it runs back through the int = int * factorial(int - 1);'s that were set up before. It ends the recursion because its not calling the function in the base case so it can run to the final return int;. Am I understanding this correctly?


#14

This condition check every 6 times but returns true only at the last iteration.

Am I understanding this correctly?

Almost, yep. This part:

It ends the recursion because its not calling the function in the base case so it can run to the final return int

It ends the recursion because we used return 1; statement which ends factorial(int - 1) execution. So, base case is:

if (int === 0) {
    return 1;
}

that stops the recursion.

else if (int < 0) {
    alert("You chose a negative number");
    return;
}

It's condition describes a statement that will cancel recursion in the event of bad input (when int < 0) and exit from the function.


#15

Just the "return" part ends the execution right? I think this takes me back to my original problem which is if it is returning a value of 1, then what is receiving that value? return 2; gives an output of twice the factorial and return int; gives a zero? What does that bit of code actually do here?


#16

Just the "return" part ends the execution right?

The following return statements all break the function execution:

return;
return true;
return false;
return x;
return x + y / 3;

In case when return 1; or return 2; break the function execution and also returns it value (1 and 2).

When recursion is working, result looks like this:

6 * 5 * 4 * 3 * 2 * 1

The last multiplier I've got when int === 0 and base condition returned 1.
If return 2; then:

6 * 5 * 4 * 3 * 2 * 2

Once more:

When a return statement is called in a function, the execution of this function is stopped. If specified, a given value is returned to the function caller. If the expression is omitted, undefined is returned instead.


#17

Ok, so it returns its value to function caller. What is the function caller in this example? The recursion statement?

And it its not actually returning int each time it calls, does it have to work back through them all to figure out the final answer?

You say here that return int; does not execute while in recursion but that it also does not execute while int === 0, so how do we get from a returned value of 1 from the base case to 720?


#18

Knowing factorial(x), you can trivially compute factorial(x+1) with factorial(x) * (x+1)

factorial(0) is defined as 1, no computation involved.

Since factorial(0) is known, factorial(1) can be computed, and therefore also factorial(2), factorial(3), and so on ad infinitum


Each time factorial is called, it does a small very trivial step, nothing is behaving differently, just refer to what the function should be doing for each value of the input


#19

return 1; stop execution of recursive calling factorial(int - 1); in line:

int = int * factorial(int - 1);

So, when it work is done then

return int;

will run.


Ok, so it returns its value to function caller. What is the function caller in this example? The recursion statement?

value is 1
function caller is factorial(int - 1)


#20

If you really want to know how recursion works, put breakpoint at line int = int * factorial(int - 1); and try to debug.

Paste this code into the browser console:

// Write a function to get the factorial of a number.
var factorial = function(int){
    if(int === 0){
        console.log("Why does it log this twice? And where does the returned 1 go?");
        return 1;
    } else {
        debugger;
        int = int * factorial(int - 1);
        return int;
    }
};

debugger;
factorial(6);

#21

Forgive me, I am very new to all of this. I am trying to understand these concepts so that I can visualize what is actually happening when the code executes. This is how I must understand it in order to reproduce it on my own. I don't think I am being clear enough in explaining my problems so I am going to go start the lessons over. Thank you for your help.