Tutorial

An Introduction to Closures and Currying in JavaScript

Published on December 12, 2019
author

Austin Roy

An Introduction to Closures and Currying in JavaScript

Introduction

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

Why Use Closures?

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.

What is Currying

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

Conclusion

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.

Learn more about our products

About the authors
Default avatar
Austin Roy

author

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.

Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
1 Comments


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.

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Become a contributor for community

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

DigitalOcean Documentation

Full documentation for every DigitalOcean product.

Resources for startups and SMBs

The Wave has everything you need to know about building a business, from raising funding to marketing your product.

Get our newsletter

Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.

New accounts only. By submitting your email you agree to our Privacy Policy

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.