Closures are typically implemented with a special data structure that contains a pointer to the function code, plus a representation of the function's lexical environment (i.e., the set of available variables) at the time when the closure was created.
In simple terms, Closure is under functional programming, and it allows an inner function to access an outer function's scope, even when the outer function has already returned. In the above example, the items variable is accessible to all the inner functions, but it's not directly accessible from outside.
Advantages of closures Variables in closures can help you maintain a state that you can use later. They provide data encapsulation. They help remove redundant code. They help maintain modular code.
A closure is simply a more convenient way to give a function access to local state. Rather than having to create a class which knows about the local variable you want the function to use, you can simply define the function on the spot, and it can implicitly access every variable that is currently visible.
A closure is a pairing of:
A lexical environment is part of every execution context (stack frame) and is a map between identifiers (ie. 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 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 modularise 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 = function() { console.log(x) }
x = x+1
return inner
}
var f = foo()
f() // 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.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.
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.
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.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)
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With