If you write code in JavaScript it’s quite likely you have come across the term closure
, which is a useful yet often confusing concept. But just what is a closure?
A closure may be described as a combination of a function and the lexical environment in which it was declared.
But what exactly does this mean? The lexical environment consists of any local variables in the function’s scope when the function is created. A closure enables one to refer to all local variables of a function in the state they were found.
This is essentially achieved by defining a function inside another function, this function within a function is technically the closure. Each time the parent function is called, a new context of execution is created holding a fresh copy of all local variables. These local variables can be referred to in the global scope by either linking them to variables declared globally or returning the closure from the parent function.
A basic example will take on a format similar to this:
function closuredFunc (){
function closure(){
// some logic
}
}
It is also possible to have a closure that returns several methods as shown below:
function closure(){
function first() { console.log('I was declared first')}
function second() { console.log('I was declared second')}
function third() { console.log('I was declared third')}
return [first, second, third]
}
To reference each of these methods, we’ll assign our closure to a global variable which will then point to an array of exposed methods. Each method can then be assigned to unique variable names to bring them into the global scope as shown below. At this point, they can now be called.
let f = closure()
let one = f[0]
let two = f[1]
let three = f[2]
one() // logs I was declared first
two() // logs I was declared second
three() // logs I was declared third
You may be wondering why would one go through the trouble of making closures. Well, closures have a number of uses and advantages.
Prior to the introduction of Classes in ES6, closures provided a means of creating class-like privacy similar to that used in Object Oriented Programming, allowing us to emulate private methods. This is known as the module pattern
and it allows us to write easily maintainable code with reduced namespace pollution and more reusability.
Let’s look at a case where this is done:
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};
var counter1 = makeCounter();
var counter2 = makeCounter();
counter1.value(); // returns 0
counter1.increment(); // adds 1
counter1.increment(); // adds 1
counter1.value(); // returns 2
counter1.decrement(); //subtracts 1
counter1.value(); // returns 1
counter2.value(); // returns 0
In the above example, we have declared a function makeCounter
which is a public function that has access to some private variables within it such as privateCounter
and the functions that manipulate it. This mimics the behaviour of creating makeCounter as a class with it’s own built in fuctionality and variables. This can be seen when we create two different counters, counter1
and counter2
. Each counter is independent to the other and references a different version of variables.
Closures also allow us to use functions to create other functions that add a specific value to their argument. In this case, the parent function allowing this behaviour is known as a function factory
as it essentially creates other functions.
Using function factories, we are able to achieve a behaviour known as Currying
, which we’ll cover in the next section.
Currying
is the pattern of functions that immediately evaluate and return other functions. This is made possible by the fact that Javascript functions are expressions that can return other functions.
Curried functions are constructed by chaining closures by defining and immediately returning their inner functions simultaneously.
Here’s an example of currying:
let greeting = function (a) {
return function (b) {
return a + ' ' + b
}
}
let hello = greeting('Hello')
let morning = greeting('Good morning')
hello('Austin') // returns Hello Austin
hello('Roy') // returns Hello Roy
morning('Austin') // returns Good morning Austin
morning('Roy') //returns Good Morning Roy
The two functions created from greeting
(hello
and morning
) each return functions that process the provided inputs to generate a greeting statement. They also take an argument which is the name of the person to be greeted.
In the above case, greeting is also used as a function factory with the two functions hello and morning generated from it.
The inner function may also be called invoked after the first call as follows:
greeting('Hello There')('General Kenobi')
//returns Hello There General Kenobi
Currying is considered to be part of functional programming and as such curried functions may be easily written using the arrow function syntax in ES6 and newer versions of Javascript for cleaner, more elegant code:
let greeting = (a) => (b) => a + ' ' + b
greeting('Hello There')('General Kenobi')
//returns Hello There General Kenobi
While closures may not be as commonly used since Javascript incorporated classes in ES6, they still have their place when it comes to writing clean reusable code. Closures and currying are also important concepts to understand when it comes to functional programming where they essentially serve a similar purpose to private methods in Object Oriented Programming.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
“A closure enables one to refer to all local variables of a function in the state they were found.” So, you are silent about global variables, those declared at file level, outside of all function definitions? You leave us to wonder whether any global variables are copied into the scope of a closure? For example, in browsers, is “window” copied into the scope of a closure? What about if there is a reference into window, such as “window.abc”?
Also, you seem strangely silent about whether variables are copied into a closure by value or by reference. There is a big difference.
Finally, you don’t seem to mention closures that are enclosed (non-valued) functions combined with arguments.
Oh, and you don’t seem to mention the use of closures to simulate private and semiprivate methods in classes.
Yes, I did notice that the article is only “an introduction”. But it’s also a “tutorial”, one that leaves questions unexplored.