A closure is when a function is able to remember and access a lexical scope, even when that function is executed outside of that lexical scope.
Simple, right? Well, maybe not so much, but let’s go step by step and understand this.
Before diving deeper into the concept, you should check out:
Closures are widely used in JavaScript — you just need to know how to recognize them in code and understand the functionality implications they have.
Closures are available because the language implements lambdas and higher-order functions, and they’re a direct consequence of writing code using lexical scopes.
Let’s see this in code:
// Pruebalo: https://jsbin.com/dajocobugu/edit?js,console
function say() {
var name = 'yeison';
function sayName() {
console.log(name);
}
// se retrona la definición de la función sayName
return sayName;
}
// se asigna la ejecución de say a sayYeison
var sayYeison = say();
sayYeison();
We have a function that has an internal variable, which uses the variable name and returns the definition of the function sayName.
If we call a function without parentheses, we’re passing the function object itself.
If we call a function with parentheses, we pass the result of its execution. Higher-order functions in JavaScript
But when executing the function say — when it’s assigned to the variable sayYeison — shouldn’t its internal variable be cleaned up by the Garbage Collector since it’s no longer in use?
That’s not what happens, because when the function executes, it returns the definition of the inner function which holds a reference to that scope. That’s why the variable won’t disappear.
The inner scope is still in use, used by the function that is returned
The key thing to understand about closures is that we have a context and a function that uses it, allowing us to access the scope of that context.
Let’s look at another example.
// Pruebalo: https://jsbin.com/zebevucamo/edit?js,console
function makeCounter(counter, step) {
function next() {
return counter += step;
}
return next;
}
var counter2 = makeCounter(10,2);
counter2(); // sumamos dos, 12
console.log(counter2()); // sumamos dos, 14
var counter10 = makeCounter(50, 10);
counter10(); // sumamos 10, 60
console.log(counter10()); // sumamos 10, 70
By using closures, we can create functions with different contexts. This leads us to a very powerful pattern that we’ll explore in the next post.
Finally, let’s look at a practical application of closures, taken from JavaScript: The Good Parts (page 60).
We’re going to create a function to calculate the Fibonacci number.
// pruebalo: https://jsbin.com/laqikax/1/edit?js,console
var contador = 0;
var fibonacci = function (n) {
// Contador para ver cuantas veces se ejecuta la función
contador++;
// recibimos un numero, si es menor de dos retornamos el numero,
// si no realizamos dos llamadas recursivas a la función
return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};
// Loop donde vamos pasando numero de uno en uno a la funcion fibonacci y mostrando el resultado
for (var i = 0; i <= 10; i += 1) {
console.log(i + ': ' + fibonacci(i));
}
console.log(contador); //453
As you can see, the function fibonacci was called 453 times. With larger numbers, that count will grow exponentially. Let’s try to improve this by applying closures.
// Pruebalo: https://jsbin.com/bucuha/edit?js,console
var contador = 0;
var fibonacci = function () {
var memo = [0, 1]; // array, para almacenar resultados
var fib = function (n) {
contador++; // contador para medir veces de ejecución
var result = memo[n]; // se almacena la posición del array
if (typeof result !== 'number') {//Se comprueba si el resultado ya existe
result = fib(n - 1) + fib(n - 2); // se hace una llamada recursiva
memo[n] = result; // y se almacena el resultado
}
return result; // se retorna el resultado
};
return fib; // se retorna la definición de la función fib
}(); // se auto ejecuta la función para cuando se llame, se utilice la definición de la función fib
for (var i = 0; i <= 10; i += 1) {
console.log(i + ': ' + fibonacci(i));
}
console.log(contador); //29
By using a closure that lets us store results in an array, the number of times the function is invoked is now just 29.
You can find more references on this topic at: