How JavaScript Closures Can Improve Your State?

Samed Skulj
Ministry of Programming — Technology
3 min readMay 10, 2024
How JavaScript Closures Can Improve Your Scope?

JavaScript is one of the most popular programming languages in the world, widely used for both client-side and server-side applications. One of its most powerful features, often not fully understood by new developers, is the concept of closures. Closures are a fundamental aspect of JavaScript, enabling powerful programming techniques and helping manage scope in original ways. In this blog, I’ll explore what closures are, how they work, and why they are so useful, providing examples to illustrate these concepts clearly.

What is a Closure?

At its core, a closure is the combination of a function and the “lexical” environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created. Essentially, closures allow a function to access those variables from an outer function even after the outer function has finished execution, which leads to various useful applications.

Lexical Scoping Explained

To understand closures, you first need to understand lexical scoping. JavaScript uses lexical scoping, meaning that a function’s ability to access variables is determined by its location within the source code. Let’s consider a simple example to see how lexical scoping works:

let scope = "global scope"; // A global variable
function checkScope() {
let scope = "local scope"; // A local variable
function f() {
return scope;
}
}

checkScope(); // Returns "local scope"

In this example, checkscope() defines a local variable scope and a function f() that returns the value of the local variable. The function f() is executed within the same scope it was defined, which is why it returns “local scope.”

How Closures Work

Now, let’s modify the previous example slightly:

let scope = “global scope”;
function checkscope() {
let scope = “local scope”;
function f() {
return scope;
}
return f;
}

let s = checkscope();
s(); // What does this return?

In this version, checkscope() returns the function f() itself, rather than the result of f(). When f() is called (from s() in our case), it still accesses the local scope variable from checkscope(). Despite being executed outside of its original scope, f() remembers the scope variable. This capability to ”remember” the environment in which it was created is the essence of a closure.

Practical Uses of Closures

Closures have numerous practical uses, such as:

  • Data Privacy: Closures can create private variables and methods. This is useful in many design patterns, like the module pattern, where we encapsulate some of the code to shield it from the global namespace and create private states.
  • Event Handlers: They can maintain state in an event without needing global variables or complex object properties.
  • Functional Programming: Closures facilitate functional programming patterns, such as currying and partial applications.

Advanced Example: Creating Private States

Consider this advanced example where closures are used to create private states:

function counterForApple() {
let apple = 0;
return {
count: function () {
return apple++;
},
reset: function () {
apple = 0;
},
};
}
let firstApple = counterForApple();
let secondApple = counterforApple();

console.log(firstApple.count()); // => 0
console.log(secondApple.count()); // => 0: they count independently

firstApple.reset();

console.log(firstApple.count()); // => 0: because we reset firstApple
console.log(secondApple.count()); // => 1: secondApple was not reset

In this case, each call to counterForApple() creates a new closure with its own apple. The count and reset methods are both closures, sharing access to the same apple.

Maybe some of you who are reading this, would compare this behaviour to OOP languages where we have private variables.

Conclusion

Closures are a powerful feature of JavaScript, providing both utility and efficiency in code management. They allow for elegant ways to handle data privacy, manage state, and write more maintainable and error-free code by keeping everything local to its execution context. Understanding closures is crucial for any JavaScript developer looking to increase the full potential of this versatile language.

By learning the concepts of closures and lexical scoping, developers can write cleaner, more efficient, and more secure JavaScript code, preparing the way for advanced programming techniques and applications. Whether you’re managing private states or handling complex application flows, closures are an important part of the JavaScript toolkit.

--

--