Search code examples
javascriptweblexical-scope

Could anyone please explain this behavior of function inside another function?


I was trying to understand lexical scoping in Javascript. In the below example, I have written a function inside an another function. When I run this, I would expect to pop-up "dad" in the first alert and "mom" in the second alert. But what actually happens is, it shows "undefined" in the first pop-up and "mom" in the second.

function first(){
  var x = "dad"; 
  function second(){
    alert(x);
    var x = "mom";
    alert(x);
  }
  second();
}
first();

Can someone please explain why variable "x" defined in parent function is not visible in the child function? Strangely, when I remove the declaration for variable "x" inside the child function, it works fine. Could someone give insight of the lexical scoping scenario valid here?


Solution

  • You re-declared x in second by using a var statement after the alert. This makes it a different x than the one declared in first.

    Furthermore, JavaScript uses a technique called hoisting. When a variable is declared in a scope, that declaration is moved to the top of the scope during a pre-execution pass. If declaration and assignment are being done in one statement, the declaration is broken away from the assigment. Declaration is moved to the top of the scope, causing an undefined variable, while assigment is left where it origianally was.

    The resulting code after the pre-pass is something like below (I've only showed hoisting of variables here and left functions alone)

    function first(){
        var x;
        x = "dad";
        function second(){
            var x; //new variable in local scope, declared not defined
            alert(x); //alerts undefined
            x = "mom"; //defines local `x` as "mom"
            alert(x); //alerts "mom"
        }
        second();
    }
    first();
    

    Thus, in the first alert your x is new and undefined, and in the second it is defined. Meanwhile, the value of x in first has remained unchanged.

    In order to get what you were expecting, and to keep the same x in both functions, you would remove the var declaration from second and leave the assignment:

    function first(){
        var x = "dad"; 
        function second(){
            alert(x);
            x = "mom";
            alert(x);
        }
        second();
    }
    first();