📄 Table of Contents

▬▬▬▬▬▬▬▬▬▬▬▬▬▬ ✦ ✦ ✦ ▬▬▬▬▬▬▬▬▬▬▬▬▬▬

◉ Closures

In JS, variables defined outside a function are automatically available inside the function (but NOT vice versa) because JS uses “Lexical Scoping” & it achieves so using Closures (or inner functions).

  • In JavaScript, all functions work like closures which literally means closures are created every time a function is created, at function creation time.
  • Also defining a function inside another function (nested functions) and exposing it acts as a Closures. To expose a function, return it or pass it to another function.

The inner function will have access to the variables in the outer function scope, even after the outer function has returned.

Closure example
Closure example

However, a function doesn’t have to return in order to be called a CLOSURE. Simply accessing variables outside of your immediate lexical scope creates a CLOSURE.

We have two functions, outer and inner. When the first function is called, it returns the second one. In the code above, by the time we call x() (which is a reference to the inner function), the outer function has already returned. We don’t expect that x can access the variable out when it is called, since that variable is not in scope when we call it.

And yet, it does. This is a closure — a function that has access to all of the variables that were in scope when it was declared.

Generally, in C & most other languages, after a function returns, all the local variables are NO longer accessible because the stack-frame is destroyed. But here we are calling the function X() (1st /2nd time), even after we have already returned from outer().

🔹 But, why to use Closures at all ?

  • When binding event handlers to element
  • Callbacks

Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns.Among above things, closures are commonly used to give objects data privacy.

When you use closures for data privacy, the enclosed variables are only in scope within the containing (outer) function. You can’t get at the data from an outside scope except through the object’s privileged methods. In JavaScript, any exposed method defined within the closure scope is privileged. For example:

const getSecret = (secret) => {
return {
get: () => secret
};
};

In the example above, the `.get()` method is defined inside the scope of `getSecret()`, which gives it access to any variables from `getSecret()`, and makes it a privileged method. In this case, the parameter, `secret`.

Objects are not the only way to produce data privacy. Closures can also be used to create stateful functions whose return values may be influenced by their internal state.

In functional programming, closures are frequently used for partial application & currying.

Event listeners

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
Closures in event listeners
</body>
<script>
const body = document.body;
const initButtons = () => {
let button;
for (var i = 0; i < 5; i++) {
button = document.createElement("button");
button.innerHTML = "Button " + i;
button.addEventListener("click", (e) => {
alert(i);
});
body.appendChild(button);
}
};
initButtons();
</script>
</html>

What do you think happens when you click on the buttons? Each button click will return an alert with ‘5’. Why is this? The first thing to note here is that we are using var not let to declare i. As such this is a bit of a contrived example as you would very rarely use var for variable declaration these days but stick with me as it will help you understand closures. Remember - var is function scoped and let is block scoped.

The for loop is within the initButtons function and var is 'hoisted' to the top of the function.

Every time a loop completes a button is created with an attached event listener who’s callback has reference to i. As subsequent loops complete, i updates, as too does each event-listeners reference to it. This is the problem, every closure has access to the same reference to i.

We could fix this in a couple of ways:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
Closures in event listeners
</body>
<script>
const body = document.body;
const initButton = (name, alertMessage) => {
button = document.createElement("button");
button.innerHTML = "Button " + name;
button.addEventListener("click", (e) => {
alert(alertMessage);
});
body.appendChild(button);
};
for (var i = 0; i < 5; i++) {
initButton(i, i);
}
</script>
</html>

Each event listener is now scoped to the alertMessage param which is defined on function invocation.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
Closures in event listeners
</body>
<script>
const body = document.body;
const initButtons = () => {
let button;
for (let i = 0; i < 5; i++) {
button = document.createElement("button");
button.innerHTML = "Button " + i;
button.addEventListener("click", (e) => {
alert(i);
});
body.appendChild(button);
}
};
initButtons();
</script>
</html>

Or just use let instead of var within the loop. Using let will ensure that each iteration of the scope has its own independent binding of i.

🔹 Disadvantages of using Closures in javascript.

In JavaScript, when a function finishes executing, any variables declared within its body is “garbage collected”. In other words, it is deleted from memory. This is why local variables are possible in JavaScript. This is why variables inside functions cannot be accessed outside.

// dev is NOT accessible herefunction someFunc() {
// dev is accessible here
const dev = 'to';
}
// dev is NOT accessible here

Special exceptions occur when something inside the function depends on the variable being deleted. For example, the function below returns another function that depends on the variables of the parent function.

// Parent functionfunction parent() {
// Local variable of the parent function
const prefix = 'I am a ';
// Child function
return function(noun) {
// The child function depends on the variables of the parent function.
return prefix + noun;
};
}

NOTE: The example above takes advantage of a concept in functional programming called currying. You can read more about it if you want.

// Store the returned child function
const getSentence = parent();
// At this point, `parent()` has finished executing.
// Despite that, the `prefix` variable is still
// accessible to the child function. More on that later.
const job = getSentence('programmer');// What is the value of `job`?
console.log(job); // 'I am a programmer'

In this case, prefix is still usable by the child function even after it has been garbage collected because the child function created its own closure.

A closure is like a “snapshot” of the environment a function is in when it is executed. Its closure is its own internal copy of the environment.

Technically speaking, any variable in a closure is exclusively accessible to the child function that owns it. Operations can only be performed on these variables if the current execution context has a reference to the closure. In this case, the “snapshot” that the child function owns is the reference to that closure, therefore it has access to its variables.

When the parent function finished executing, the prefix variable is scheduled to be deleted. However, before that can be done, the child function "takes a snapshot" of its current environment (which includes all of the variables of the parent function it depends on). The child function now has its own copy of the prefix variable that it can access and manipulate. This is what closures are in its most basic use case. MDN provides a more technical definition.

So to fix this in your program if there comes a point that you’re done using an element inside the closure then you need to set it to null.

[2].creating functions inside other functions lead to duplication in memory consuming more momory, potentially slowing down the application.

Closures in action.

How to do it correctly.

Suppose you want to use a variable to count and want to create a function to increment the count variable.

var counter = 0; function increase() {
counter += 1; // increment its current value.
console.log(counter);
}
increase();
increase();
increase();
// The counter is now equal to 3.

Here we have a solution, but has flaws; the counter variable is global, any script on the page would have access to it and could change it without calling the increase function .

We need to make sure that the counter variable is only modified by the increase function.

Therefore, move the definition of the variable inside the function, so no one can modify it without calling the function increase:

function increase() {
var counter = 0;
counter += 1; // increment its current value.
console.log(counter);
}
increase();
increase();
increase();
// We expect the value of the count variable is 3, but it will be 1.

Now the counter variable is not accessible from the outside (now is protected), but this wong work properly because every time you call the function it will define the variable account.

We need to create an internal function to solve this:

var increase = (function() {
var counter = 0;
return function () {
return counter += 1;
}
console.log(counter);
})(); //* IIFE Auto-invoked function.increase();
increase();
increase();
// The counter is now equal to 3.

A common mistake

function count() {
var i;
for (i = 1; i <= 3; i ++) {
setTimeout (function () {
console.log ('The count value is '+ i);
}, 1000); // 1000 milliseconds = 1 second
}
}
count();

And this is how you can solve it:

function count() {
var i;
function display(j) {
return function () {
console.log ('The counter value is ' + j);
}
};
for (i = 1; i <= 3; i ++) {
setTimeout (display(i), 1000);
}
}
count();

🔹 Alternative of Closures ?

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.