Closures in JavaScript

Closure Scope Chain, Uses and Disadvantages of Closures

Ayush Verma
Mar 5 · 5 min read
  • A closure is a combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment).
  • In other words, a closure gives you access to an outer function’s scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time.
function x() {
var a = 5;
function y(){
console.log(a);
}
y();
}
x(); //5

Here y() is bundled together with its lexical environment of x(). First, y() will check its local scope, if it does not find “a” it will go to the lexical parent. So inside y(), it forms a closure with the variable which was part of x lexical scope i.e. y() was bind to variables of x.

  • When functions are returned from another function, they still maintain their lexical scope i.e they remember where they were actually present.
function x() {
var a = 5;
function y(){
console.log(a);
}
return y;
}
var z = x();
z(); //5

Here though x no longer exists, still y() remembers its lexical scope i.e when we return a y() not just function code is returned, but closure was returned( function along with lexical scope).

  • One important characteristic of closure is it keeps the state of the outer variable between the multiple calls. The inner function does not contain a separate copy of the variable, it just keeps the reference of the outer variable.
function x() {
var a = 5;
function y(){
console.log(a);
}
a = 100;
return y;
}
var z = x();
z(); //100

Here also y() will come along with its lexical scope i.e. “a” will not refer to the value, it will refer to its reference.

Example 1:function ParentFunction() {
var parentVariable = 60;
function ChildFunction() {
return parentVariable += 1;
}
return ChildFunction;
}
var executeChild = ParentFunction();
console.log(executeChild()); //61
console.log(executeChild()); //62
console.log(executeChild()); //63
console.log(executeChild()); //64
Example 2:var add = (function () {
var counter = 0;
return function () {counter += 1; return counter}
})();
add(); //1
add(); //2
add(); //3

Closure Scope Chain

Every closure has three scopes:

  • Local Scope (Own scope)
  • Outer Functions Scope
  • Global Scope
// global scope
var e = 10;
function sum(a){
return function(b){
return function(c){
// outer functions scope
return function(d){
// local scope
return a + b + c + d + e;
}
}
}
}

console.log(sum(1)(2)(3)(4)); // log 20

Uses of Closures

  • Using private variables and methods −Languages such as Java provide the ability to declare methods private, meaning that they can only be called by other methods in the same class. JavaScript does not provide a native way of doing this, but it is possible to emulate private variables and methods using closures.
// Define the closure 
var rentPrice = function(initialRent) {
var rent = initialRent;

// Defien private variables for
// the closure
return {
getRent: function() {
return console.log(rent);
},
incRent: function(amount) {
rent += amount;
console.log(rent);
},
decRent: function(amount) {
rent -= amount;
console.log(rent);
}
}
}

var Rent = rentPrice(8000);

// Access the private methods
Rent.incRent(2000);
Rent.decRent(1500);
Rent.decRent(1000);
Rent.incRent(2000);
Rent.getRent();
Output:
10000
8500
7500
9500
9500
  • Currying- It is when you break down a function that takes multiple arguments into a series of functions that each take only one argument.
function add (a, b) {
return a + b;
}
add(3, 4); // returns 7

This is a function that takes two arguments, a and b, and returns their sum. We will now curry this function:

function add (a) {
return function (b) {
return a + b;
}
}

This is a function that takes one argument, a, and returns a function that takes another argument, b, and that function returns its sum.

add(3)(4); //7
var add3 = add(3);
add3(4); //7

The first statement returns 7, like the add(3, 4) statement. The second statement defines a new function called add3 that will add 3 to its argument. This is what some people may call a closure. The third statement uses the add3 operation to add 3 to 4, again producing 7 as a result.

  • Function factories- One powerful use of closures is to use the outer function as a factory for creating functions that are somehow related.
function Job(title) {
return function(prefix) {
return prefix + ' ' + title;
};
}
var sales = Job('Salesman');
var manager = Job('Manager');
alert(sales('Top')); // Top Salesman
alert(manager('Assistant to the Regional')); // Assistant to the Regional Manager
alert(manager('Regional')); // Regional Manager

Using closures as function factories is a great way to keep your JavaScript DRY. Five powerful lines of code allow us to create any number of functions with similar, yet unique purposes.

  • Run function only once- functions remember how many times the function has been run by forming a closure.
var something = (function() {
var executed = false;
return function() {
if (!executed) {
executed = true;
console.log("do something");
}
};
})();
something(); // "do something" happens
something(); // nothing happens
  • setTimeout- It is a method that calls a function or evaluates an expression after a specified number of milliseconds.
function x(){
var i = 1;
setTimeout(function(){
console.log(i)
},3000)
console.log(“After setTimeout”)
}
x();
//After setTimeout
// 1 (after 3 sec)

Here function in setTimeout forms a closure. So this function remembers the reference to “i”. So wherever this function goes it takes the value of “i” with it. setTimeout takes a callback function and stores it in someplace and attaches a timer to that. Once the timer expires, it will take the function and put it to the current call stack, and runs it.

  • Memoization- It is the programmatic practice of making long recursive/iterative functions run much faster. Here’s an example of a basic memo function:
function memo(func){
var cache = {};
return function(){
console.log("arguments",arguments)
var key = JSON.stringify(arguments);
console.log("key",key)
if (cache[key]){
console.log("cache", cache)
return cache[key];
}
else{
val = func.apply(null, arguments);
cache[key] = val;
return val;
}
}
}
var fib = memo(function(n) {
if (n < 2){
return 1;
}else{
//We'll console.log a loader every time we have to recurse
console.log("loading...");
return fib(n-2) + fib(n-1);
}
});
// This is what the cache now looks like:
/*
{ ‘{“0”:0}’: 1,
‘{“0”:1}’: 1,
‘{“0”:2}’: 2,
‘{“0”:3}’: 3,
‘{“0”:4}’: 5,
‘{“0”:5}’: 8,
‘{“0”:6}’: 13,
‘{“0”:7}’: 21,
‘{“0”:8}’: 34,
‘{“0”:9}’: 55,
‘{“0”:10}’: 89,
‘{“0”:11}’: 144}
  • Maintaining state in the async world
  • Iterators
  • Module Design Pattern

Disadvantages of Closures

  • Closures prevent variables inside functions from being released by memory i.e. as long as the closure is active, the memory can’t be garbage collected. These variables will occupy memory and consume a lot of memory, which may lead to memory leakage.
    The solution to this problem is to delete all unnecessary local variables in time when these variables are not used i.e set closure to null.
  • Creating a function inside a function leads to duplicity in memory and causes the slowing down of the application.
    The solution to this problem is to use closures only when you need privacy otherwise use module patterns to create new objects with shared methods.

Nerd For Tech

From Confusion to Clarification

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store