Javascript closure in 3 minutes: examples and interview questions

Author image
Author

Fashanu T.

15, Jan 2021

4 Minutes Read...


There are so many complicated tutorials out there on closure, —its just unbelievable 😩.

So i am going to bet you a $ that by the end of reading this tutorial, you will understand the basic fundamental of closure in no time.

Lets get right into it...

Look at the function below::

javascript
var foo = function(passed) {
    var inner  = 2;
    return passed + inner;
} 
console.log(foo(3));

In the above i have a function named foo and i am passing the parameter passed with inner variable of 2, and then i returned passed + inner.

The  function above basically adds 2 to what ever you passed and return the sum.

But in JavaScript, you can get by without passing any variables. 

What do i mean by this? If you are not passing, how do you get the value?

Well, you can define the variable outside like this:

javascript
var passed = 3;
var foo = function() {
    var inner = 2;
    return passed + inner;
}
console.log(foo());

This will still give you the same result, and closure is already in this.

So, where is the closure in this?

Scope in JavaScript

Generally a variable defined outside have a general scope and is available inside any function, because JavaScript uses what we call lexical scoping this is the —core basic of closure.

This mean that inner variables in a function is not available outside of that function, but variable defined outside a function is available in any function.

What is JavaScript closure

Closure is when a function use variables that are defined outside that function.

closure.jpg

Javascript CLOSURE in add function

Expand the function scope in the log and expand closure. You will see that it has a property called passed of 3. This is the closure.

So for you to execute foofrom the code above, it will look at the variables it needs.

passed is not inside the function, so it will look outside the function for passed. If it cannot find passed, it will be undefined.

Lets do something interesting::

—Closure lets functions to have private variable.
javascript
var addTo = function(passed) {
  var add = function(inner){
	return passed + inner;
  }
  return add;
}

console.dir(addTo(3)); <!-- Expand the scope closure to see property passed of 3 -->
console.dir(addTo(4));
<!-- Expand the scope closure to see property passed of 3 -->

Now do this::

javascript

var addThree = new addTo(3);
var addTwo = new addTo(2);

console.log(addThree(1));
console.log(addTwo(1));

<!-- the result is 4 and 3 respectively; -->

So basically, closure lets a function addThree and addTwo keep the private variable it needed to execute.

For this lets look at another example::

Auto-detect
let f = () => {
    let i = 1;
    let j = 2;
    return () => {
	console.log(i);
    }
}
console.dir(f());

When you expand the function and then closure, you might expect to find i: 1, j:2.

But, surprisingly, it only holds i: 1. Why is that?

Because the function is not using j and so cannot have a closure for j. Basically, the function f() will only hold i which is the minimum it needed to execute.

What does this mean?

Well, if you require j, for instance, adding console.log(j) in the return function for f(), it will also have a closure for j in this case.

A closure inside a loop: interview question

If i have a for loop for instance, lets say::

javascript
for (let i = 0; i< 3; i++) {
     setTimeout(()=> {
	console.log(i);
     },1000);
}
console.log('after the loop');

<!--- You will get -->
result: after the lopp 0 1 2

This is a common behavior you should expect. Now lets try this:

javascript
for (var i = 0; i< 3; i++) {
     setTimeout(()=> {
	console.log(i);
     },1000);
}
console.log('after the loop');

<!--- You will get -->
result: after the lopp 3 3 3

Why is the behavior this way when your loop is meant to run from 0 to 2?

First of all, your loop should be running 0 - 2 and should not even go to three. 

We have to pause for a minute to understand this. Lets go to the sample code that uses let.

Because, i am using let, which is a block scope, so it will first hold i = 0 for the first loop scope.

As soon as the next loop comes in, since its a block scope, it hold i and so, it will look at the i++ and create a new variable for each loop. Which in turn, then gives you i = 1, the i is a new variable here and so on and so forth.

Now lets switch to var in this case, like in the sample code above.

What it does is, It will first look at var = 0

The function inside the setTimeout holds a closure of 0 for the first loop.

For the next loop, now because var has function scope, it doesn't create a new variable. It just changes its value instead of creating a new i variable like in let.

So since the setTimeout executes after the original loop is completed, it means the function has already looped and kept its closure ahead of time.

Lets go to the first loop for var.

var = 0; so the first loop holds 0;

var = 1; so the next loop holds 1; —right.

Since var is changed (not creating new variable) and is now 1

The first loop now hold var as 1 which did not create a new variable, but changed its value, unlike let that created a new variable of 1 instead of changing 0 to 1.

So you will get instead::::

First loop now hold var of 1;

Second loop now holds var of 1;

thirs loop..............;

When var is now changed to 2,

First loop now holds new var of 2;

Second loop var of 2 .......

Third loop ......

For for loop to verify it's actually less than three, it has to go to three, so var will increment one more time to 3.

Even though its not creating new setTimeout function for it last increment.

Therefore, the first loop var is now 3: an updated closure value.

Second loop.....

Third loop...

At the end of 1000 millisecond, you get 3 printed 3 times.

Okey, lets say we want to fix this var and not use let, but also make sure it keeps the value as private to its function.

We remedy this by immediately invoking the setTimeout function like this.

javascript
for (var i = 0; i< 3; i++) {
  (()=> {
  	setTimeout(()=> {
	console.log(i);
	},1000);
  })();
}
console.log('after the loop');

<!--- You will get -->
result: after the lopp 0 1 2

The reason this works is because, if you immediately invoke a function, it kinda create a block scope, because it runs right away.

This is the basic fundamental of closure in JavaScript.

In conclusion, JavaScript CLOSURE are functions with preserved data, that's all there is to it.

Learn all about JSON, and transferring JSON here

If you also want to have the basic in-depth knowledge on redirect in JavaScript, check here.