Introduction
Following on from my previous article Prototypal inheritance with JavaScript, another area of the Javascipt programming language that can seem confusing, especially to a developer coming from a common programming language (such as C, C++, C# and Java), is the concept of closure.
A closure defines a function and the environment in which the function is defined. This environment includes free variables i.e. those variables that are not local to a function nor a parameter to a function but still part of the environment of the function. For example a global variable is a free variable. Although not local to the function it nonetheless is part of the function's environment as the function can access its value.
Closures and scope
Closures are related to the concept of scope. In a programming language the concept of scope refers to the visibility and lifetime of variables and parameters.
Common programming languages such as C, C++, C# and Java denote scope using curly braces. The curly braces define a block of code, hence these languages implement what is known as block scope. A block is a function and these functions define the lifetime (or scope) of the variables defined within them, and the parameters that are passed to them.
Any programmer coming from a common language will be used to block scope, and this can cause confusion, as JavaScript does not implement block scope. Instead, JavaScript implements what is known as function scope. As you would expect from a language that defines first class functions, the scope of variables and parameters is bound to the scope of the function.
In practice, what this means is that variables and parameters defined within a function are not visible outside of the function, and that a variable defined anywhere within a function is visible everywhere within the function.
To understand this let's consider the following example.
var someFunction = function(){
var a = 3, b = 5;
var someOtherFunction = function(){
var b = 7, c = 11;
a += b + c;
};
someOtherFunction();
};
In most common programming languages it is often best practice to define a variable as late as possible, just before it is required by the code. In JavaScript however, because it lacks block scope, it is best practice to define variables at the top of the function.
Closures in JavaScript
Now that we understand how scope works within JavaScript, we can continue with how closures work, as the two are closely related to each other.
Closures are found in programming languages which are capable of defining first-class functions such as JavaScript. In JavaScript, functions can be passed as parameters to other functions and assigned to variables.
If you program in a common programming language then you will know that a function defines a closure i.e. all variables defined within the function are not accessible outside the function.
However, things work slightly differently in JavaScript, and this can confuse even a seasoned developer.
Simple Example
Consider the following simple example.
function mainFunction() {
var name = "Dominic";
function displayText() {
alert(name);
}
return displayText
}
var myFunc = mainFunction();
myFunc();
The code above displays the text Dominic in a JavaScript alert box. This is unintuitive at first, as variables defined in one function are not accessible to another function. What is also interesting is that the displayText
inner function was returned from the outer function before being executed.
This is easily explained when we learn that the function displayText
is in fact a closure. It defines both the function and the environment in which it was created, which in the case of JavaScript includes all local variables that are in scope at the time the closure was defined. So in our simple example, the function displayText
is a closure that incorporates the name
variable.
In JavaScript, inner functions have access to variables defined in their outer functions. Whenever you define a function inside another function you are actually creating a closure. In other common programming languages, when you return from a function, all the local variables are no longer accessible because the stack has deallocated them. In JavaScript however, when you declare a function within another function, the local variables can remain accessible after returning from the function.
Here is another simple example that demonstrates that behaviour.
var before = 100;
function testFunction() {
alert(before);
alert(after);
}
var after = 99;
test();
When a Javascrpt function is invoked, a new excution context is created. This execution context is the environment in which the function is invoked. In the case of the function testFunction
above this includes both the variables before
and after
.
It's important to note that the local variables are not copies but references. The following example demonstrates this behaviour.
function output100() {
var num = 99;
var sayAlert = function() { alert(num); }
num++;
return sayAlert;
}
var sayNumber = output100();
sayNumber();
We can summarise ALL of the above by stating that a closure is the local variables to a function - kept alive after the function has returned.
If you are writing code using JavaScript then I suggest you take the time to fully comprehend closures and how they relate to JavaScript. Otherwise you will find yourself creating bugs that are difficult to diagnose.
Summary
Closures within JavaScript can be confusing, especially if coming from a common programming language. The best advice I can give is to play around with some of the code examples I have given here until you have grasped them. Feel free to leave a comment if you would like me to further elaborate on anything within this article.