Los closures son un patrón de programación en JavaScript que permite usar variables de un ámbito léxico externo dentro de un bloque de código anidado. JavaScript admite los closures de forma transparente, y muchas veces 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 ámbito de las variables. En JavaScript, hay 3 tipos de ámbito léxico para las variables:
var.{...}) con las palabras clave let y const.En la práctica, un closure suele aparecer cuando una función (o un bloque) usa una variable de un ámbito externo. En JavaScript, esto se admite de forma transparente, por lo que muchas veces se usan closures sin mencionarlo explícitamente.
La palabra clave var define una variable con ámbito de función. Esto significa que las variables definidas con var están disponibles en cualquier parte de la función donde se definen y en cualquier ámbito 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 ámbito de bloque. let define una variable mutable, cuyo valor se puede asignar varias veces y que puede declararse pero no inicializarse. const define una variable que debe inicializarse cuando se declara, y su valor no puede cambiar después. Si la variable const se asigna a un valor primitivo, no se puede mutar. 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í se puede mutar.
Considera 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 común es encontrarlas alrededor de 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;
}