Understanding Closures in JavaScript

Vijay Prasanna

Closures have been hard to explain traditionally because, despite their usefulness, they work silently in the background to make things work, the stuff we take for granted. In this article, I’ll try to cover the basics of what a closure is and why JavaScript benefits from closures.

A closure can be defined as a persistent scope that is held onto by a variable. Languages like JavaScript and Ruby support closures, which allows variables to have references to their parent scope even after their programming block has been executed and, as long as these variable have a reference somewhere, the closure exists.

Let’s take a look at an example to illustrate:

function outerFunction() {
 // randomly gets an alligator object
 let alligator = veryLongOperation(); 

 let result = function() { someCallback(alligator); }
}

Notice result, it’s a function that is able to access the alligator object. This is described as the closure of the function result - the ability of the result function to access its parent scope elements. I consider closures as a kind of a sticky parent environment attached to a variable or a snapshot of the execution context when the variable is declared.

Now that we’ve seen what closures are, why are they useful?

JavaScript is async when it comes to execution, so waiting for an operation to get over doesn’t really happen. Instead, if an operation is done then a callback is fired. This callback now has to run with the same execution context as it’s caller/parent. This means that whatever variables or functions were available to the parent must now be made available to the callback as well. If these callbacks did not have closures, then we’d have to manually bind the needed scope members.

Closures make our lives a lot easier by doing this for us in the background. If there is function inside an function, the inner function has access to its scope members throughout its lifetime.

We use closures all the time without noticing them.

We’ve come across them during normal class definitions:

let Alligator = function () {
 let alligatorLength = Math.floor(Math.random()*10);
 let getAlligatorLength = function() { 
  console.log(alligatorLength); 
 };
}

The scope chain of the getAlligatorLength is extended to include the members of the Alligator function.

Another instance where closures come into play is during currying (currying is process of returning multiple functions to reduce arity, it’s employed in functional programming paradigm to reduce state changes)

function addStuff(name1) {
  return function(name2) {
    return name1+ " and " + name2;
  }
}

console.log(addNames("alligator")("croc")); 
// alligator and croc

Closures can be used along with currying to introduce private members for JavaScript classes.

function Alligator() {
 let hiddenPower = "I can fly";
 return {
  showPower: () => { console.log(hiddenPower); }
 };
}

let alligator = new Alligator();
console.log(alligator.hiddenPower); // undefined
alligator.showPower(); // I can fly

Conclusion

Closures are a very subtle yet a powerful feature of JavaScript and understanding them is a very important step on the path to become a serious JavaScript developer. This is explained in more detail in Kyle Simpson’s excellent write-up on Closures.

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#