Understanding JavaScript Closure with example

Subscribe to my newsletter and never miss my upcoming articles

Joy of getting to the end

All's well that ends well.

Welcome to the last post of the series JavaScript: Cracking the Nuts. I would like to thank you all for liking the series so far. There is another reason why this article is special to me. This is my 50th 🎉.

If you are new to the series and want to check out previous articles, here are the links,

Let us get started with the understanding of another JavaScript fundamental called, Closure.

Introduction to Closure

Closure is considered as an advanced concept in JavaScript. It may take a while to understand the concept fully. But, do not worry. As you have come across the fundamentals of Execution Context, Scope and Scope Chain in the previous articles of the series, it is going to be much simpler for you.

Let us start with a simple code example,

function sayHello(msg) {
  return function(name) {
    console.log(`${name}! ${msg}`);
  }
}

Here we have a function sayHello() takes a message as an argument. In JavaScript, functions can return another function. sayHello() returns a function that takes name as an argument and logs the name and message in the console. The function inside sayHello() is called inner function and sayHello() can be referred as an outer function.

Fair enough. How do we invoke them? Here it is,

var messageFor = sayHello('Hello, there!');
console.log(messageFor('Jack'));

As sayHello() returns a function, the variable messageFor points to a function. In the next line, we invoke messageFor() passing the value 'Jack'. It logs the following output,

Jack! Hello, there!

But, we have few questions to ask and get clarifications about,

  • How does the inner function of sayHello() got access to the msg variable? How is that possible?
  • What about the scope here? The msg variable is no way in the scope of the inner function, right? Then how is it working?

The answer is, it is working with the help of a JavaScript feature called, Closure.

A bit of recap

By now we are aware,

  • There is something called, global execution context and function execution context.
  • When a JavaScript program runs, a global execution context gets created.
  • When a function is invoked, a function execution context gets created.
  • All the function execution contexts get a reference to its outer environment, i.e, the execution context of the function who has created the currently running function.
  • Using the outer reference, JavaScript engine determines the accessibility of a variable. This is called, Scoping.
  • The scope of the variable can be found by traversing through the scope chain leading up-to the global execution context.

We have seen this picture before, scope_chain.png

Closure anatomy

In JavaScript, when a function is nested inside another function, the inner function creates a closure to the outer function's execution context. Doing so, it has access to the variables exactly the same way as the outer function's execution context has.

Let us understand the execution steps of the example above in more details. Here is the code again,

// declare the function
function sayHello(msg) {
  // it returns another function
  return function(name) {
    console.log(`${name}! ${msg}`);
  }
}

// invoke the function that returns a function
var messageFor = sayHello('Hello, there!');
// invoke the returned function
console.log(messageFor('Jack'));
  • A global execution context gets created. In its execution phase, the function sayHello() gets invoked.
    var messageFor = sayHello('Hello, there!');
    
  • A function execution context gets created for sayHello() and it gets added to the execution stack. Note, it has an argument called, msg and it will be available in its execution context.
     function sayHello(msg) {
       // code
     }
    
  • sayHello() returns another function and pop out the execution stack.
     function sayHello(msg) {
       // it returns another function
       return function(name) {
         console.log(`${name}! ${msg}`);
       }
    }
    
    But, hold on. sayHello() returns an inner function. It means, the inner function will create a closure to the outer function's(sayHello()) execution context. With that, it will also have all the access to the outer function's variables. In this case, it is msg.
  • Next, the global execution context invokes messageFor('Jack'). This is nothing but that inner function returned in the last step.
     console.log(messageFor('Jack'));
    
    This invocation will create a new function execution context. As we are passing Jack as an argument, it will be available in its execution context. But remember, it also has the access to the msg as explained in the step above.

This is how Closure help in retaining the access to the parent's execution context even when, the parent is already been executed and removed from the execution stack.

This is an extremely powerful concept. Hope it was simpler to understand. Not yet? Alright, let us see all these happening in visual way,

flow.gif

The inner function creates a special scope called, Closure Scope on the outer function's execution context. This is how the closure scope will be(in red border),

closure.png

Try this example

With the explanation we have got so far, what do you think will be the output of the following?

function myMultiplier(x) {
   return function inner(y) {
     return x * y;
   }
}

and then invoke the functions like,

var multiplyOf5 = myMultiplier(5);
var multiply5x4 = multiplyOf5(4);
console.log(multiply5x4);

I'm sure, you got this! Yeah, the inner function will have the access to the variable of parent function's(myMultiplier()) execution context. With that, the inner function, now has two variables, i,e, x and y in scope.

In the execution phase, x and y has values as, 5 and 4 respectively. The multiplication of these results in the value, 20. Isn't that simple now?

Conclusion

Closure is much easy to understand when you get to it conceptually with execution context and scope. I hope, you will try out many more examples with the understanding we got here.


If it was useful to you, please Like/Share so that, it reaches others as well. To get e-mail notification on my latest posts, please subscribe to my blog by hitting the Subscribe button at the top of the page.

Hope the entire series was useful to you and helped in learning some JavaScript concepts under the hood. See you sooner with another series in making, stay tuned!

Victoria Lo's photo

Thanks for this series! :) And congrats on your 50th post!

Prateek Aher's photo

What a wonderful way to explain. Dude! You're a wizard.

Tapas Adhikary's photo

Thanks Prateek Aher! Great that you liked it.

Nabeelah's photo

Absolutely loved how you broke down complex topics in these series 🔥

Tapas Adhikary's photo

Thank you Nabeelah! Very happy that, it was useful..

Subha Chanda's photo

I was searching for an article about Closures recently. Thank you for writing this! 😊

Show +2 replies
Tapas Adhikary's photo

Subha Chanda yeah I am! You too? Small world..

Subha Chanda's photo

Not actually! I am doing B. Sc in CS from A. C. College. 😅 Tapas Adhikary

Bolaji Ayodeji's photo

Thanks for starting this series, it's been amazing so far. Love this one!!