Saltar al contenido
¿Qué son los cierres en JavaScript?

¿Qué son los cierres en JavaScript?

Un cierre JavaScript es una función que recuerda el entorno en el que se creó. Podemos pensar en él como un objeto con un método y variables privadas.

7min read

Los cierres de JavaScript son un tipo especial de objeto que contiene la función y el alcance local de la función con todas las variables (entorno) cuando se creó el cierre.

El cierre de JavaScript es una función que recuerda el entorno en el que se creó

Para entender los cierres, primero tenemos que entender SCOPING en el JavaScript.  Podemos crear una variable o una función en tres niveles de alcance,

  1. Global scope
  2. Función o ámbito local
  3. Ámbito léxico

Scopes in JavaScript

Tan pronto como creamos una variable, está en un ámbito global. Por lo tanto, si hemos creado una variable que no está dentro de ninguna función, está en un ámbito global.

var foo = "foo";
console.log(foo);

Si algo está en un ámbito global, podemos acceder a él desde cualquier lugar, lo que lo convierte en nuestro amigo y enemigo al mismo tiempo. Poner todo en un ámbito global nunca es una buena idea, ya que puede causar conflictos de espacio de nombres, entre otros problemas. Si algo está en un ámbito global, se puede acceder a él desde cualquier lugar y si hay variables con el mismo nombre en una función, esto puede causar conflictos.

Cualquier variable o función que no esté dentro de un ámbito global está dentro de un ámbito funcional o local. Considere la lista a continuación:

function foo() {
  var doo = "doo";
  console.log(doo);
}

foo();

Hemos creado una variable doo que está dentro del alcance de la función foo. El tiempo de vida de la variable doo es local a la función foo y no se puede acceder a él fuera de esa función. Esto se denomina ámbito local en JavaScript.  Consideremos la lista de códigos que se muestra en el diagrama a continuación:

Consideremos la lista de códigos que se muestra en el diagrama

Aquí hemos creado una variable en la función foo con el mismo nombre que una variable del ámbito global, por lo que ahora tenemos dos variables. Debemos tener en cuenta que estas variables son dos variables diferentes con su respectivo tiempo de vida. Fuera de la función, se puede acceder a la variable doo con valor a, sin embargo, dentro de la función foo, existe la variable doo con vale doo. Como referencia, el código anterior se proporciona a continuación:

var doo = "a";
function foo() {
  var doo = "doo";
  console.log(doo); //print doo
}

foo();
console.log(doo); //print a

Let us tweak the above code snippet a bit as shown in listing below:

var doo = "a";
function foo() {
  doo = "doo";
  console.log(doo); //print doo
}

foo();
console.log(doo); //print doo

Ahora no tenemos dos ámbitos para la variable doo. Dentro de la función foo, se modifica la variable doo creada en el ámbito global.  No estamos recreando la variable doo dentro de foo, sino que modificamos la variable doo existente desde el ámbito global.

No estamos recreando la variable doo dentro de foo, sino que modificamos la variable existente doo desde el ámbito global

Al crear la variable en el ámbito local o funcional, debemos usar la palabra clave var para crear la variable.  De lo contrario, la variable se creará en el ámbito global o, si la variable ya existe en el ámbito global, se modificará.

En JavaScript, podemos tener una función dentro de una función. Puede haber funciones anidadas de cualquier nivel, lo que significa que podemos tener cualquier número de funciones anidadas unas dentro de otras.  Considere la lista a continuación:

function foo() {
  var f = "foo";

  function doo() {
    console.log(f);
  }

  doo();
}

foo(); //print foo

Esencialmente, en el fragmento anterior, tenemos una función doo que se crea dentro de la función foo, y no tiene ninguna de sus propias variables. La función foo crea una variable local y se puede acceder a ella dentro de la función doo. La función doo es la función interna de la función foo y puede acceder a las variables de la función foo. Además, la función doo se puede llamar dentro del cuerpo de la función foo. La función doo puede acceder a las variables declaradas en la función principal y esto se debe al alcance léxico de JavaScript.

Aquí hay dos niveles de alcance:

  1. Parent function foo scope
  2. Child function doo scope
Aquí hay dos niveles de alcance

Las variables creadas dentro de la función doo tienen acceso a todo lo creado dentro del alcance de la función foo debido al alcance léxico de JavaScript. Sin embargo, la función foo no puede acceder a las variables de la función doo.

function foo no puede acceder a las variables de function doo

Closures in JavaScript

Comencemos a entender los cierres en JavaScript con un ejemplo. Considere la lista como se muestra a continuación. En lugar de llamar a la función doo dentro del cuerpo de la función foo, estamos devolviendo la función doo de la función foo.

function foo() {
  var f = "foo";
  function doo() {
    console.log(f);
  }
  return doo;
}
var afunct = foo();
afunct();

 

En el listado anterior:

  1. function foo está devolviendo otra función doo
  2. La función DOO no tiene ninguna de sus propias variables
  3. Debido al alcance léxico, la función doo puede acceder a la variable de la función principal foo
  4. se llama a la función foo y se asigna a una variable afunct
  5. luego se llama a afunct como una función e imprime la cadena "foo"
 function foo

Sorprendentemente, la salida del fragmento de código anterior es la cadena "foo". Ahora podríamos confundirnos: ¿cómo se accede a la variable f fuera de la función foo? Normalmente, las variables locales dentro de una función solo existen durante la duración de la ejecución de esa función. Por lo tanto, idealmente después de la ejecución de foo, la variable f ya no debería ser accesible. Pero en JavaScript podemos acceder a él, porque afunct se ha convertido en un cierre de JavaScript. El cierre afunct tiene información sobre la función doo y todas las variables de ámbito local de la función doo en el momento de la creación del cierre posterior.

En caso de cierre, la función interna mantiene las referencias del ámbito de la función externa. Entonces, en los cierres:

  • La función interna mantiene la referencia de su ámbito de función externo. En este caso, la función doo mantiene la referencia del alcance de la función foo.
  • La función doo puede acceder a las variables de la referencia de alcance de la función food en cualquier momento, incluso si la función externa foo terminó de ejecutarse.
  • JavaScript mantiene la referencia de ámbito de la función externa (foo en este caso) y sus variables en la memoria hasta que existe una función interna y hace referencia a ella. En este caso, el alcance y las variables de la función foo se mantendrán en memoria mediante JavaScript, hasta que exista la función doo.

Para entender mejor el cierre, analicemos un ejemplo más:

function add(num1) {
  function addintern(num2) {
    return num1 + num2;
  }

  return addintern;
}

var sum9 = add(7)(2);
console.log(sum9);
var sum99 = add(77)(22);
console.log(sum99);

Aquí tenemos dos cierres, SUM9 y SUM99.

Cuando se creó el cierre sum9, en el ámbito local de la función, el valor de addintern de num1 era 7, y JavaScript recuerda ese valor al crear los cierres de sum9.

Lo mismo en el caso de cierre sum99, en el ámbito local de la función addintern el valor de num1 era 7, y JavaScript recuerda ese valor al crear el cierre sum99.  Como se esperaba, la producción sería de 9 y 99.

Podemos pensar en un cierre como un objeto con variables privadas y un método. Los cierres nos permiten adjuntar datos con la función que trabajan sobre esos datos.  Así, se puede definir un cierre con las siguientes características:

  • It is an object
  • Contiene una función
  • Recuerda los datos asociados con la función, incluidas las variables del ámbito local de la función cuando se creó el cierre
  • Para crear un cierre, la función debe devolver otra referencia de función

Por último, podemos definir un cierre:

"El cierre de JavaScript es un tipo especial de objeto que contiene una función y el entorno en el que se creó la función. Aquí, el entorno representa el alcance local de la función y todas sus variables en el momento de la creación del cierre".

Conclusión

En esta publicación, aprendimos sobre los cierres en JavaScript. Espero que os sea de utilidad. ¡Gracias por leer!

[Actualizado el 22/03/2019]

Solicitar una demostración