JavaScript Recipe with Closures, Currying and Arrow Functions

Share This Post

Let’s not kid ourselves—although JavaScript is the most popular and widely used programming language today, it also carries a strong wave of hate (although PHP still holds the crown, I think). And let’s be honest: some of that hate is justified. The infamous == operator, the handling of global variables and scope, falsy values, and the management of this … nothing that hasn’t already been discussed a thousand times. Although, to be fair, there’s surprisingly little hate directed at how the DOM is designed—the part JS has to deal with constantly.

Getting back to my point, it’s true that many of these issues have been gradually addressed since the ES6 update, way back in 2015. But it’s also true that JavaScript has some features that are quite well-executed and worth highlighting. Among them are a few that have sparked a resurgence of JavaScript toward Functional Programming, such as Arrow Functions, closures, and currying. These not only allow for more structured and functional code, but also make it easier to use features that didn’t work so well before, like this context, privacy (encapsulation), and code reuse.

In this article, we will dive deeper into these concepts, explaining what they are, how to use them, and why they can be helpful to you.

Closures, Currying, and Arrow Functions

What is a Closure?

A closure in JavaScript is a function that retains access to the variables from its creation context, even when it’s executed outside of that context. In other words, a function has access to its local scope, the outer scope where it was defined, and the global environment.

This concept allows functions to “remember” the state they were created with, which is especially useful when you need to keep certain values encapsulated and out of reach from other parts of the program.

Imagine you’re developing an application and you need certain functions to access specific variables without exposing them to the rest of the code. Closures allow you to encapsulate that state safely. This pattern is common in scenarios like managing user sessions, implementing role-based permissions, or controlling time-based logic such as timers.

  Migrate from JavaScript to TypeScript

Since we’re talking about timers, let’s take a look at how a closure can be applied to a timer with its logic fully encapsulated.

function createTimer() {

  let seconds = 0;

  return {

    start: () => setInterval(() => seconds++, 1000),

    reset: () => seconds = 0,

    getTime: () => seconds

  };

}

const timer = createTimer();

const timerInterval = timer.start();

setTimeout(() => {

  console.log(timer.getTime()); // Output: 5 (después de 5 segundos)

  timer.reset();

  console.log(timer.getTime()); // Output: 0

  clearInterval(timerInterval);

}, 5000);

In the example above, the createTimer function creates a closed scope (closure) with the seconds variable. The start, reset, and getTime functions can access and modify that variable even after createTimer has finished executing.

From the outside, there’s no direct access to seconds, which keeps its internal state protected. This kind of pattern is very useful when you want to avoid exposing global variables or prevent other parts of the code from manipulating sensitive state.

What About Currying?

Currying is a technique from functional programming that involves transforming a function that takes multiple arguments into a sequence of functions, each taking one argument at a time. It sounds a bit abstract when you first read it (as functional programming often does), but let’s look at its benefits and go through an example to make it clearer.

Benefits

  • Logic reuse: It allows you to create more specific functions from a general one, reducing code duplication.
  • Simpler composition: It encourages building small functions that can be easily chained and combined.

Connection to Closures
So, what does this have to do with closures? Well, currying works precisely because of closures: each time an argument is applied, a new context is created that “remembers” the previously provided values. This way, you can build partial functions that can be completed later on.

function multiply(a) {

  return function(b) {

    return a * b;

  };

}

const multiplyBy2 = multiply(2);

console.log(multiplyBy2(5)); // Output: 10

In this example, the multiply function doesn’t return the result directly—it returns a new function that “remembers” the value of a. That new function, when executed later, still has access to the original value thanks to a closure. In other words, multiplyBy2 is a specific function built from a more general one, with the first argument already “saved.”

Here’s the arrow function version as well, since we’re going to talk about them:

const multiply = a => b => a * b;

const multiplyBy2 = multiply(2);

console.log(multiplyBy2(5)); // Output: 10

The Relevance of Closures in Modern JavaScript

With the arrival of ES6, JavaScript underwent one of the most significant transformations in its history. New ways to declare variables (let, const) were introduced, along with new structures like classes, and most notably, arrow functions, which have redefined the way we write functions over the past few years.

  How to simplify the data layer with MoyaRx and Codable

These tools not only made the language more expressive and concise but also made working with closures in daily practice much easier. Thanks to a cleaner and more modular design, working with closures today is far more intuitive.

Arrow Functions and Closures

Arrow functions do not create their own this context, which makes them especially useful in certain scenarios where you want to preserve the outer context. If this is your first time seeing this type of syntax (although it’s already quite adopted by many languages today), it might be hard to understand at first. However, once you get past that initial barrier, it’s clear that having more compact code helps create functions that capture and reuse values, one of the key strengths of closures.

const createAdder = (a) => (b) => a + b;

const add10 = createAdder(10);

console.log(add10(5)); // Output: 15

In this case, createAdder generates a new function that remembers the value a even after it has been executed. That “memory” isn’t magic: it’s a closure working behind the scenes. The arrow function syntax not only reduces the code but also makes it more readable and expressive.

Still, like anything in life, you need to know when to use them and when they might cause some headaches. Some of these issues can come from:

  • Unnecessary memory accumulation: If not managed properly, closures can keep variables alive in memory longer than necessary.
  • Confusion with the this scope: Especially when mixing traditional functions with arrow functions. Remember, arrow functions don’t have their own this.
  • Closures inside poorly structured loops: If you create closures inside loops without care (e.g., using var), you might end up capturing unexpected references.

In summary, closures are one of the most elegant and powerful features of JavaScript. Understanding them thoroughly will not only help you write better code but also master advanced patterns used in modern libraries, frameworks, and functional programming.

  Of Gods and Procrastination. Agile management.

Conclusion

JavaScript has its highs and lows, but if there’s one thing it does well, it’s offering us powerful tools, though sometimes not so obvious, that help us write better code. Closures, currying, and arrow functions aren’t just academic flourishes of functional programming: they’re real resources that can help you write cleaner, more modular code and, in many cases, code that’s easier to maintain.

Understanding the concepts of closures, currying, and arrow functions isn’t just about “knowing more JavaScript,” but about learning to think better in JavaScript. Because, at the end of the day, it’s not about memorizing techniques, but about knowing when to use them to solve real problems and make your code more expressive and easier for others to understand.

And although we’ve constantly talked about functional programming—I don’t know if I’ve mentioned it enough…—keep in mind that you can also apply these concepts to your object-oriented code. I’ve been getting a lot of mileage out of this mix lately… but that, probably, would make for another whole article.

Resources

To leave you not wanting more… here are a few resources for you to dive deeper into the concepts we’ve covered:

Author

  • Jose Castro

    Web developer, strongly oriented to the front end but with extensive backend knowledge that allows him to develop a better teamwork. His main motivation is continuous learning

    View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Subscribe To Our Newsletter

Get updates from our latest tech findings

About Apiumhub

Apiumhub brings together a community of software developers & architects to help you transform your idea into a powerful and scalable product. Our Tech Hub specialises in Software ArchitectureWeb Development & Mobile App Development. Here we share with you industry tips & best practices, based on our experience.

Estimate Your Project

Request
Popular posts​
Get our Book: Software Architecture Metrics

Have a challenging project?

We Can Work On It Together

apiumhub software development projects barcelona
Secured By miniOrange