DEV Community

OzIheb
OzIheb

Posted on • Edited on

Closure in JavaScript Explanation done RIGHT

Introduction

Closure is arguably the most essential part of javascript to understand, once you do get it everything else will naturally fall into place.
Closure is often used in :

  • Data-privacy with objects pro-level functions like once that allows you to run a function one time only.

  • event handlers in asynchronous javascript which I will get into in a different article.

  • Use closure to hide away functionality that you generally do not want people to mess with.

How does it work?

Simply put, when you return a function ( from another function call ) in JavaScript you will also return with it a "Backpack" of saved data ( Part of the local memory of the parent function execution context that the returned function uses ).

Hold on just a minute, returning a function? Execution context? A function with a backpack??
Do not worry we will answer all these questions and more below.

Execution context

When a function is called the JavaScript interpreter starts what you can call a "sub-program" that has it own state ( memory ) where it stores it locally defined variables and passed arguments and it own thread of execution ( the method javascript uses to interpret code, going through it line by line ) where you find the function specific instructions ( code ).
For example, take a look at the following code block

const myLibrary = [];
function isLibraryEmpty(library) {
  const length = library.length;
  length <  0 ? console.log("library is empty") : console.log("library is not empty") ;
};
isLibraryEmpty(myLibrary);
Enter fullscreen mode Exit fullscreen mode

On line 6 the function is called which triggers the creation of a brand new execution context for it as the code is being run which will have it own local state ( as in local memory )
that will store the following :

  • library : myLibrary
  • length : 0 ( since the array is empty )

showing isLibraryEmpty execution context

then it will execute the condition check which will lead to the console log of "library is not empty" followed by the deletion of the execution context including all of it local state.

Returning a function from another function

For more clarity, review this modified version of our earlier example :

const myLibrary = [];
function isLibraryEmpty(library) {
  const length = library.length;
  return function checker(length) {length <  0 ? console.log("library is empty") : console.log("library is not empty") ; }
};
const newfunc = isLibraryEmpty(myLibrary);
newfunc()//"library is empty"
Enter fullscreen mode Exit fullscreen mode

With const newfunc = isLibraryEmpty(myLibrary) the isLibraryEmpty execution context will run eventually returning to newfunc a function that checks if the myLibrary array specifically is empty or not then all the local memory stored in the execution context will be deleted

Showing newfunc execution context

If you run the following code but at add at line 6 myLibrary.push("test") you will notice that it console logs that the library is not empty anymore.
But hold on! How could it do that when we have established clearly that the isLibraryEmpty execution context was deleted which means all of the local memory was also gone? How could the length have incremented to 1 knowing that?

What it means to have closure?

Continuing from the previous section, the truth is, when we returned the function we returned with it what you can call a backpack that contains some important data that the returned function requires to run, in another words that data is persistant, it is not the data that was deleted in the isLibraryEmpty execution context, it is a copy or a reference of that data.
Only newfunc function has access to that backpack, the data in it is lexically scoped.

In technical words, the function when it returned it brought with it a P.L.S.R.D (Persistant Lexically Scoped Referenced Data) also known as closure as you can see in the figure below

Showing closure at work

Review

To sum it up, closure, is a javascript feature that allows us to return lexically scoped data from the invoked function local memory with the returned function X so X can run without any errors or issues.

Top comments (0)