10. Call Stack , Lexical scoping, Closures in javascript

  1. Call Stack

    The call stack is a data structure that keeps track of function calls in LIFO (Last In, First Out) order.

    How It Works?

    1. When a function is called, it's pushed onto the stack.

    2. When the function finishes execution, it's popped off the stack.

    3. The stack continues this process until it's empty.

  1. Execution Context

    The Execution Context is the environment where JavaScript code is executed.

    » It is a wrapper that contain global object and this variable

  2. Lexical Scoping

    Lexcal scoping is the ability of a nested function to access the variable decalred in thier parent function scope

    » If nested function defination written outside but called inside any other function then variable search for outside fucntion defination scope not a function call.

    Example:

//Lexical scoping
var a = 10;
function fn1 (){ 
    console.log("Inside fn1",a);  // function defination of fn1 , access value of varibale a outside its fucntion defination
}

function fn2(){
    var a=20;

    function fn3(){            // access the value of a in its parent function scope
        console.log("Inside fn3",a)
    }

    fn1();                // function call of fn1 
    fn3();

    console.log("Inside fn2",a);
}

fn2();

/* Ouput
Inside fn1 10
Inside fn3 20
Inside fn2 20
  1. Closures

    A closure is created when inner function(nested) remember and continue to access variables from its lexical scope even after the outer function has finished executing.

    Closures = Function + Lexical Scope

function outer() {
    let count = 0;

    return function inner() {
        count++;
        console.log(count);
    };
}

const counter = outer(); // outer function return inner function
counter(); // 1
counter(); // 2         // count updated, inner function remeber previous count defined in outer()
counter(); // 3

inner() remembers count, even after outer() has finished executing.

How can closures be useful?

Answer:
Closures are useful for:

  1. Data Privacy (Encapsulation)

  2. Creating Private Variables

  3. Memoization & Caching

  4. Event Handlers & Callbacks

Interview Questions

  1. What will be the output of following code ?

     function a() {
         console.log("A");
         b();
     }
    
     function b() {
         console.log("B");
         c();
     }
    
     function c() {
         console.log("C");
     }
    
     a();
     console.log("End");
    

    Output:

    A

    B

    C

    End

    The Call Stack order: a()b()c()

    c() finishes first, then b(), and finally a(), before "End" is printed.

  2. Write output ?

     console.log(foo());
     function foo() {
         return "Hello";
     }
    
     console.log(bar());
     var bar = function() {
         return "World";
     };
    
     /* Output
     Hello
     TypeError: bar is not a function
    
  3.   function outer() {
          let a = "Hello";
    
          function inner() {
              let a = "World";
              console.log(a);
          }
    
          inner();
          console.log(a);
      }
    
      outer();
    
      /*
      World
      Hello
    
  4. What will be the output ?

     function counter() {
         let count = 0;
         return function () {
             count++;
             console.log(count);
         };
     }
    
     const c1 = counter();
     c1();
     c1();
    
     const c2 = counter();
     c2();
     c2();
    

    Output :

    1

    2

    1

    2

Next Topic

Built-in functions in JS