Closures in JavaScript for Beginners

Siddhant Varma
Better Programming
Published in
3 min readSep 5, 2019

--

Photo by Cristina Gottardi on Unsplash

It’s not unnatural that when you first start learning JavaScript, closures seem rather intimidating. But they’re actually really simple — let’s see how.

function outer(){
var a="From outer "
return function inner(){
var b="to inner"
console.log(a+b);
}
}
//outer();
//outer()();
//inner();

If you’re familiar with functions, closures are nothing but functions that make use of variables in outer functions that have previously returned. To begin with, copy the above code, and run it in the console. What do you think would be the result of invoking the respective function calls?

When we invoked outer(), we got the inner function as it is. When we invoked outer()(), we got two strings on the console concatenated. When we invoked inner(), we got an error.

Let’s see another example:

function outer(){
var a=10;
return function inner(){
console.log(a*10);
}
}
outer()();

You might find it strange to invoke functions using ()(). But this is what essentially distinguishes closures from nested functions syntactically.

The above two examples show two distinguishable features — one being the way of invocation and the other being the presence of the return keyword. What it really means is the inner function can access the variables of the outer function long after the outer function has returned.

Let’s say you want to write a simple function to multiply two numbers. An obvious way is:

function multiply(a,b){
return a*b;
}
multiply(3,5);

Let’s try another way.

function multiply(a){
return function(b){
return a*b;
}
}
multiply(3)(5);

The second method makes use of closures, where we reference a specific instance of a local binding in an enclosing scope and return the inner function.

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

If you run the above code first, you’ll get an error saying “Function statements require a function name” and subsequently another saying “add(…) is not a function.” This is because we haven’t returned the inner function. Hence using the ()() for an invoking call doesn’t make sense. If you remove one pair of (), it returns “undefined,” which it should since you aren’t really returning anything.

That’s pretty much it. They’re nested functions where the inner function makes use of a variable of the outer function. And remember to add the return keyword before the inner function.

Let’s See a Practical Use of Closures

Closures can be used to create a private variable. A private variable is the one that cannot be modified externally.

Let’s look at another example to understand this. Say, you want to count the number of times a user clicked a button.

<button onclick="clickCount()">click me!</button>

You can use a global variable(cnt) to count.

var cnt=0;
function clickCount(){
cnt++;
}

But there’s a small problem with this: Any script on the page can change the value of our variable cnt without even calling the function clickCount().

It’s not really an issue — let’s just declare cnt inside the function.

function clickCount(){
var cnt=0;
cnt++;
}

But now every time that function is called, cnt always starts from 0. So let’s use nested functions instead.

function cntWrapper() {
var cnt = 0;
function clickCount() {
cnt++;
}
clickCount();
return cnt;
}

Remember that nested functions have access to the scope above them. To invoke the inner function, you’ll have to invoke the outer function and once again your counter variable will start from 0 every time. Looks like we’re back to square one. If only we could invoke the inner function from the outside.

Enter closure (pun intended)

var updateCnt=(function() {
var cnt = 0;
return function() {
cnt++;
return cnt;
}
})();

We created a self-invoking function that runs only once, initializes cnt to 0, and returns a function expression.

Our function binding can access the cnt in the parent scope. You’ll notice every time you invoke updateCnt(), your counter takes the previous value and adds 1 to it. If you type cnt on the console, you’ll get an error saying it is not defined. Thus our cnt variable, now all safe and secure, is essentially a private variable, protected by the scope of an anonymous function.

That’s everything about closures you need to know!

--

--

Building Looppanel 🚀 (Future of user research) | Software Engineer/Tech Writer