DEV Community ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป

Cover image for Seriously though, what is Closure?!
Anna J McDougall
Anna J McDougall

Posted on • Originally published at blog.annamcdougall.com

Seriously though, what is Closure?!

Follow Me on Twitter @AnnaJMcDougall

Closure: it's not only what you need when a relationship ends, it's also something you need to understand when coding in JavaScript. Unfortunately, it can be a tough thing to explain to those new to programming, and since I only recently feel like closure has 'clicked' for me, I've decided to write a short article to explain it in ways other newer coders can understand. I hope this helps someone out there!

If you can write basic JavaScript functions, you have almost certainly already used closures without even realising it. In fact, for the longest time my main complaint about understanding 'closure' has been: "Isn't that just basic programming? Why do we even need a name for it?". Despite my protestations, I've been assured time and again that this is "a thing" and you need to know it, so let's stop dilly-dallying and get into it.

The basics of scope

Firstly, let's take a step back and think about the concept of lexical scope, which tells us which variables are accessible at any given time. Consider the following code:

function add (a,b) {
   let sum = a + b
   return sum
}
console.log(sum)
Enter fullscreen mode Exit fullscreen mode

You probably already understand that the reason the above doesn't work is that we can't access sum because it exists only within "the world" of the function add. This "world" is known as scope, and it is created by our darling curly braces { and }.

Accessing scope from within and "local binding"

"Local binding" is just a fancy pants way of referring to variables declared within the scope of a function. In other words:

function funkyTown(){
   let localBinding = "this is a local binding"
}
Enter fullscreen mode Exit fullscreen mode

Let's expand on this a bit: if we know that we can access local bindings anywhere within the "world" of a function, then we can add a line like this:

function funkyTown(){
   let localBinding = "this is a local binding"
   console.log(localBinding)
}

funkyTown()
Enter fullscreen mode Exit fullscreen mode

Does the above function call log to the console? YES. We can access localBinding because we're still within the existing scope of our funkyTown function.

Wouldn't you know it, the above example also includes a closure! Our console.log is a function which references a local binding in an enclosing scope (whew!) and is therefore considered a closure.

"Closure" vs "A closure"

I'm going to just to a straight copy-paste from an excellent online resource, Eloquent JavaScript, which clarifies the situation in just a few words (emphasis mine):

"Being able to reference a specific instance of a local binding in an enclosing scopeโ€”is called closure. A function that references bindings from local scopes around it is called a closure." - Eloquent JavaScript Chapter 3

In other words, closure as a concept refers to the ability and idea of referring to variables which only exist within the "world" they were created: the scope created by curly brackets. Since we cannot access these variables from outside that scope, closure can only exist from within it. As I mentioned earlier: you have probably known that you can only access variables within their own scope for a long time, but now you know that the ability to do so is called closure.

To expand on this even more, a closure therefore refers to any instance in which you use the above ability in a function. Any function which references variables existing only in its enclosing scope, is itself a closure.

One more example for the road

Since this article is aimed at beginner-to-intermediate learners, I won't dive too deep into the ways in which we can use closure more complexly, I'll just pop another example of a fairly simple closure in here.

 // a function which will only divide even numbers
function divideEvens(num, divider) {                

   // local binding
   let isEven = (num % 2 === 0) ? true : false;   

   // a closure function
   function doDivision() {                

      // references to local bindings                     
      return (isEven) ? num / divider : null;           
   }

   // uses the inner function to refer to local bindings 
   return doDivision()                                          
}

console.log(divideEvens(24, 4))           
// logs 6             
Enter fullscreen mode Exit fullscreen mode

Of course the above is not the best way to implement the goal of the code, but simply acts as a verbose example.

Conclusion

As a programmer, you will frequently define and refer to variables from inside the scope of a function. As you do so, and as you use and reuse those variables in that "world", you are unknowingly utilising closure to your advantage. There is a difference between closure as a concept, and 'a closure' as a piece of code utilising that concept. Using closures is an everyday part of programming, and although knowing the name for it sometimes seems a bit odd, you can hopefully now see why they're important and give a relatively simple explanation of them if needed.

Top comments (1)

Collapse
indoor_keith profile image
Keith Charles • Edited on

Your explanations are well put. Great read! Quick note on formatting. if you place a "js" right after the first set of backticks, DEV will highlight your syntax accordingly ๐Ÿ™‚. So it would look like so if you replaced the single quotes with backticks:

'''js
// your code here
'''

Lastly, whereas your last example showcases the idea of closures, it doesn't quite reflect the benefit of them. A great example of a closure utilizing a lexically scoped variable would be a persistent counter without a global count variable. We know that whenever a function runs, it rebuilds any variable that is declared inside of it, rendering those variables non-persistent if we need to call that function multiple times. And if we don't want to pollute our global scope, we wouldn't want to declare the variable outside of any function. We'd need a closure to handle counting said variable! Example:

// a function that creates the count variable and the closure 
// that will increment said variable
function createCounter() {
  // our block scoped variable
  let count = 0;
  // our closure
  function increment() {
    count++;
    return count;
  }
  // we return our closure to be used outside of createCounter
  return increment;
}

// now we can store the result of createCounter to use our 
// closure as many times as we want without the need to expose
// our count variable globally to access and increment it.
const getIncrement = createCounter();

console.log(getIncrement()); //-> 1
console.log(getIncrement()); //-> 2
console.log(getIncrement()); //-> 3
Enter fullscreen mode Exit fullscreen mode

When you think of closure's this way, you begin to see how powerful closures are. You're essentially creating a manageable state without the need to expose any variables globally! ๐Ÿคฏ

I'm excited to read more of your posts and welcome to the Dev Community! โœŒ

๐ŸŒš Friends don't let friends browse without dark mode.

Sorry, it's true.