DEV Community

Tanmay Agrawal
Tanmay Agrawal

Posted on

JavaScript Lexical Scoping and Nested Functions

Nested functions are functions defined within the body of another function. In JavaScript, when you declare a function inside another function, the inner function has access to the variables and parameters of its containing (outer) function. This ability of the inner function to access the variables of the outer function, even after the outer function has completed execution, is what creates a closure.

Here's how nested functions work and how the inner function closes over the variables from the outer function's scope:

A. Defining a Nested Function

function outer() {
  let outerVar = 10;

  function inner() {
    console.log(outerVar);
  }

  return inner;
}

Enter fullscreen mode Exit fullscreen mode

In this example, inner is a function defined inside the outer function.

B. Accessing Outer Variables:
The inner function, in this case, inner(), has access to all the variables and parameters of its containing scope, which is the outer() function. This includes outerVar, which is a variable declared in outer().

C. Closure Creation:
When the outer function is executed, it defines inner() but doesn't execute it immediately. Instead, it returns the inner function itself. This means inner is a closure because it "closes over" or retains a reference to the outerVar variable from the outer function's scope.

D. Accessing Outer Variables Later:
Even after the outer function has completed execution and its scope should technically have exited, the inner function still has access to outerVar. You can call inner() at any time, and it will log the value of outerVar because it remembers the reference to it.

Here's how you would use the nested functions and the closure:

const closureFunc = outer(); // outer() returns inner()
closureFunc(); // This logs the value of outerVar (which is 10)

Enter fullscreen mode Exit fullscreen mode

When closureFunc() is called, it executes inner(), which can still access outerVar because of the closure. This is a fundamental feature of #closures in JavaScript, allowing you to create private variables and functions within the scope of an outer function and use them later as needed.

An example of the nested function and closures

function outerfunction(){

let pop="pop-up1"

function dance(){

let pop="pop-up-z"

console.log(pop)

function sing(){

console.log(pop)

}

pop="pop-up-y"

sing()

}

pop="pop-up2"

console.log(pop)

return dance

}

let z = outerfunction()

z()

//console output:

//pop-up2

//pop-up-z

//pop-up-y
Enter fullscreen mode Exit fullscreen mode

Now let us see what is happening here.

  • outerfunction() will call the function, this will initialize the pop variable and then update it to pop-up2 and then log this value in console.
  • Then this function returns another function which is dance, stored in the variable z, when z() calls happens the dance function will be called.
  • when dance function is called, it creates a variable pop with value pop-up-z and then console log happens which log this value to console and the it changes the value of pop variable to pop-up-y and then it calls the function sing()
  • when sing function is called, it console log the value of pop from its lexical environment, which is the pop-up-y.

notice here all the nested functions are accessing the variable from their lexical (nearest) environment which is also an example of #lexicalScoping

Top comments (0)