JavaScript Closures
Tags: javascript, webdev, beginners, programming
Published: 2022-09-24 18:22:21

What is closure?

A closure is a function that accesses the scope of its outer function even after the outer function returns. This means that a closure can remember and access its outer function's variables and arguments even after the function has finished.closure is a function that references variables in its outer scope from its inner scope. The closure keeps the outer scope inside its inner scope.

example-

function OuterFunction() {

    var extern variable = 100;

    function InnerFunction() {
        alert(externalVariable);
    }

    return InnerFunction;
}
var innerFunc = OuterFunction();

innerFunc();


In the example above, return InnerFunction; returns InnerFunction from OuterFunction when you call OuterFunction(). The innerFunc variable only refers to InnerFunction(), not OuterFunction(). as the call innerFunc() it can still access the externalVariable that is declared in OuterFunction(). This is called closure.
One important property of closures is that external variables can retain their state between multiple calls. Remember that the inner function does not keep a separate copy of the outer variables, but refers to the outer variables, that is, the value of the outer variables will change if you change it using the inner function.


What is lexical scope?

Lexical scope in JavaScript refers to the availability of variables, functions, and objects based on their physical location in the source code. Lexical scope defines the scope of a variable according to the position of the variable declared in the source code.
In this example:

let name = 'John';

function greeting() { 
    let message = 'Hi';
    console.log(message + ' '+ name);
}



The variable name is a global variable. It is accessible from anywhere, including the greeting() function.
The message variable is a local variable that is only accessible within the greeting() function.
If we access the message variable outside the greeting() function, you will get an error.

So the Js engine uses a scope to manage variable accessibility.

According to the lexical scope, scopes can be nested and an inner function can access variables declared in its outer scope.
example-

function greeting() 
{
    let message = 'Hi';

    function sayHi() {
        console.log(message);
    }

    sayHi();
}

greeting();



The greeting() function makes a local variable named message and a function named sayHi().

SayHi() is an internal function that is only available in the body of the greeting() function.

The sayHi() function can access external function variables, such as the message variable of the hello() function.

Inside the greet() function, we call the sayHi() function to display the Hello message.

Take a look at this code snippet:

function person() {
  let name = 'Peter';
  
  return function displayName() {
    console.log(name);
  };
}
let peter = person();
Peter(); // prints 'Peter'
When the person function is invoked, the JavaScript engine creates a new execution context and lexical environment for the function. After this function is finished, it returns the displayName function and assigns it to the peter variable.
the lexical environment will look like this:

personLexicalEnvironment = {
  EnvironmentRecord: {
    name: 'Peter',
    displayName: <displayName function reference>
  }
  external: <globalLexicalEnvironment>
}
When a person's function completes, its execution context is removed from the stack. But its lexical environment is still in memory because its lexical environment is referenced by the lexical environment of its internal displayName function. So its variables are still available in memory.

Please note that when a personLexicalEnvironment is created, the JavaScript engine attaches the personLexicalEnvironment to all function definitions in that lexical environment. So that later, if any of the internal functions are called, the JavaScript engine can set the external lexical environment to the lexical environment attached to that function definition.

When the peter function (which is actually a reference to the displayName function) is executed, the Js engine makes a new execution context and lexical environment for that function.

The  lexical environment will be- 

displayNameLexicalEnvironment = {
  EnvironmentRecord: {
    
  }
  outer: <personLexicalEnvironment>
}
Since there is no variable in the displayName function, its environment record will be empty. During the execution of this function, the JavaScript engine tries to find the variable name in the lexical environment of the function.

Since there are no variables in the lexical environment of the displayName function, it looks in the external lexical environment, i.e. the lexical environment of the person function, which is still in memory. The JavaScript engine finds the variable and prints its name to the console.