39

Closures in JavaScript: Why Do We Need Them?

 4 years ago
source link: https://www.tuicool.com/articles/UbmyUrE
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Learn how to answer one of the most frequently asked JavaScript interview questions.

IZvUNbY.png!web

Closures aren’t a JavaScript-only concept, although if you’re part of the JavaScript/Node.js community, you might've heard the term quite a bit. In fact, it is one of the many questions that are normally asked as part of technical interviews for JavaScript developers. I myself am one of those interviewers who normally adds that particular question to the list since it tends to help understand the level of understanding of the language.

That being said, it’s also one of those concepts that normally a lot of people tend to ignore or not properly understand during those interviews so I thought I’d throw something together to help in those kinds of situations.

So without further ado, what exactly is a closure and why do you need one?

Tip: Share utility and UI components

Use Bit to easily publish, install and update small individual modules across different JavaScript projects. Don’t install entire libraries and don’t copy-paste code, when you can build faster with small reusable modules. Take a look .

RzERBnM.jpg Bit: Easily reuse and sync small modules and utils across JS projects

What are Closures then?

Like I mentioned above, the actual concept of closures has been around since the 60's, purely as a mathematical construct and it was implemented as part of a programming language for the first time in the 70’s.

Quickly jumping into the “now” and talking about JavaScript, closures are the way the languages can achieve lexically scoped name binding. If we want to get technical, the lexical scope makes it so that every function values (i.e every time you return a function or assign a function to a variable) carries with it, the values of all variables that it depends on. That pack of records is what we know normally as “Closures”.

I know, that sounds like a lot, so let’s unpack it:

Look at the following code, it’s pretty simple and you probably know what happens when you execute it, don’t you?:

That would clearly print the number 3 on the standard output, but why? Like I mentioned before, the function being returned (that anonymous function inside test ) is not going alone, in fact, it’s pulling the values of all variables it depends on (in other words, the values from a and b ) .

In other words, when you’re executing the test function, you’re not just returning a single function, you’re actually returning a record, containing the lexical scope of that anonymous function. Or, as I like to call it (me and everyone else, but who’s counting? right?) the closure is being returned.

Finally, if we wanted to simplify it even further, you can think of a closure as the function that is assigned (or returned as a value) and its associated scope.

Why are Closures needed?

Now that we’ve cleared that up, let’s cover the why. Why would you want to care about closures?

Granted, closures make a lot of sense in the functional programming world, after all, you need functions to be first-class citizens in order to have closures. So if you’re going full OOP with your JavaScript code, you’re probably not interested or even see the need for such a concept.

And that is perfectly fine, but mind you, JavaScript is not a completely OOP language, even though ES6 has tried to bridge that gap by adding concepts, such as classes. So, let me show you some benefits of mixing things up a bit and I’ll let you decide then, if closures are for you or not.

Useful use cases for closures in JavaScript

Let me show you now a few examples of when closures tend to come in handy, even if you’re someone who tries to stick to the stricter of OOP styles.

The For Loop little problem

This one is a quick little common problem when trying to define a function inside a For… loop. In other words, this scenario works when you’re trying to compile a list of functions that use one of the items inside each time.

Something like this:

If you had to guess, what would be the output? According to what I’ve been saying so far, you’ve probably noticed that we’re creating closures every-time we add the new anonymous function to the array. So when we create a closure, the function is saved, along with the variables it’s using right?

Almost right! In fact, what is saved, is a reference to the scope, meaning, you have your variables available, yes, but because it’s an actual reference, any further changes to it, will permeate into your closure. In other words, the output of the above code would be:

The closure-specific way would be to create a new context to wrap the function on, so in fact, every-time the function is created, we’re creating a new scope, one that has the new variable and the closure inside it. Every-time you create the latter, it will only be associated to that particular scope (which again, only contains one variable).

Let me explain:

As you can see, for every iteration of the For loop, I’m creating a IIFE that creates a new scope, which only contains the new variable, and thus, the closure created inside of it is associated to that one. New iterations will create further scopes , so the problem we had before will not happen. And in fact, the actual output from the above code is:

Simulating private scopes for variables

This is yet another useful case where closures come in handy. The point here is to allow others to access values you have inside your function, without letting them directly modify the variables.

Remember, JavaScript still doesn’t have the concept of a private scope for attributes or methods on your classes, so simulating this might help you protect your code and allow others to use your libraries properly.

So, the main goal we’re trying to achieve here is to allow others to set values on your variables without actually accessing them, providing some form of pre-validation, as well as getting compounded values, based on several different variables, again, without accessing them directly.

Here is what you would do with the current state of OOP in JavaScript:

As you ca see, the getter and setter methods are there, trying to protect access to both first_name and last_name but there is nothing that actually prevents others from accessing them directly.

Notice how we’re not using this at all now, that’s because I’m creating a literal object (the one I’m returning), containing all three methods (our closures), and the scope associated with them will contain the variables we need. So no need for more.

The best part? There is no way for you to access the fname and lname variables from outside the function. This works exactly like before, by returning a closure (or in this case, a set of closures), we’re allowing those functions to access their related variables from outside the MyObject ‘s scope.

This can also be used to hide functions, just like you would private methods if you could, simply by not returning them as part of the object literal at the end of the constructor function.

Delayed execution

We all know and maybe have used setTimeout in the past, but did you stop to realize it actually works thanks to closures?

Look at the following example:

What do you think will be the output of the last line? This is it by the way:

done!
Hello World!

But if you think about it, when the greetDelay function gets called, it immediately returns the string “done!”, so later, when the timeout is over, the anonymous function we’ve created gets called. How then, is this new function able to write the correct string, if the original greetDelay function no longer exists?

You guessed it! Closures! The anonymous function is passed as a value to the setTimeout function, thus, creating a new closure and associating the variables in the scope (i.e greet ) to that new function. So when the timeout is over and our callback gets called, the function has everything it needs to be executed.

Function composition

For my last example, I want to cover function composition. Or in other words, the ability to create functions from others. There are many ways to explain this concept that comes from mathematics, but let’s be honest, we’re not here to talk about math, are we?

This is what composition looks like:

const add = (a,b) => a + b;
const add10 = x => add(10, x);

The function add10 is composed by a call to add . In other words, we’re creating functions that wrap others by fixing some of their parameters (in this case a is fixed to the value 10.

The above example is a bit too simplistic to pick up on the closure, but let me show you another one.

The gist (no pun intended!) of the above code, is that by returning the anonymous function from makeIncrementer it is able to use the original value of a even further down, because that returned function has it’s original scope still associated to it (the last line essentially executes that anonymous function that now is assigned to incBy10 and it can still access the value 10 you assigned to a on line 7).

And to extend this concept a bit further, let me show you another practical application for composition.

This code uses the same concept, and thanks to the closure returned, we’re able to assign the strings for each tag only once, and then worry only about the actual content.

Conclusion

This is it for my overview of closures. This is definitely a very useful concept, but one that sometimes gets over-explained, and people, usually those that are just getting started with JavaScript get overwhelmed and avoid it.

Maybe you’ve already been using closures without actually realizing it, but if you haven’t, give them a try and don’t hesitate to reach out and ask if you have questions!

Share down in the comments if you can think of another interesting use case for closures that I might’ve missed!

Otherwise, see you on the next one!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK