Cl

Clausuras en JavaScript

1 ejercicio

Acerca de Clausuras

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.

Razones para usar closures en JavaScript

  1. Privacidad de datos / Encapsulación de datos

    • A diferencia de otros lenguajes, en 2020 no había forma de declarar variables privadas. Por eso los closures se pueden usar para emular de manera efectiva variables privadas (existía una propuesta para introducir la notación de variables privadas, que puede que ya sea estándar cuando leas esto).
    // 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;
    
  2. Aplicación parcial

    • Las funciones pueden devolver funciones, y cuando una función devuelta usa el argumento de la función que la creó, es un ejemplo de uso de un closure para realizar una aplicación parcial. A veces a esto se le llama hacer currying de una función.
    // 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');
    }
    

Ámbito léxico de las variables

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:

  1. Ámbito global: son las variables que se declaran fuera de las funciones y los bloques.
  2. Ámbito de función: son las variables que se declaran dentro de una función con la palabra clave var.
  3. Ámbito de bloque: son las variables que se declaran dentro de un bloque ({...}) 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.

Ámbito de función

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;

Ámbito de bloque

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;
}
Editar en GitHub El enlace se abre en una ventana o pestaña nueva

Aprende Clausuras