If you just started out learning javascript and spends a few month with it, or even if you've used javascript for a while, chances are you probably didn't face an issue that required knowledge of javascript closure, or actually maybe behind the scene you already used closure without realizing it.
Closures are considered an advanced topic in javascript, understanding closures is crucial for writing more complex and efficient JavaScript code, let's start to learn more about it.
Understanding Closures
Closures occur when a function is defined within another function (the outer function) and has access to variables from the outer function's scope.
As we all know functions in javascript have access to variables outside of their scope.
const c = 10;
const add = (a, b) => {
return a + b + c;
}
console.log(add(1,1))
As you can see we accessed variable 'c' even though it is outside of add
function.
When javascript first created it didn't support classes, so at that time developers used factory function which is a function that returns an object not a value, here is a simple example of factory function
function createCounter(){
let value = 0;
function increment(){
return ++value
}
return {
increment
}
}
Let's create a couple of counters to see what is going on
const counter1 = createCounter();
const counter2 = createCounter();
console.log(counter1.increment()); // 1
console.log(counter1.increment()); // 2
console.log(counter2.increment()); // 1
Now as you see each counter has its own value and keep tracks of it, but how is javascript doing that?! the answer is closure, closure tells us increment()
function has access to value
variable, but remember each time createCounter()
get called we're creating a new value
variable so each time incrment()
will get access to its own copy of a value
variable.
So we can just call closure HIDDEN STATE, and ofcourse its pretty usefull in object oriented programming.
Implementing Memoization Funciton with Closure
One of the core concept of web or programming in general is memoization, it is also a technique that applied in dynamic programming, basically memoization is realy just a fancy word for caching, so we are just caching the result of the function so that we don't excute the function if we know the result.
const add = (a, b) => {
return a + b;
}
add(1,2); // Excute
add(1,2); // Excute
add(2,2); // Excute
Normally when we call a function javascript will not cache the result for you, it is just calling and excute the function but if we add a memoizaiton it will only excute when the result is changing,
So here is the solution of creating a memoization function that takes a function as its argument and handle the HIDDEN STATE (closure) to track the result of the function's excustion
function memoize (fn){
let cache = {}
return function(...args){
const key = JSON.stringify(args);
if(key in cache) {
return cache[key]
}
cache[key] = fn(...args);
return cache[key]
}
}
We used cache
variable as a HIDDEN STATE and stored the function parameters as key and result of the function as the value in a Hash Map, with that we can use our memoize function like this
const add = memoize((a, b) => {
return a + b;
})
console.log(add(1,2)); // Excute
console.log(add(1,2)); // Doesn't Excute
console.log(add(2,2)); // Excute
Conclusion
In conclusion, closures are a powerful and often misunderstood concept in JavaScript. They allow functions to retain access to variables from their lexical scope, even after the outer function has finished executing. Closures are essential for creating private variables, implementing function factories, and optimizing code through techniques like memoization. Understanding closures is crucial for writing more complex and efficient JavaScript code.
Top comments (5)
Is there any way to protect the external context to "leak" inside a function context? This might happen accidentially changing existing code:
We can simply declare a locale variable inside the function to prevent this
You know Murphy's law:
βAnything that can go wrong will go wrong.β
IΒ΄m not talking about intentional behavoir, but about possible and hard to track errors. As the global scope is always "vulnerable" in Javascript, it is a good habit not to use any global variables at all. But this is not so easy if you use HTML-IDΒ΄s:
See this example:
This is not correct. A closure is created whenever a function is created - nested functions are irrelevant.
Misconceptions About Closures
Jon Randy ποΈ γ» Sep 27 '23
Thanks Jon for your comment!
While it's true that closures are created whenever a function is defined, including nested functions, the concept is often explained in the context of nested functions because that's where the effects of closures are most noticeable and useful. The ability of inner functions to access variables from their outer scope, even after the outer function has finished executing, is a key aspect of closures that is often illustrated using nested functions.