Los closures son un patrón de programación en JavaScript que permite usar variables de un scope léxico externo dentro de un bloque de código anidado. JavaScript admite los closures de forma transparente y a menudo se usan sin saber qué son.
// Top-level declarations are global-scope
const dozen = 12;
// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
return dozen * n;
}
El nombre closure deriva históricamente del cálculo λ y fue popularizado por Scheme (fuente) para referirse a las vinculaciones abiertas y cerradas de variables de una función.
Privacidad de datos / Encapsulación de datos
// Consider this function:
const saveNumber = (number) => {
// The saved value is unaccessible by the outer lexical scope.
const value = number;
// We can provide access to the primitive value with a function, but the original will never change
return () => value;
};
// Attempting to set the variable outside of its lexical scope results in an error
value = 42;
Aplicación parcial
// The arguments are applied one-by-one, using closures to arrive at the final result
function partialBuildUri(scheme) {
return function (domain) {
return function (path) {
return `${scheme}://${domain}/${path}`;
};
};
}
// A function could apply them all at once.
function buildUri(scheme, domain, path) {
return partialBuildUri(scheme)(domain)(path);
}
// Or apply a few to create a flexible system of functions for reuse.
function buildHttpsExercismUri(path) {
return partialBuildUri('https')('exercism.org');
}
En cualquier lenguaje de programación, los closures están estrechamente relacionados con el scope de las variables. En JavaScript hay tres tipos de scope léxico para las variables:
var.{...}) con las palabras clave let y const.En la práctica, un closure suele producirse cuando una función (o un bloque) usa una variable de un scope externo. En JavaScript, esto se admite de forma transparente, por lo que a menudo se usan closures sin mencionarlos de forma explícita.
La palabra clave var define una variable con scope de función. Esto significa que las variables definidas con var están disponibles en cualquier parte de la función en la que se definen y en cualquier scope léxico anidado (ya sea de función o de bloque).
{
var five = 5;
}
// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;
Las palabras clave let y const definen variables con scope de bloque. let define una variable mutable, cuyo valor puede asignarse varias veces y puede definirse sin inicializarse. const define una variable que debe inicializarse en el momento de definirla, y su valor no puede cambiar después. Si la variable const se asigna a un valor primitivo, no puede mutarse. Si la variable const se asigna a un valor de referencia, como un array o un objeto, la referencia no puede cambiar, pero el contenido del array sí puede mutarse.
Fíjate en este bloque:
// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;
{
// This succeeds, as 'two' is available from the outer lexical scope
const oneLess = two - 1;
}
// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);
Aunque podemos usar llaves ({...}) de forma arbitraria para crear bloques, lo más habitual es encontrarlas rodeando condicionales, funciones y clases.
const PI = 3.14;
// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
return PI * radius * radius;
}