Introduction
If you have learnt about functions and modules, learning closures should not be a big deal for you. If you just happened to land here and haven't gone through those two topics, that is also perfectly fine. Closures fall in the category of advanced JavaScript concepts but trust me, if you know and understand how inner functions work, understanding closures will be a cakewalk.
For all hard working and curious folks here who hate shortcuts and love to dive deep, I will recommend the post on functions before moving on. For those lazy and 2-minutes maggi lovers kinda dudes, this post will make sure you get the required basic concepts cooked and served right to your plate before jumping to the main course (closures).
Inner Functions
An inner function is fundamentally a "function within a function". JavaScript supports nested functions, that means you can create one or more functions inside a function. The inner functions may again contain functions inside and this nesting can go even deeper. Let's see this with a simple example.
function innerOuterDemo(){
console.log("The outer function");
function innerFunction(){
console.log("The inner function");
}
return innerFunction;
}
The function innerOuterDemo
contains an inner function named innerFunction
that just writes "The inner function" to console. A call to innerOuterDemo
will write "The outer function" to console and return the function innerFunction
.
var doSomething = innerOuterDemo();
doSomething();
Pretty simple and straightforward. But just keep in mind that once a function finishes the execution and returns, it's no longer in scope. That says when innerOuterDemo
gets executed and returns the innerFunction
, innerOuterDemo
is no longer in scope.
Now that we have covered the basics of function nesting and scope, let's jump right to closures. Consider the example below:
function foodAndMore(){
var myFood = "Pizza and Pasta";
function getMyFood(){
return myFood;
}
return getMyFood;
}
var foodILove = foodAndMore();
console.log("I love " + foodILove());
Quite similar to the first illustration except that we have some data (myFood
variable) we are playing with. The variable myFood
belongs to the outer function foodAndMore
but is used inside inner function getMyFood
in return
statement. Invocation to foodAndMore
function returns getMyFood
function which is assigned to variable foodILove
. When you run the above snippet, it will write the text "I love Pizza and Pasta
" to console.
Now what is special here? Remember my words when I said when a function completes its execution, it goes out of scope? If so, shouldn't myFood
variable that contains value "Pizza and Pasta
" go out of scope when function foodAndMore
returns after execution? But if you have seen the output in console which logs "I love Pizza and Pasta
", then this is certainly not the case.
Closure
A closure is the combination of an inner function and variables defined at outer scope but accessible to inner function. In other words, a closure is an inner function that can access outer function’s variables. Now let's get hungry and take a glance over our foodie example. As we have already observed, the inner function getMyFood
has access to outer function's variable myFood
even when outer function has completed its execution and is out of scope. So the combination of function getMyFood
and variable myFood
is an example of a closure. We can call getMyFood
function anytime through a variable reference (e.g. foodILove
) and get the value of myFood
variable which is "Pizza and Pasta
".
In JavaScript, inner functions have access not only to the variables of outer functions but also to their parameters. The next example will prove this right.
function getMultiplier(multiplyBy){
function multiply(num){
return multiplyBy * num;
}
return multiply;
}
var multiplyByTwo = getMultiplier(2);
var multiplyByTen = getMultiplier(10);
var twoIntoFive = multiplyByTwo(5);
var tenIntoSix = multiplyByTen(6);
So inner function multiply
has access to the outer function's parameter multiplyBy
. Outer function getMultiplier
returns a function that can be used as a multiplier function. We are creating two functions multiplyByTwo
and multiplyByTen
out of it. While invoking any of these two functions, JavaScript runtime remembers the execution environment (arguments to getMultiplier
function) and performs the multiplication between the numbers.
Closures are used extensively in JavaScript and JavaScript based libraries and frameworks. Trivial examples are event handling and AJAX calls when you write inline functions as event handler or callbacks. Those inline functions have access to the main (outer) function's variables and parameters.
Here is an example of a button click event handler function (closure) in jQuery. The function has access to count
variable and its state even when outer function is not in execution.
$(function(){
var count = 1;
$("#counterBtn").Click(function(){
alert("Your click count is: " + count++);
});
});
Closures are also useful in defining public
functions that can access private
functions and variables in JavaScript's popular module pattern. A simple illustration is given below.
var mathUtility = (function(){
var count = 1;
function increment(number){
return number + count;
}
function decrement(number){
return number - count;
}
return {
nextOf: increment,
previousOf: decrement
};
}());
var numberAfterFive = mathUtility.nextOf(5);
var numberBeforeTen = mathUtility.previousOf(10);
I hope the example above is self explanatory. We are creating a module mathUtility
that contains two private
functions increment
and decrement
. Both private
functions have access to count
variable in outer anonymous function, hence forming closures. We return an object, actually a module named mathUtility
containing two public
functions nextOf
and previousOf
that can be used to find next or previous numbers of any given number.
Final Words
Let me not reduce the size of your scrollbar and say the final words. Just remember that JavaScript functions remember their execution environment. JavaScript runtime makes sure that outer function's variables and parameters that were in scope and accessible to inner functions will always be accessible to inner functions.
I tried to keep this post concise, to the point and easy to understand. Leave your comments if you still have doubts or if you find something that can be improved further. Thanks for reading.
You might also be interested in:
I'm a software developer in Bangalore, India. I have special interest in web development and I blog at www.code-morning.com