Reputation: 597261
How would you explain JavaScript closures to someone with a knowledge of the concepts they consist of (for example functions, variables and the like), but does not understand closures themselves?
I have seen the Scheme example given on Wikipedia, but unfortunately it did not help.
Upvotes: 7612
Views: 1630610
Reputation: 13972
A closure is a pairing of:
A lexical environment is part of every execution context (stack frame) and is a map between identifiers (i.e. local variable names) and values.
Every function in JavaScript maintains a reference to its outer lexical environment. This reference is used to configure the execution context created when a function is invoked. This reference enables code inside the function to "see" variables declared outside the function, regardless of when and where the function is called.
If a function was called by a function, which in turn was called by another function, then a chain of references to outer lexical environments is created. This chain is called the scope chain.
In the following code, inner
forms a closure with the lexical environment of the execution context created when foo
is invoked, closing over variable secret
:
function foo() {
const secret = Math.trunc(Math.random() * 100)
return function inner() {
console.log(`The secret number is ${secret}.`)
}
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret` is to invoke `f`
In other words: in JavaScript, functions carry a reference to a private "box of state", to which only they (and any other functions declared within the same lexical environment) have access. This box of the state is invisible to the caller of the function, delivering an excellent mechanism for data-hiding and encapsulation.
And remember: functions in JavaScript can be passed around like variables (first-class functions), meaning these pairings of functionality and state can be passed around your program, similar to how you might pass an instance of a class around in C++.
If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier.
So, if you want a function to always have access to a private piece of state, you can use a closure.
...and frequently we do want to associate the state with a function. For example, in Java or C++, when you add a private instance variable and a method to a class, you are associating the state with functionality.
In C and most other common languages, after a function returns, all the local variables are no longer accessible because the stack-frame is destroyed. In JavaScript, if you declare a function within another function, then the local variables of the outer function can remain accessible after returning from it. In this way, in the code above, secret
remains available to the function object inner
, after it has been returned from foo
.
Closures are useful whenever you need a private state associated with a function. This is a very common scenario - and remember: JavaScript did not have a class syntax until 2015, and it still does not have a private field syntax. Closures meet this need.
In the following code, the function toString
closes over the details of the car.
function Car(manufacturer, model, year, color) {
return {
toString() {
return `${manufacturer} ${model} (${year}, ${color})`
}
}
}
const car = new Car('Aston Martin', 'V8 Vantage', '2012', 'Quantum Silver')
console.log(car.toString())
In the following code, the function inner
closes over both fn
and args
.
function curry(fn) {
const args = []
return function inner(arg) {
if(args.length === fn.length) return fn(...args)
args.push(arg)
return inner
}
}
function add(a, b) {
return a + b
}
const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5
In the following code, function onClick
closes over variable BACKGROUND_COLOR
.
const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200, 200, 242, 1)'
function onClick() {
$('body').style.background = BACKGROUND_COLOR
}
$('button').addEventListener('click', onClick)
<button>Set background color</button>
In the following example, all the implementation details are hidden inside an immediately executed function expression. The functions tick
and toString
close over the private state and functions they need to complete their work. Closures have enabled us to modularize and encapsulate our code.
let namespace = {};
(function foo(n) {
let numbers = []
function format(n) {
return Math.trunc(n)
}
function tick() {
numbers.push(Math.random() * 100)
}
function toString() {
return numbers.map(format)
}
n.counter = {
tick,
toString
}
}(namespace))
const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())
This example shows that the local variables are not copied in the closure: the closure maintains a reference to the original variables themselves. It is as though the stack-frame stays alive in memory even after the outer function exits.
function foo() {
let x = 42
let inner = () => console.log(x)
x = x + 1
return inner
}
foo()() // logs 43
In the following code, three methods log
, increment
, and update
all close over the same lexical environment.
And every time createObject
is called, a new execution context (stack frame) is created and a completely new variable x
, and a new set of functions (log
etc.) are created, that close over this new variable.
function createObject() {
let x = 42;
return {
log() { console.log(x) },
increment() { x++ },
update(value) { x = value }
}
}
const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42
If you are using variables declared using var
, be careful you understand which variable you are closing over. Variables declared using var
are hoisted. This is much less of a problem in modern JavaScript due to the introduction of let
and const
.
In the following code, each time around the loop, a new function inner
is created, which closes over i
. But because var i
is hoisted outside the loop, all of these inner functions close over the same variable, meaning that the final value of i
(3) is printed, three times.
function foo() {
var result = []
for (var i = 0; i < 3; i++) {
result.push(function inner() { console.log(i) } )
}
return result
}
const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
result[i]()
}
function
from inside another function is the classic example of closure, because the state inside the outer function is implicitly available to the returned inner function, even after the outer function has completed execution.eval()
inside a function, a closure is used. The text you eval
can reference local variables of the function, and in the non-strict mode, you can even create new local variables by using eval('var foo = …')
.new Function(…)
(the Function constructor) inside a function, it does not close over its lexical environment: it closes over the global context instead. The new function cannot reference the local variables of the outer function.Upvotes: 8345
Reputation: 126082
I wrote a blog post a while back explaining closures. Here's what I said about closures in terms of why you'd want one.
Closures are a way to let a function have persistent, private variables - that is, variables that only one function knows about, where it can keep track of info from previous times that it was run.
In that sense, they let a function act a bit like an object with private attributes.
var iplus1= (function ()
{
var plusCount = 0;
return function ()
{
return ++plusCount;
}
})();
Here the outer self-invoking anonymous function run only once and sets plusCount
variable to 0, and returns the inner function expression.
Whereas inner function has access to plusCount
variable. Now every time we invoke the function iplus1()
, the inner function increments the plusCount
variable.
The important point to keep in mind is that no other script on the page has access to plusCount
variable and the only way to change the plusCount
variable is through iplus1
function.
Read More for reference: So what are these closure thingys?
Upvotes: 255
Reputation: 26277
A closure is where an inner function has access to variables in its outer function. That's probably the simplest one-line explanation you can get for closures.
And the inner function has access not only to the outer function’s variables, but also to the outer function’s parameters as in the example below
Example
// Closure Example
function addNumbers(firstNumber, secondNumber)
{
var returnValue = "Result is : ";
// This inner function has access to the outer function's variables & parameters
function add()
{
return returnValue + (firstNumber + secondNumber);
}
return add();
}
var result = addNumbers(10, 20);
console.log(result); //30
Upvotes: 99
Reputation: 59234
I tend to learn better by GOOD/BAD comparisons. I like to see working code followed by non-working code that someone is likely to encounter. I put together a jsFiddle that does a comparison and tries to boil down the differences to the simplest explanations I could come up with.
console.log('CLOSURES DONE RIGHT');
var arr = [];
function createClosure(n) {
return function () {
return 'n = ' + n;
}
}
for (var index = 0; index < 10; index++) {
arr[index] = createClosure(index);
}
for (var index of arr) {
console.log(arr[index]());
}
In the above code createClosure(n)
is invoked in every iteration of the loop. Note that I named the variable n
to highlight that it is a new variable created in a new function scope and is not the same variable as index
which is bound to the outer scope.
This creates a new scope and n
is bound to that scope; this means we have 10 separate scopes, one for each iteration.
createClosure(n)
returns a function that returns the n within that scope.
Within each scope n
is bound to whatever value it had when createClosure(n)
was invoked so the nested function that gets returned will always return the value of n
that it had when createClosure(n)
was invoked.
console.log('CLOSURES DONE WRONG');
function createClosureArray() {
var badArr = [];
for (var index = 0; index < 10; index++) {
badArr[index] = function () {
return 'n = ' + index;
};
}
return badArr;
}
var badArr = createClosureArray();
for (var index of badArr) {
console.log(badArr[index]());
}
In the above code the loop was moved within the createClosureArray()
function and the function now just returns the completed array, which at first glance seems more intuitive.
What might not be obvious is that since createClosureArray()
is only invoked once only one scope is created for this function instead of one for every iteration of the loop.
Within this function a variable named index
is defined. The loop runs and adds functions to the array that return index
. Note that index
is defined within the createClosureArray
function which only ever gets invoked one time.
Because there was only one scope within the createClosureArray()
function, index
is only bound to a value within that scope. In other words, each time the loop changes the value of index
, it changes it for everything that references it within that scope.
All of the functions added to the array return the SAME index
variable from the parent scope where it was defined instead of 10 different ones from 10 different scopes like the first example. The end result is that all 10 functions return the same variable from the same scope.
After the loop finished and index
was done being modified the end value was 10, therefore every function added to the array returns the value of the single index
variable which is now set to 10.
CLOSURES DONE RIGHT
n = 0
n = 1
n = 2
n = 3
n = 4
n = 5
n = 6
n = 7
n = 8
n = 9CLOSURES DONE WRONG
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
n = 10
Upvotes: 189
Reputation: 17243
The original question had a quote:
If you can't explain it to a six-year old, you really don't understand it yourself.
This is how I'd try to explain it to an actual six-year-old:
You know how grown-ups can own a house, and they call it home? When a mom has a child, the child doesn't really own anything, right? But its parents own a house, so whenever someone asks "Where's your home?", the child can answer "that house!", and point to the house of its parents.
A "Closure" is the ability of the child to always (even if abroad) be able to refer to its home, even though it's really the parent's who own the house.
Upvotes: 240
Reputation: 4254
The children will never forget the secrets they have shared with their parents, even after their parents are gone. This is what closures are for functions.
The secrets for JavaScript functions are the private variables
var parent = function() {
var name = "Mary"; // secret
}
Every time you call it, the local variable "name" is created and given the name "Mary". And every time the function exits the variable is lost and the name is forgotten.
As you may guess, because the variables are re-created every time the function is called, and nobody else will know them, there must be a secret place where they are stored. It could be called Chamber of Secrets or stack or local scope but it doesn't matter. We know they are there, somewhere, hidden in the memory.
But, in JavaScript, there is this very special thing that functions which are created inside other functions, can also know the local variables of their parents and keep them as long as they live.
var parent = function() {
var name = "Mary";
var child = function(childName) {
// I can also see that "name" is "Mary"
}
}
So, as long as we are in the parent -function, it can create one or more child functions which do share the secret variables from the secret place.
But the sad thing is, if the child is also a private variable of its parent function, it would also die when the parent ends, and the secrets would die with them.
So to live, the child has to leave before it's too late
var parent = function() {
var name = "Mary";
var child = function(childName) {
return "My name is " + childName +", child of " + name;
}
return child; // child leaves the parent ->
}
var child = parent(); // < - and here it is outside
And now, even though Mary is "no longer running", the memory of her is not lost and her child will always remember her name and other secrets they shared during their time together.
So, if you call the child "Alice", she will respond
child("Alice") => "My name is Alice, child of Mary"
That's all there is to tell.
Upvotes: 141
Reputation: 347
Closures in JavaScript are associated with concept of scopes.
Prior to es6, there is no block level scope, there is only function level scope in JS.
That means whenever there is a need for block level scope, we need to wrap it inside a function.
Check this simple and interesting example, how closure solves this issue in ES5
// let say we can only use a traditional for loop, not the forEach
for (var i = 0; i < 10; i++) {
setTimeout(function() {
console.log('without closure the visited index - '+ i)
})
}
// this will print 10 times 'visited index - 10', which is not correct
/**
Expected output is
visited index - 0
visited index - 1
.
.
.
visited index - 9
**/
// we can solve it by using closure concept
//by using an IIFE (Immediately Invoked Function Expression)
// --- updated code ---
for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function() {
console.log('with closure the visited index - '+ i)
})
})(i);
}
NB: this can easily be solved by using es6 let
instead of var
, as let creates lexical scope.
Upvotes: 7
Reputation: 89
Maybe you should consider an object-oriented structure instead of inner functions. For example:
var calculate = {
number: 0,
init: function (num) {
this.number = num;
},
add: function (val) {
this.number += val;
},
rem: function (val) {
this.number -= val;
}
};
And read the result from the calculate.number variable, who needs "return" anyway.
//Addition
First think about scope which defines what variable you have to access to (In Javascript);
//there are two kinds of scope
Global Scope which include variable declared outside function or curly brace
let globalVariable = "foo";
One thing to keep in mind is once you've declared a global variable you can use it anywhere in your code even in function;
Local Scope which include variable that are usable only in a specific part of your code:
Function scope is when you declare a variable in a function you can access the variable only within the function
function User(){
let name = "foo";
alert(name);
}
alert(name);//error
//Block scope is when you declare a variable within a block then you can access that variable only within a block
{
let user = "foo";
alert(user);
}
alert(user);
//Uncaught ReferenceError: user is not defined at.....
//A Closure
function User(fname){
return function(lname){
return fname + " " lname;
}
}
let names = User("foo");
alert(names("bar"));
//When you create a function within a function you've created a closure, in our example above since the outer function is returned the inner function got access to outer function's scope
Upvotes: 18
Reputation: 2862
In JavaScript closures are awesome and unique, where variables or arguments are available to inner functions, and they will be alive even after the outer function has returned. Closures are used in most of the design patterns in JS
function getFullName(a, b) {
return a + b;
}
function makeFullName(fn) {
return function(firstName) {
return function(secondName) {
return fn(firstName, secondName);
}
}
}
makeFullName(getFullName)("Stack")("overflow"); // Stackoverflow
Upvotes: 38
Reputation: 545985
Closures are hard to explain because they are used to make some behaviour work that everybody intuitively expects to work anyway. I find the best way to explain them (and the way that I learned what they do) is to imagine the situation without them:
const makePlus = function(x) {
return function(y) { return x + y; };
}
const plus5 = makePlus(5);
console.log(plus5(3));
What would happen here if JavaScript didn't know closures? Just replace the call in the last line by its method body (which is basically what function calls do) and you get:
console.log(x + 3);
Now, where's the definition of x
? We didn't define it in the current scope. The only solution is to let plus5
carry its scope (or rather, its parent's scope) around. This way, x
is well-defined and it is bound to the value 5.
Upvotes: 544
Reputation: 1024
Every function in JavaScript maintains a link to its outer lexical environment. A lexical environment is a map of all the names (eg. variables, parameters) within a scope, with their values.
So, whenever you see the function
keyword, code inside that function has access to variables declared outside the function.
function foo(x) {
var tmp = 3;
function bar(y) {
console.log(x + y + (++tmp)); // will log 16
}
bar(10);
}
foo(2);
This will log 16
because function bar
closes over the parameter x
and the variable tmp
, both of which exist in the lexical environment of outer function foo
.
Function bar
, together with its link with the lexical environment of function foo
is a closure.
A function doesn't have to return in order to create a closure. Simply by virtue of its declaration, every function closes over its enclosing lexical environment, forming a closure.
function foo(x) {
var tmp = 3;
return function (y) {
console.log(x + y + (++tmp)); // will also log 16
}
}
var bar = foo(2);
bar(10); // 16
bar(10); // 17
The above function will also log 16, because the code inside bar
can still refer to argument x
and variable tmp
, even though they are no longer directly in scope.
However, since tmp
is still hanging around inside bar
's closure, it is available to be incremented. It will be incremented each time you call bar
.
The simplest example of a closure is this:
var a = 10;
function test() {
console.log(a); // will output 10
console.log(b); // will output 6
}
var b = 6;
test();
When a JavaScript function is invoked, a new execution context ec
is created. Together with the function arguments and the target object, this execution context also receives a link to the lexical environment of the calling execution context, meaning the variables declared in the outer lexical environment (in the above example, both a
and b
) are available from ec
.
Every function creates a closure because every function has a link to its outer lexical environment.
Note that variables themselves are visible from within a closure, not copies.
Upvotes: 4144
Reputation: 27786
TLDR
A closure is a link between a function and its outer lexical (ie. as-written) environment, such that the identifiers (variables, parameters, function declarations etc) defined within that environment are visible from within the function, regardless of when or from where the function is invoked.
Details
In the terminology of the ECMAScript specification, a closure can be said to be implemented by the [[Environment]]
reference of every function-object, which points to the lexical environment within which the function is defined.
When a function is invoked via the internal [[Call]]
method, the [[Environment]]
reference on the function-object is copied into the outer environment reference of the environment record of the newly-created execution context (stack frame).
In the following example, function f
closes over the lexical environment of the global execution context:
function f() {}
In the following example, function h
closes over the lexical environment of function g
, which, in turn, closes over the lexical environment of the global execution context.
function g() {
function h() {}
}
If an inner function is returned by an outer, then the outer lexical environment will persist after the outer function has returned. This is because the outer lexical environment needs to be available if the inner function is eventually invoked.
In the following example, function j
closes over the lexical environment of function i
, meaning that variable x
is visible from inside function j
, long after function i
has completed execution:
function i() {
var x = 'mochacchino'
return function j() {
console.log('Printing the value of x, from within function j: ', x)
}
}
const k = i()
setTimeout(k, 500) // invoke k (which is j) after 500ms
In a closure, the variables in the outer lexical environment themselves are available, not copies.
function l() {
var y = 'vanilla';
return {
setY: function(value) {
y = value;
},
logY: function(value) {
console.log('The value of y is: ', y);
}
}
}
const o = l()
o.logY() // The value of y is: vanilla
o.setY('chocolate')
o.logY() // The value of y is: chocolate
The chain of lexical environments, linked between execution contexts via outer environment references, forms a scope chain and defines the identifiers visible from any given function.
Please note that in an attempt to improve clarity and accuracy, this answer has been substantially changed from the original.
Upvotes: 421
Reputation: 1912
A function is executed in the scope of the object/function in which it is defined. The said function can access the variables defined in the object/function where it has been defined while it is executing.
And just take it literally.... as the code is written :P
Upvotes: 20
Reputation: 504
OK, 6-year-old closures fan. Do you want to hear the simplest example of closure?
Let's imagine the next situation: a driver is sitting in a car. That car is inside a plane. Plane is in the airport. The ability of driver to access things outside his car, but inside the plane, even if that plane leaves an airport, is a closure. That's it. When you turn 27, look at the more detailed explanation or at the example below.
Here is how I can convert my plane story into the code.
var plane = function(defaultAirport) {
var lastAirportLeft = defaultAirport;
var car = {
driver: {
startAccessPlaneInfo: function() {
setInterval(function() {
console.log("Last airport was " + lastAirportLeft);
}, 2000);
}
}
};
car.driver.startAccessPlaneInfo();
return {
leaveTheAirport: function(airPortName) {
lastAirportLeft = airPortName;
}
}
}("Boryspil International Airport");
plane.leaveTheAirport("John F. Kennedy");
Upvotes: 406
Reputation: 3260
Taking the question seriously, we should find out what a typical 6-year-old is capable of cognitively, though admittedly, one who is interested in JavaScript is not so typical.
On Childhood Development: 5 to 7 Years it says:
Your child will be able to follow two-step directions. For example, if you say to your child, "Go to the kitchen and get me a trash bag" they will be able to remember that direction.
We can use this example to explain closures, as follows:
The kitchen is a closure that has a local variable, called
trashBags
. There is a function inside the kitchen calledgetTrashBag
that gets one trash bag and returns it.
We can code this in JavaScript like this:
function makeKitchen() {
var trashBags = ['A', 'B', 'C']; // only 3 at first
return {
getTrashBag: function() {
return trashBags.pop();
}
};
}
var kitchen = makeKitchen();
console.log(kitchen.getTrashBag()); // returns trash bag C
console.log(kitchen.getTrashBag()); // returns trash bag B
console.log(kitchen.getTrashBag()); // returns trash bag A
Further points that explain why closures are interesting:
makeKitchen()
is called, a new closure is created with its own separate trashBags
.trashBags
variable is local to the inside of each kitchen and is not accessible outside, but the inner function on the getTrashBag
property does have access to it. getTrashBag
function does that here.Upvotes: 814
Reputation: 5720
The author of Closures has explained closures pretty well, explaining the reason why we need them and also explaining LexicalEnvironment which is necessary to understanding closures.
Here is the summary:
What if a variable is accessed, but it isn’t local? Like here:
In this case, the interpreter finds the variable in the
outer LexicalEnvironment
object.
The process consists of two steps:
When a function is created, it gets a hidden property, named [[Scope]], which references the current LexicalEnvironment.
If a variable is read, but can not be found anywhere, an error is generated.
Nested functions
Functions can be nested one inside another, forming a chain of LexicalEnvironments which can also be called a scope chain.
So, function g has access to g, a and f.
Closures
A nested function may continue to live after the outer function has finished:
Marking up LexicalEnvironments:
As we see, this.say
is a property in the user object, so it continues to live after User completed.
And if you remember, when this.say
is created, it (as every function) gets an internal reference this.say.[[Scope]]
to the current LexicalEnvironment. So, the LexicalEnvironment of the current User execution stays in memory. All variables of User also are its properties, so they are also carefully kept, not junked as usually.
The whole point is to ensure that if the inner function wants to access an outer variable in the future, it is able to do so.
To summarize:
This is called a closure.
Upvotes: 85
Reputation: 4960
(I am not taking the 6-years-old thing into account.)
In a language like JavaScript, where you can pass functions as parameters to other functions (languages where functions are first class citizens), you will often find yourself doing something like:
var name = 'Rafael';
var sayName = function() {
console.log(name);
};
You see, sayName
doesn't have the definition for the name
variable, but it does use the value of name
that was defined outside of sayName
(in a parent scope).
Let's say you pass sayName
as a parameter to another function, that will call sayName
as a callback:
functionThatTakesACallback(sayName);
Note that:
sayName
will be called from inside functionThatTakesACallback
(assume that, since I haven't implemented functionThatTakesACallback
in this example).sayName
is called, it will log the value of the name
variable.functionThatTakesACallback
doesn't define a name
variable (well, it could, but it wouldn't matter, so assume it doesn't).So we have sayName
being called inside functionThatTakesACallback
and referring to a name
variable that is not defined inside functionThatTakesACallback
.
What happens then? A ReferenceError: name is not defined
?
No! The value of name
is captured inside a closure. You can think of this closure as context associated to a function, that holds the values that were available where that function was defined.
So: Even though name
is not in scope where the function sayName
will be called (inside functionThatTakesACallback
), sayName
can access the value for name
that is captured in the closure associated with sayName
.
--
From the book Eloquent JavaScript:
A good mental model is to think of function values as containing both the code in their body and the environment in which they are created. When called, the function body sees its original environment, not the environment in which the call is made.
Upvotes: 23
Reputation: 104870
A closure is a function having access to the parent scope, even after the parent function has closed.
So basically a closure is a function of another function. We can say like a child function.
A closure is an inner function that has access to the outer (enclosing) function’s variables—scope chain. The closure has three scope chains: it has access to its own scope (variables defined between its curly brackets), it has access to the outer function’s variables, and it has access to the global variables.
The inner function has access not only to the outer function’s variables but also to the outer function’s parameters. Note that the inner function cannot call the outer function’s arguments object, however, even though it can call the outer function’s parameters directly.
You create a closure by adding a function inside another function.
Also, it's very useful method which is used in many famous frameworks including Angular
, Node.js
and jQuery
:
Closures are used extensively in Node.js; they are workhorses in Node.js’ asynchronous, non-blocking architecture. Closures are also frequently used in jQuery and just about every piece of JavaScript code you read.
But how the closures look like in a real-life coding? Look at this simple sample code:
function showName(firstName, lastName) {
var nameIntro = "Your name is ";
// this inner function has access to the outer function's variables, including the parameter
function makeFullName() {
return nameIntro + firstName + " " + lastName;
}
return makeFullName();
}
console.log(showName("Michael", "Jackson")); // Your name is Michael Jackson
Also, this is classic closure way in jQuery which every javascript and jQuery developers used it a lot:
$(function() {
var selections = [];
$(".niners").click(function() { // this closure has access to the selections variable
selections.push(this.prop("name")); // update the selections variable in the outer function's scope
});
});
But why we use closures? when we use it in an actual programming? what are the practical use of closures? the below is a good explanation and example by MDN:
Practical closures
Closures are useful because they let you associate some data (the lexical environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods.
Consequently, you can use a closure anywhere that you might normally use an object with only a single method.
Situations where you might want to do this are particularly common on the web. Much of the code we write in front-end JavaScript is event-based — we define some behavior, then attach it to an event that is triggered by the user (such as a click or a keypress). Our code is generally attached as a callback: a single function which is executed in response to the event.
For instance, suppose we wish to add some buttons to a page that adjust the text size. One way of doing this is to specify the font-size of the body element in pixels, then set the size of the other elements on the page (such as headers) using the relative em unit:
Read the code below and run the code to see how closure help us here to easily make separate functions for each sections:
//javascript
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
/*css*/
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.2em;
}
<!--html><!-->
<p>Some paragraph text</p>
<h1>some heading 1 text</h1>
<h2>some heading 2 text</h2>
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
For further study about closures, I recommend you to visit this page by MDN: https://developer.mozilla.org/en/docs/Web/JavaScript/Closures
Upvotes: 36
Reputation: 62412
I need to know how many times a button has been clicked and do something on every third click...
// Declare counter outside event handler's scope
var counter = 0;
var element = document.getElementById('button');
element.addEventListener("click", function() {
// Increment outside counter
counter++;
if (counter === 3) {
// Do something every third time
console.log("Third time's the charm!");
// Reset counter
counter = 0;
}
});
<button id="button">Click Me!</button>
Now this will work, but it does encroach into the outer scope by adding a variable, whose sole purpose is to keep track of the count. In some situations, this would be preferable as your outer application might need access to this information. But in this case, we are only changing every third click's behavior, so it is preferable to enclose this functionality inside the event handler.
var element = document.getElementById('button');
element.addEventListener("click", (function() {
// init the count to 0
var count = 0;
return function(e) { // <- This function becomes the click handler
count++; // and will retain access to the above `count`
if (count === 3) {
// Do something every third time
console.log("Third time's the charm!");
//Reset counter
count = 0;
}
};
})());
<button id="button">Click Me!</button>
Notice a few things here.
In the above example, I am using the closure behavior of JavaScript. This behavior allows any function to have access to the scope in which it was created, indefinitely. To practically apply this, I immediately invoke a function that returns another function, and because the function I'm returning has access to the internal count variable (because of the closure behavior explained above) this results in a private scope for usage by the resulting function... Not so simple? Let's dilute it down...
A simple one-line closure
// _______________________Immediately invoked______________________
// | |
// | Scope retained for use ___Returned as the____ |
// | only by returned function | value of func | |
// | | | | | |
// v v v v v v
var func = (function() { var a = 'val'; return function() { alert(a); }; })();
All variables outside the returned function are available to the returned function, but they are not directly available to the returned function object...
func(); // Alerts "val"
func.a; // Undefined
Get it? So in our primary example, the count variable is contained within the closure and always available to the event handler, so it retains its state from click to click.
Also, this private variable state is fully accessible, for both readings and assigning to its private scoped variables.
There you go; you're now fully encapsulating this behavior.
Full Blog Post (including jQuery considerations)
Upvotes: 628
Reputation: 4075
FOREWORD: this answer was written when the question was:
Like the old Albert said : "If you can't explain it to a six-year old, you really don't understand it yourself.”. Well I tried to explain JS closures to a 27 years old friend and completely failed.
Can anybody consider that I am 6 and strangely interested in that subject ?
I'm pretty sure I was one of the only people that attempted to take the initial question literally. Since then, the question has mutated several times, so my answer may now seem incredibly silly & out of place. Hopefully the general idea of the story remains fun for some.
I'm a big fan of analogy and metaphor when explaining difficult concepts, so let me try my hand with a story.
Once upon a time:
There was a princess...
function princess() {
She lived in a wonderful world full of adventures. She met her Prince Charming, rode around her world on a unicorn, battled dragons, encountered talking animals, and many other fantastical things.
var adventures = [];
function princeCharming() { /* ... */ }
var unicorn = { /* ... */ },
dragons = [ /* ... */ ],
squirrel = "Hello!";
/* ... */
But she would always have to return back to her dull world of chores and grown-ups.
return {
And she would often tell them of her latest amazing adventure as a princess.
story: function() {
return adventures[adventures.length - 1];
}
};
}
But all they would see is a little girl...
var littleGirl = princess();
...telling stories about magic and fantasy.
littleGirl.story();
And even though the grown-ups knew of real princesses, they would never believe in the unicorns or dragons because they could never see them. The grown-ups said that they only existed inside the little girl's imagination.
But we know the real truth; that the little girl with the princess inside...
...is really a princess with a little girl inside.
Upvotes: 2615
Reputation: 28666
This answer is a summary of this youtube video Javascript Closures. So full credits to that video.
Closures are nothing but Stateful functions which maintain states of their private variables.
Normally when you make a call to a function as shown in the below figure. The variables are created on a stack ( running RAM memory) used and then disallocated.
But now there are situations where we want to maintain this state of the function thats where Javascript closures comes to use. A closure is a function inside function with a return call as shown in the below code.
So the closure code for the counter function above looks something as shown below.Its a function inside function with a return statement.
function Counter() {
var counter = 0;
var Increment = function () {
counter++;
alert(counter);
}
return {
Increment
}
}
So now if you make a call the counter will increment in other words the function call maintains states.
var x = Counter(); // get the reference of the closure
x.Increment(); // Displays 1
x.Increment(); // Display 2 ( Maintains the private variables)
But now the biggest question whats the use of such stateful function. Stateful functions are building blocks to implement OOP concept like abstraction ,encapsulation and creating self contained modules.
So whatever you want encapsulated you can put it as private and things to be exposed to public should be put in return statement. Also these components are self contained isolated objects so they do not pollute global variables.
A object which follows OOP principles is self contained , follows abstraction , follows encapsulation and so. With out closures in Javascript this is difficult to implement.
Upvotes: 21
Reputation: 104870
Let's start from here, As defined on MDN: Closures are functions that refer to independent (free) variables (variables that are used locally, but defined in an enclosing scope). In other words, these functions 'remember' the environment in which they were created.
Lexical scoping
Consider the following:
function init() {
var name = 'Mozilla'; // name is a local variable created by init
function displayName() { // displayName() is the inner function, a closure
alert(name); // use variable declared in the parent function
}
displayName();
}
init();
init() creates a local variable called name and a function called displayName(). The displayName() function is an inner function that is defined inside init() and is only available within the body of the init() function. The displayName() function has no local variables of its own. However, because inner functions have access to the variables of outer functions, displayName() can access the variable name declared in the parent function, init().
function init() {
var name = "Mozilla"; // name is a local variable created by init
function displayName() { // displayName() is the inner function, a closure
alert (name); // displayName() uses variable declared in the parent function
}
displayName();
}
init();
Run the code and notice that the alert() statement within the displayName() function successfully displays the value of the name variable, which is declared in its parent function. This is an example of lexical scoping, which describes how a parser resolves variable names when functions are nested. The word "lexical" refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available. Nested functions have access to variables declared in their outer scope.
Closure
Now consider the following example:
function makeFunc() {
var name = 'Mozilla';
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
Running this code has exactly the same effect as the previous example of the init() function above: this time, the string "Mozilla" will be displayed in a JavaScript alert box. What's different — and interesting — is that the displayName() inner function is returned from the outer function before being executed.
At first glance, it may seem unintuitive that this code still works. In some programming languages, the local variables within a function exist only for the duration of that function's execution. Once makeFunc() has finished executing, you might expect that the name variable would no longer be accessible. However, because the code still works as expected, this is obviously not the case in JavaScript.
The reason is that functions in JavaScript form closures. A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time that the closure was created. In this case, myFunc is a reference to the instance of the function displayName created when makeFunc is run. The instance of displayName maintains a reference to its lexical environment, within which the variable name exists. For this reason, when myFunc is invoked, the variable name remains available for use and "Mozilla" is passed to alert.
Here's a slightly more interesting example — a makeAdder function:
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
In this example, we have defined a function makeAdder(x), which takes a single argument, x, and returns a new function. The function it returns takes a single argument, y, and returns the sum of x and y.
In essence, makeAdder is a function factory — it creates functions which can add a specific value to their argument. In the above example we use our function factory to create two new functions — one that adds 5 to its argument, and one that adds 10.
add5 and add10 are both closures. They share the same function body definition, but store different lexical environments. In add5's lexical environment, x is 5, while in the lexical environment for add10, x is 10.
Practical closures
Closures are useful because they let you associate some data (the lexical environment) with a function that operates on that data. This has obvious parallels to object oriented programming, where objects allow us to associate some data (the object's properties) with one or more methods.
Consequently, you can use a closure anywhere that you might normally use an object with only a single method.
Situations where you might want to do this are particularly common on the web. Much of the code we write in front-end JavaScript is event-based — we define some behavior, then attach it to an event that is triggered by the user (such as a click or a keypress). Our code is generally attached as a callback: a single function which is executed in response to the event.
For instance, suppose we wish to add some buttons to a page that adjust the text size. One way of doing this is to specify the font-size of the body element in pixels, then set the size of the other elements on the page (such as headers) using the relative em unit:
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 12px;
}
h1 {
font-size: 1.5em;
}
h2 {
font-size: 1.2em;
}
Our interactive text size buttons can change the font-size property of the body element, and the adjustments will be picked up by other elements on the page thanks to the relative units. Here's the JavaScript:
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
size12, size14, and size16 are now functions which will resize the body text to 12, 14, and 16 pixels, respectively. We can attach them to buttons (in this case links) as follows:
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
<a href="#" id="size-12">12</a>
<a href="#" id="size-14">14</a>
<a href="#" id="size-16">16</a>
function makeSizer(size) {
return function() {
document.body.style.fontSize = size + 'px';
};
}
var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);
document.getElementById('size-12').onclick = size12;
document.getElementById('size-14').onclick = size14;
document.getElementById('size-16').onclick = size16;
for reading more about closures, visit the link on MDN
Upvotes: 7
Reputation: 316
A closure is simply when a function have access to its outside scope even after the scope's function has finished executing. Example:
function multiplier(n) {
function multiply(x) {
return n*x;
}
return mutliply;
}
var 10xmultiplier = multiplier(10);
var x = 10xmultiplier(5); // x= 50
we can see that even after multiplier has finished executing, the inner function multiply gets still access to the value of x which is 10 in this example.
A very common use of closures is currying (the same example above) where we spice our function progressively with parameters instead of supplying all of the arguments at once.
We can achieve this because Javascript (in addition to the prototypal OOP) allows as to program in a functional fashion where higher order functions can take other functions as arguments (fisrt class functions). functional programming in wikipedia
I highly recommend you to read this book by Kyle Simpson: 2 one part of the book series is dedicated to closures and it is called scope and closures. you don't know js: free reading on github
Upvotes: 3
Reputation: 1134
My perspective of Closures:
Closures can be compared to a book, with a bookmark, on a bookshelf.
Suppose you have read a book, and you like some page in the book. You put in a bookmark at that page to track it.
Now once you finish reading the book, you do not need the book anymore, except, you want to have access to that page. You could have just cut out the page, but then you would loose the context on the story. So you put the book back in your bookshelf with the bookmark.
This is similar to a closure. The book is the outer function, and the page is your inner function, which gets returned, from the outer function. The bookmark is the reference to your page, and the context of the story is the lexical scope, which you need to retain. The bookshelf is the function stack, which cannot be cleaned up of the old books, till you hold onto the page.
Code Example:
function book() {
var pages = [....]; //array of pages in your book
var bookMarkedPage = 20; //bookmarked page number
function getPage(){
return pages[bookMarkedPage];
}
return getPage;
}
var myBook = book(),
myPage = myBook.getPage();
When you run the book()
function, you are allocating memory in the stack for the function to run in. But since it returns a function, the memory cannot be released, as the inner function has access to the variables from the context outside it, in this case 'pages' and 'bookMarkedPage'.
So effectively calling book()
returns a reference to a closure, i.e not only a function, but a reference to the book and it's context, i.e. a reference to the function getPage, state of pages and bookMarkedPage variables.
Some points to consider:
Point 1: The bookshelf, just like the function stack has limited space, so use it wisely.
Point 2: Think about the fact, whether you need to hold onto the entire book when you just want to track a single page. You can release part of the memory, by not storing all the pages in the book when the closure is returned.
This is my perspective of Closures. Hope it helps, and if anyone thinks that this is not correct, please do let me know, as I am very interested to understand even more about scopes and closures!
Upvotes: 6
Reputation: 5831
Closure are not difficult to understand. It depends only from the point of view.
I personally like to use them in cases of daily life.
function createCar()
{
var rawMaterial = [/* lots of object */];
function transformation(rawMaterials)
{
/* lots of changement here */
return transformedMaterial;
}
var transformedMaterial = transformation(rawMaterial);
function assemblage(transformedMaterial)
{
/*Assemblage of parts*/
return car;
}
return assemblage(transformedMaterial);
}
We only need to go through certain steps in particular cases. As for the transformation of materials is only useful when you have the parts.
Upvotes: 7
Reputation: 14588
Closures allow JavaScript programmers to write better code. Creative, expressive, and concise. We frequently use closures in JavaScript, and, no matter our JavaScript experience, we undoubtedly encounter them time and again. Closures might appear complex but hopefully, after you read this, closures will be much more easily understood and thus more appealing for your everyday JavaScript programming tasks.
You should be familiar with JavaScript variable scope before you read further because to understand closures you must understand JavaScript’s variable scope.
A closure is an inner function that has access to the outer (enclosing) function’s variables—scope chain. The closure has three scope chains: it has access to its own scope (variables defined between its curly brackets), it has access to the outer function’s variables, and it has access to the global variables.
The inner function has access not only to the outer function’s variables, but also to the outer function’s parameters. Note that the inner function cannot call the outer function’s arguments object, however, even though it can call the outer function’s parameters directly.
You create a closure by adding a function inside another function.
A Basic Example of Closures in JavaScript:
function showName (firstName, lastName) {
var nameIntro = "Your name is ";
// this inner function has access to the outer function's variables, including the parameter
function makeFullName () {
return nameIntro + firstName + " " + lastName;
}
return makeFullName ();
}
showName ("Michael", "Jackson"); // Your name is Michael Jackson
Closures are used extensively in Node.js; they are workhorses in Node.js’ asynchronous, non-blocking architecture. Closures are also frequently used in jQuery and just about every piece of JavaScript code you read.
A Classic jQuery Example of Closures:
$(function() {
var selections = [];
$(".niners").click(function() { // this closure has access to the selections variable
selections.push (this.prop("name")); // update the selections variable in the outer function's scope
});
});
1. Closures have access to the outer function’s variable even after the outer function returns:
One of the most important and ticklish features with closures is that the inner function still has access to the outer function’s variables even after the outer function has returned. Yep, you read that correctly. When functions in JavaScript execute, they use the same scope chain that was in effect when they were created. This means that even after the outer function has returned, the inner function still has access to the outer function’s variables. Therefore, you can call the inner function later in your program. This example demonstrates:
function celebrityName (firstName) {
var nameIntro = "This celebrity is ";
// this inner function has access to the outer function's variables, including the parameter
function lastName (theLastName) {
return nameIntro + firstName + " " + theLastName;
}
return lastName;
}
var mjName = celebrityName ("Michael"); // At this juncture, the celebrityName outer function has returned.
// The closure (lastName) is called here after the outer function has returned above
// Yet, the closure still has access to the outer function's variables and parameter
mjName ("Jackson"); // This celebrity is Michael Jackson
2. Closures store references to the outer function’s variables:
They do not store the actual value. Closures get more interesting when the value of the outer function’s variable changes before the closure is called. And this powerful feature can be harnessed in creative ways, such as this private variables example first demonstrated by Douglas Crockford:
function celebrityID () {
var celebrityID = 999;
// We are returning an object with some inner functions
// All the inner functions have access to the outer function's variables
return {
getID: function () {
// This inner function will return the UPDATED celebrityID variable
// It will return the current value of celebrityID, even after the changeTheID function changes it
return celebrityID;
},
setID: function (theNewID) {
// This inner function will change the outer function's variable anytime
celebrityID = theNewID;
}
}
}
var mjID = celebrityID (); // At this juncture, the celebrityID outer function has returned.
mjID.getID(); // 999
mjID.setID(567); // Changes the outer function's variable
mjID.getID(); // 567: It returns the updated celebrityId variable
3. Closures Gone Awry
Because closures have access to the updated values of the outer function’s variables, they can also lead to bugs when the outer function’s variable changes with a for loop. Thus:
// This example is explained in detail below (just after this code box).
function celebrityIDCreator (theCelebrities) {
var i;
var uniqueID = 100;
for (i = 0; i < theCelebrities.length; i++) {
theCelebrities[i]["id"] = function () {
return uniqueID + i;
}
}
return theCelebrities;
}
var actionCelebs = [{name:"Stallone", id:0}, {name:"Cruise", id:0}, {name:"Willis", id:0}];
var createIdForActionCelebs = celebrityIDCreator (actionCelebs);
var stalloneID = createIdForActionCelebs [0];
console.log(stalloneID.id()); // 103
Upvotes: 26
Reputation: 2421
Closures are a somewhat advanced, and often misunderstood feature of the JavaScript language. Simply put, closures are objects that contain a function and a reference to the environment in which the function was created. However, in order to fully understand closures, there are two other features of the JavaScript language that must first be understood―first-class functions and inner functions.
First-Class Functions
In programming languages, functions are considered to be first-class citizens if they can be manipulated like any other data type. For example, first-class functions can be constructed at runtime and assigned to variables. They can also be passed to, and returned by other functions. In addition to meeting the previously mentioned criteria, JavaScript functions also have their own properties and methods. The following example shows some of the capabilities of first-class functions. In the example, two functions are created and assigned to the variables “foo” and “bar”. The function stored in “foo” displays a dialog box, while “bar” simply returns whatever argument is passed to it. The last line of the example does several things. First, the function stored in “bar” is called with “foo” as its argument. “bar” then returns the “foo” function reference. Finally, the returned “foo” reference is called, causing “Hello World!” to be displayed.
var foo = function() {
alert("Hello World!");
};
var bar = function(arg) {
return arg;
};
bar(foo)();
Inner Functions
Inner functions, also referred to as nested functions, are functions that are defined inside of another function (referred to as the outer function). Each time the outer function is called, an instance of the inner function is created. The following example shows how inner functions are used. In this case, add() is the outer function. Inside of add(), the doAdd() inner function is defined and called.
function add(value1, value2) {
function doAdd(operand1, operand2) {
return operand1 + operand2;
}
return doAdd(value1, value2);
}
var foo = add(1, 2);
// foo equals 3
One important characteristic of inner functions is that they have implicit access to the outer function’s scope. This means that the inner function can use the variables, arguments, etc. of the outer function. In the previous example, the “value1” and “value2” arguments of add() were passed to doAdd() as the “operand1” and “operand2” arguments. However, this is unnecessary because doAdd() has direct access to “value1” and “value2”. The previous example has been rewritten below to show how doAdd() can use “value1” and “value2”.
function add(value1, value2) {
function doAdd() {
return value1 + value2;
}
return doAdd();
}
var foo = add(1, 2);
// foo equals 3
Creating Closures
A closure is created when an inner function is made accessible from outside of the function that created it. This typically occurs when an outer function returns an inner function. When this happens, the inner function maintains a reference to the environment in which it was created. This means that it remembers all of the variables (and their values) that were in scope at the time. The following example shows how a closure is created and used.
function add(value1) {
return function doAdd(value2) {
return value1 + value2;
};
}
var increment = add(1);
var foo = increment(2);
// foo equals 3
There are a number of things to note about this example.
The add() function returns its inner function doAdd(). By returning a reference to an inner function, a closure is created. “value1” is a local variable of add(), and a non-local variable of doAdd(). Non-local variables refer to variables that are neither in the local nor the global scope. “value2” is a local variable of doAdd(). When add(1) is called, a closure is created and stored in “increment”. In the closure’s referencing environment, “value1” is bound to the value one. Variables that are bound are also said to be closed over. This is where the name closure comes from. When increment(2) is called, the closure is entered. This means that doAdd() is called, with the “value1” variable holding the value one. The closure can essentially be thought of as creating the following function.
function increment(value2) {
return 1 + value2;
}
When to Use Closures
Closures can be used to accomplish many things. They are very useful for things like configuring callback functions with parameters. This section covers two scenarios where closures can make your life as a developer much simpler.
Working With Timers
Closures are useful when used in conjunction with the setTimeout() and setInterval() functions. To be more specific, closures allow you to pass arguments to the callback functions of setTimeout() and setInterval(). For example, the following code prints the string “some message” once per second by calling showMessage().
<!DOCTYPE html>
<html lang="en">
<head>
<title>Closures</title>
<meta charset="UTF-8" />
<script>
window.addEventListener("load", function() {
window.setInterval(showMessage, 1000, "some message<br />");
});
function showMessage(message) {
document.getElementById("message").innerHTML += message;
}
</script>
</head>
<body>
<span id="message"></span>
</body>
</html>
Unfortunately, Internet Explorer does not support passing callback arguments via setInterval(). Instead of displaying “some message”, Internet Explorer displays “undefined” (since no value is actually passed to showMessage()). To work around this issue, a closure can be created which binds the “message” argument to the desired value. The closure can then be used as the callback function for setInterval(). To illustrate this concept, the JavaScript code from the previous example has been rewritten below to use a closure.
window.addEventListener("load", function() {
var showMessage = getClosure("some message<br />");
window.setInterval(showMessage, 1000);
});
function getClosure(message) {
function showMessage() {
document.getElementById("message").innerHTML += message;
}
return showMessage;
}
Emulating Private Data
Many object-oriented languages support the concept of private member data. However, JavaScript is not a pure object-oriented language and does not support private data. But, it is possible to emulate private data using closures. Recall that a closure contains a reference to the environment in which it was originally created―which is now out of scope. Since the variables in the referencing environment are only accessible from the closure function, they are essentially private data.
The following example shows a constructor for a simple Person class. When each Person is created, it is given a name via the “name” argument. Internally, the Person stores its name in the “_name” variable. Following good object-oriented programming practices, the method getName() is also provided for retrieving the name.
function Person(name) {
this._name = name;
this.getName = function() {
return this._name;
};
}
There is still one major problem with the Person class. Because JavaScript does not support private data, there is nothing stopping somebody else from coming along and changing the name. For example, the following code creates a Person named Colin, and then changes its name to Tom.
var person = new Person("Colin");
person._name = "Tom";
// person.getName() now returns "Tom"
Personally, I wouldn’t like it if just anyone could come along and legally change my name. In order to stop this from happening, a closure can be used to make the “_name” variable private. The Person constructor has been rewritten below using a closure. Note that “_name” is now a local variable of the Person constructor instead of an object property. A closure is formed because the outer function, Person() exposes an inner function by creating the public getName() method.
function Person(name) {
var _name = name;
this.getName = function() {
return _name;
};
}
Now, when getName() is called, it is guaranteed to return the value that was originally passed to the constructor. It is still possible for someone to add a new “_name” property to the object, but the internal workings of the object will not be affected as long as they refer to the variable bound by the closure. The following code shows that the “_name” variable is, indeed, private.
var person = new Person("Colin");
person._name = "Tom";
// person._name is "Tom" but person.getName() returns "Colin"
When Not to Use Closures
It is important to understand how closures work and when to use them. It is equally important to understand when they are not the right tool for the job at hand. Overusing closures can cause scripts to execute slowly and consume unnecessary memory. And because closures are so simple to create, it is possible to misuse them without even knowing it. This section covers several scenarios where closures should be used with caution.
In Loops
Creating closures within loops can have misleading results. An example of this is shown below. In this example, three buttons are created. When “button1” is clicked, an alert should be displayed that says “Clicked button 1”. Similar messages should be shown for “button2” and “button3”. However, when this code is run, all of the buttons show “Clicked button 4”. This is because, by the time one of the buttons is clicked, the loop has finished executing, and the loop variable has reached its final value of four.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Closures</title>
<meta charset="UTF-8" />
<script>
window.addEventListener("load", function() {
for (var i = 1; i < 4; i++) {
var button = document.getElementById("button" + i);
button.addEventListener("click", function() {
alert("Clicked button " + i);
});
}
});
</script>
</head>
<body>
<input type="button" id="button1" value="One" />
<input type="button" id="button2" value="Two" />
<input type="button" id="button3" value="Three" />
</body>
</html>
To solve this problem, the closure must be decoupled from the actual loop variable. This can be done by calling a new function, which in turn creates a new referencing environment. The following example shows how this is done. The loop variable is passed to the getHandler() function. getHandler() then returns a closure that is independent of the original “for” loop.
function getHandler(i) {
return function handler() {
alert("Clicked button " + i);
};
}
window.addEventListener("load", function() {
for (var i = 1; i < 4; i++) {
var button = document.getElementById("button" + i);
button.addEventListener("click", getHandler(i));
}
});
Unnecessary Use in Constructors
Constructor functions are another common source of closure misuse. We’ve seen how closures can be used to emulate private data. However, it is overkill to implement methods as closures if they don’t actually access the private data. The following example revisits the Person class, but this time adds a sayHello() method which doesn’t use the private data.
function Person(name) {
var _name = name;
this.getName = function() {
return _name;
};
this.sayHello = function() {
alert("Hello!");
};
}
Each time a Person is instantiated, time is spent creating the sayHello() method. If many Person objects are created, this becomes a waste of time. A better approach would be to add sayHello() to the Person prototype. By adding to the prototype, all Person objects can share the same method. This saves time in the constructor by not having to create a closure for each instance. The previous example is rewritten below with the extraneous closure moved into the prototype.
function Person(name) {
var _name = name;
this.getName = function() {
return _name;
};
}
Person.prototype.sayHello = function() {
alert("Hello!");
};
Things to Remember
Upvotes: 13
Reputation: 1600
Version picture for this answer: [Resolved]
Just forget about scope every thing and remember: When a variable needed somewhere, javascript will not destroy it. The variable always point to newest value.
Example 1:
Example 2:
Upvotes: 21
Reputation: 2587
I believe in shorter explanations, so see the below image.
function f1()
..> Light Red Box
function f2()
..> Red Small Box
Here we have two functions, f1()
and f2()
. f2() is inner to f1().
f1() has a variable, var x = 10
.
When invoking the function f1()
, f2()
can access the value of var x = 10
.
Here is the code:
function f1() {
var x=10;
function f2() {
console.log(x)
}
return f2
}
f1()
f1()
invoking here:
Upvotes: 43
Reputation: 754
The following simple example covers all the main points of JavaScript closures.*
Here is a factory that produces calculators that can add and multiply:
function make_calculator() {
var n = 0; // this calculator stores a single number n
return {
add: function(a) {
n += a;
return n;
},
multiply: function(a) {
n *= a;
return n;
}
};
}
first_calculator = make_calculator();
second_calculator = make_calculator();
first_calculator.add(3); // returns 3
second_calculator.add(400); // returns 400
first_calculator.multiply(11); // returns 33
second_calculator.multiply(10); // returns 4000
The key point: Each call to make_calculator
creates a new local variable n
, which continues to be usable by that calculator's add
and multiply
functions long after make_calculator
returns.
If you are familiar with stack frames, these calculators seem strange: How can they keep accessing n
after make_calculator
returns? The answer is to imagine that JavaScript doesn't use "stack frames", but instead uses "heap frames", which can persist after the function call that made them returns.
Inner functions like add
and multiply
, which access variables declared in an outer function**, are called closures.
That is pretty much all there is to closures.
* For example, it covers all the points in the "Closures for Dummies" article given in another answer, except example 6, which simply shows that variables can be used before they are declared, a nice fact to know but completely unrelated to closures. It also covers all the points in the accepted answer, except for the points (1) that functions copy their arguments into local variables (the named function arguments), and (2) that copying numbers creates a new number, but copying an object reference gives you another reference to the same object. These are also good to know but again completely unrelated to closures. It is also very similar to the example in this answer but a bit shorter and less abstract. It does not cover the point of this answer or this comment, which is that JavaScript makes it difficult to plug the current value of a loop variable into your inner function: The "plugging in" step can only be done with a helper function that encloses your inner function and is invoked on each loop iteration. (Strictly speaking, the inner function accesses the helper function's copy of the variable, rather than having anything plugged in.) Again, very useful when creating closures, but not part of what a closure is or how it works. There is additional confusion due to closures working differently in functional languages like ML, where variables are bound to values rather than to storage space, providing a constant stream of people who understand closures in a way (namely the "plugging in" way) that is simply incorrect for JavaScript, where variables are always bound to storage space, and never to values.
** Any outer function, if several are nested, or even in the global context, as this answer points out clearly.
Upvotes: 226