skip to Main Content

I am relatively new to JavaScript and i can’t wrap around my head on how this code is executing

function foo(i) {
  if (i < 0) {
    return;
  }
  console.log(`begin: ${i}`);
  foo(i - 1);
  console.log(`end: ${i}`);
}
foo(3);

the output of this code is

begin: 3
begin: 2
begin: 1
begin: 0
end: 0
end: 1
end: 2
end: 3

According to my understanding after all logs of begin statement, only one log with end statement should get printed that too with -1 value

begin: 3
begin: 2
begin: 1
begin: 0
end: -1 

As I gets decremented from 0 by -1, the if statement condition becomes true and returns the flow to next line of recursive function and prints end: -1 and ends the program.
I have an intuition that this might be a silly question but I still want to know where am I lacking. Help would be appreciated

3

Answers


  1. i is not decremented, the value i-1 is passed as the value when foo is recursively called. When the value passed into foo is -1, it returns before anything is console logged, and goes up a level to where i is 0.

    console.log(`end: ${i}`); prints out that value, and then the function implicitly returns up to the next level where i is 1. And so on from there.

    Login or Signup to reply.
  2. The flow is like this

       Foo(3)
          Begin 3
          Foo(2)
            Begin 2
            Foo(1)
              Begin 1
              Foo(0)
                Begin 0
                Foo(-1) returns
                End 0
              End 1
            End 2
          End 3
    
    Login or Signup to reply.
  3. When you call a function, you don’t enter that function’s definition. You enter that function definition’s copy.

    Each invocation of a function is separate. It doesn’t matter what’s the name of that function. Whether it’s the same name of some other name — each invocation is new. It copies the corresponding definition, and works on the fresh copy.

    Imagine you call foo(1) in your example. Then your snippet is the same as

    function foo1(i1) { // i1 here is 1
      if (i1 < 0) {
        return;
      }
      console.log(`begin: ${i1}`);
      foo0(i1 - 1);
      console.log(`end: ${i1}`);
    }
    function foo0(i0) {  // i0 here is 0
      if (i0 < 0) {
        return;
      }
      console.log(`begin: ${i0}`);
      foo_1(i0 - 1);
      console.log(`end: ${i0}`);
    }
    function foo_1(i_1) {  // i_1 here is -1
      if (i_1 < 0) {
        return;        // return is called
      }
      console.log(`begin: ${i_1}`);   // these lines
      foo_2(i_1 - 1);                 // are not
      console.log(`end: ${i_1}`);     //   executed
    }
    foo1(1);
    

    You are probably not surprised that these i_nnns in these different functions do not interfere with each other. But it’s the same thing even with the same function foo called everywhere instead of these foo_nnns. Because each call to foo copies the same definition and works on the new, fresh copy of it, as if it got a new name foo_nnn like here above, working on its own set of its inner variables i_nnn.

    So then it is non-surprising that the above execution proceeds as

    foo1(1);
    

    which is

    //foo1(1):
      ///// i1==1 ////
      if (i1 < 0) { return; }       // i1==1
      console.log(`begin: ${i1}`);  // i1==1
      foo0(i1 - 1);
      // function foo1 continues
      console.log(`end: ${i1}`);    // i1==1
      // end of function foo1
    

    and this is the same as

    //foo1(1):
      //// i1==1 ////
      if (i1 < 0) { return; }       // i1==1 ; 1<0 is false
      console.log(`begin: ${i1}`);  // i1==1
      //foo0(0):
              //// i0==0 ////
              if (i0 < 0) { return; }       // i0==0 ; 0<0 is false
              console.log(`begin: ${i0}`);  // i0==0
              foo_1(-1);
              // function foo0 continues
              console.log(`begin: ${i0}`);  // i0==0
              // end of function foo0
      // function foo1 continues
      console.log(`end: ${i1}`);    // i1==1
      // end of function foo1
    

    and this is the same as

    //foo1(1):
      //// i1==1 ////
      if (i1 < 0) { return; }       // i1==1 ; 1<0 is false
      console.log(`begin: ${i1}`);  // i1==1
      //foo0(0):
              //// i0==0 ////
              if (i0 < 0) { return; }       // i0==0 ; 0<0 is false
              console.log(`begin: ${i0}`);  // i0==0
              //foo_1(-1):
                      //// i_1== -1 ////
                      if (i_1 < 0) { return; }   // i_1== -1 ; -1<0 is true
                      // the function foo_1 is exited i.e.
                      //    nothing is printed and no more calls are made
                      // end of function foo_1
              // function foo0 continues
              console.log(`begin: ${i0}`);  // i0==0
              // end of function foo0
      // function foo1 continues
      console.log(`end: ${i1}`);    // i1==1
      // end of function foo1
    

    Now, replace all foo_nnn in the above with foo.

    Nothing changes.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search