Closure in Javascript - nodeblogger.com

Understanding Closures In Javascript

Featured, Javascript

Hi Coders, Today we are going to understand the most important and popular topic of javascript – Understanding Closures In Javascript

The Callbacks, event handlers can access outer scope variable because of closures. Closures are important part of functional programming and also the most asked question in javascript interviews.

Before moving to the main topic of this blog Understanding Closures In Javascript. Lets discuss what is scope and lexical environment. Please do not skip these sections if you really want to understand the closures.

The Scope

Every variable in javascript has its own boundaries in which it can be accessible. This accessibility of variable is managed by the scope. You are free to access the variable inside its scope, but outside scope you will not be able to access the variable.

A scope can be functional or code block ( blocked scope ) . Lets understand using some examples

Functional Scope
function testScope() {
    // The function scope
    let count = 0;
    console.log(count); // logs 0
  }
  
  testScope();
  console.log(count); // ReferenceError: count is not defined

Blocked Scope

if(true){
  const a = 1;
}
console.log(a) // a is not defined

Lexical Scope or Lexical Environment

In Javascript a code block or a function or a script as a whole have a hidden internal object known as Lexical Environment.

Lets try that in example

function outerFunc() {
  // the outer scope
  let outerVar = 'I am outside!';

  function innerFunc() {
    // the inner scope
    console.log(outerVar); // => logs "I am outside!"
  }

  innerFunc();
}

outerFunc();

In above example you will ask how inner function innerFunc() can access the outer function variable outerVar ?

Its because the outerVar is saved in the lexical environment of innerFunc(). The lexical environment object has two parts:

  1. Environment Record – an object that stores all local variables as its properties (and some other information like the value of this).
  2. A reference to the outer lexical environment, the one associated with the outer code.

This is how javascript engine understands the above example code.

  1. You define a function outerFunc() that has a variable outerVar.
  2. Inside the outerFunc(), You defined a function innerFunc().
  3. Inside the innerFunc(), you have used outerVar without any declaration. So innerFunc() finds outerVar in its lexical socpe
  4. OuterVar found in lexical scope and gets availabe for innerFunc()

When the code wants to access a variable – the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.

The Closure

Now we know lexical scope allows to access the variable of the outer scope.

Lets take a look at the example shared above and make some adjsutments in it

function outerFunc() {
  let outerVar = 'I am outside!';

  function innerFunc() {
    console.log(outerVar); // => logs "I am outside!"
  }

  return innerFunc;
}

const myInnerFunc = outerFunc();
myInnerFunc();

Here we have executed the innerFunc() outside of its lexical scope, and innerFunc() still has access to outerVar from its lexical scope, after executed outside its lexical scope.

In other words we can say that innerFunc() closes over ( captures or remembers ) the variable outerVar from its lexical scope.

The closure is a function that accesses its lexical scope even executed outside of its lexical scope.

The closure is a function that remembers the variables from the place where it is defined, regardless of where it is executed later.

Closure Example

You have come through this below snippet in interviews and get shocked with its output. So lets understand the below example also known as auto increment function.

function makeCounter() {
    let count = 0;

    return function () {
        return count++;
    };
}

let counter = makeCounter();
console.log(counter()); // 0
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

At the beginning of each makeCounter() call, a new Lexical Environment object is created, to store variables for this makeCounter run.

So here in above example counter() has a reference to {count: 0} Lexical Environment when runs first time . When code inside counter runs again and look for count, it first search it in its own lexical environment, then the Lexical Environment of the outer makeCounter() call, where it finds and changes it.

If we call counter() multiple times, the count variable will be increased to 23 and so on, at the same place.

References :

https://javascript.info/closure#lexical-environment

https://dmitripavlutin.com/simple-explanation-of-javascript-closures

Leave a Reply