A closure is when a function can access its scope even if the function is executed outside of it.
examples of closures
The JavaScript timer function could be used as an example of closure.
JavaScript
function addSnackbar (text) {
// createSnackbar() show a Snackbar on the screen
const Snackbar = createSnackbar(text);
setTimeout(function () {
Snackbar.remove();
console.log(`Snackbar '${ text }' was removed`);
}, 1000);
}
addSnackbar('a new todo was added');
// Snackbar 'a new todo was added' was removed
Once addSnackbar() is executed and a second later passes it will still remember the variables text and Snackbar because of closures.
Another exampe of a closure could be the addEventListener() method because it takes in a function that can be executed later.
JavaScript
function addEventListenerToButton () {
const addedAt = new Date();
document.querySelector('.button')
.addEventListener('click', function () {
console.log(addedAt);
});
}
addEventListenerToButton();
// the date the event listener was added at when the button is clicked
This is a closure because you never know when the button is going to be clicked and it will always print in the console the addedAt date.
Another example of a closure is wrapping a setTimeout()
method in an IIFE
inside a for loop.
JavaScript
for (var i = 1; i <= 5; i++) {
(function (currentI) {
setTimeout(function () {
// currentI can still be access even though it is executed later
console.log("i: " + currentI);
// i: 1, i: 2, i: 3, i: 4, i: 5
}, currentI * 1000);
})(i);
}
This is a closure because currentI is stored in the scope of the IIFE
and currentI is referenced inside the setTimeout()
call.
If you don’t understand what IIFEs
are there is an explanation later on.
Another example of closure is returning a inner function from an outer function while the inner function references a variable from the outer function.
JavaScript
function add (x) {
return function (y) {
return x + y;
}
}
In the add()function the x parameter is passed in and it is use within a new function that is being returned.
In the returned function no where in it x is defined.
Variables are remembered if they are reference even after the function is returned.
JavaScript
function add (x) {
return function (y) {
return x + y;
}
}
const add10 = add(10);
// returns a function with x set to 10
console.log(add10(5));
// 15
console.log(add10(20));
// 30
When the add() function is executed with 10 passed in it will set x to 10 and return a function that takes in a y parameter that returns x + y.
Now we can add 10 to any number by calling add10 with any number passed in.
x is remembered because of closures.
note: also known as IIFE
- a function expression that get invoked immediately
- doesn’t add to or modify the global object
This is how a IIFE
looks like
JavaScript
(function () {
// these variable will not exist
// after console.log is executed
let number = 42;
const fruit = 'oranges';
console.log('hi');
})();
// console log hi
Why use IIFE
- global scope doesn’t get polluted
- when you want to utilize a closure
conclusion
A closure is a function that can use variables declared around it even when it is executed outside the scope it was created in.