w3schools español bootstrap javascript closures

javascript - español - w3schools jquery



¿Dónde vive un cierre de JavaScript? (5)

Cada vez que JavaScript ejecuta la función function3, se crea un objeto ''alcance'' para contener la variable local nombrada por usted como una variable ("foo"). Tenga en cuenta que su código JavaScript no puede acceder directamente a este objeto de alcance. Y así, el valor "foo" está disponible para la función interna, aunque la función externa ha regresado.

¿JavaScript atraviesa algún tipo de cadena de cierre, de manera similar a como atraviesa la cadena de prototipo?

Sí. "Los objetos de alcance forman una cadena llamada cadena de alcance, similar a la cadena de prototipo utilizada por el sistema de objetos de JavaScript.

Un cierre es la combinación de una función y el objeto de ámbito en el que se creó. Los cierres le permiten guardar el estado, como tal, a menudo se pueden usar en lugar de objetos "

Leer más aquí:

Escribí este código para enseñarme sobre los cierres de JavaScript:

function1 = function(){ var variable = "foo" var function2 = function(argument){ console.log(variable + argument); } return function2 } function3 = function1(); function3("bar");

Esto imprime "foobar" como se esperaba. ¿Pero dónde vive la variable?

¿Se convierte en una propiedad de function3, o se almacena en otro lugar en function3? ¿JavaScript atraviesa algún tipo de cadena de cierre, de manera similar a como atraviesa la cadena de prototipo? ¿Está almacenado en la memoria en otro lugar?

Estoy tratando de entender esto más profundamente.


Las variables viven en el ámbito en el que se declaran, que es global o una función.

La palabra clave aquí es alcance .

Como se explica brillantemente en el sitio web de MSDN:

Una variable que se declara dentro de una definición de función es local. Se crea y se destruye cada vez que se ejecuta la función, y no se puede acceder a ella por ningún código fuera de la función. JavaScript no admite el ámbito de bloque (en el que un conjunto de llaves {..} Define un nuevo ámbito), excepto en el caso especial de las variables de ámbito de bloque.

EDITAR :

En realidad es un poco más complicado que esto, vea la toddmotto de toddmotto sobre los alcances de JS.


Para una explicación sobre cómo funcionan los cierres, vea esta respuesta.

¿Cómo funcionan los cierres de JavaScript?

A nivel de máquina virtual, cada función tiene su propio entorno léxico que realiza un seguimiento de esta información. La máquina virtual encuentra las variables a las que se accede en los cierres y las almacena en el montón, y viven durante el tiempo que el cierre las necesite.

Para obtener información más detallada, vea por ejemplo estas dos grandes piezas:



tl; dr:

¿Dónde vive la variable?

En el entorno se definió en.

¿Se convierte en una propiedad de function3, o se almacena en otro lugar en function3?

No.

¿JavaScript atraviesa algún tipo de cadena de cierre, de manera similar a como atraviesa la cadena de prototipo?

Sí.

¿Está almacenado en la memoria en otro lugar?

Sí.

tl; dr 2:

Las funciones mantienen una referencia al entorno en el que se crean. Cuando se llama a una función, se crea un nuevo entorno cuyo entorno principal es el entorno al que la función mantuvo la referencia.

Explicación más larga:

Cada vez que se ejecuta una función , se crea un nuevo entorno léxico . El entorno tiene dos "campos": un registro de entorno en el que se realiza un seguimiento de todas las variables y un entorno léxico externo que se refiere, como el nombre sugiere, al "entorno léxico principal".

Entonces, cuando evaluamos el ejemplo de su código, el estado inicial de la memoria (antes de ejecutar cualquier cosa) podría verse así (simplificado):

+-(Global) lexical environment-+ +-Environment Record-+ +-------------+----------------+ +---------+----------+ | Environment | *--------+---> |function1|undefined | | Record | | +---------+----------+ +-------------+----------------+ |function3|undefined | | Outer | | +---------+----------+ | lexical | (empty) | | environment | | +-------------+----------------+

El entorno global no tiene ningún entorno externo porque está en la parte superior. function1 y function3 son dos enlaces que aún no se han inicializado (la tarea aún no se ha evaluado).

Después de crear la función (evaluando function1 = function() { ... } ), la memoria se ve así:

+------------------------------------------------------------------------+ | | v | +-(Global) lexical environment-+ +-Environment Record-+ +-----Function Object-+---+ +-------------+----------------+ +---------+----------+ +---------------+-----+---+ | Environment | *--------+--->|function1| *-----+---->|[[Environment]]| * | | Record | | +---------+----------+ +---------------+---------+ +-------------+----------------+ |function3|undefined | | name |function1| | Outer | | +---------+----------+ +---------------+---------+ | lexical | (empty) | | environment | | +-------------+----------------+

Ahora function1 tiene un valor, un objeto de función. Los objetos de función tienen múltiples propiedades internas (por ejemplo, [[Environment]] ) y externas (por ejemplo, name ). Como su nombre lo indica, no se puede acceder a las propiedades internas desde el código de usuario. La propiedad [[Environment]] es muy importante. ¡Observe cómo se refiere al entorno léxico en el que se creó la función!

El siguiente paso es ejecutar function3 = function1() , es decir, llamar a function2 . Como dije al principio, cada vez que se ejecuta una función, se crea un nuevo entorno léxico. Echemos un vistazo a la memoria justo después de entrar en la función:

+------------------------------------------------------------------------+ | | v | +-(Global) lexical environment-+ +-Environment Record-+ +-----Function Object-+---+ +-------------+----------------+ +---------+----------+ +---------------+-----+---+ | Environment | *--------+--->|function1| +---->|[[Environment]]| * | | Record | | +---------+----------+ +---------------+---------+ +> +-------------+----------------+ |function3|undefined | | name |function1| | | Outer | | +---------+----------+ +---------------+---------+ | | lexical | (empty) | | | environment | | | +-------------+----------------+ | | | | +-----lexical environment------+ +-Environment Record-+ | +-------------+----------------+ +---------+----------+ | | Environment | *--------+--->|variable |undefined | | | Record | | +---------+----------+ | +-------------+----------------+ |function2|undefined | | | Outer | | +---------+----------+ | | lexical | * | | | environment | | | | +-------------+--------+-------+ | | +-------------------------+

¡Esto se ve muy similar a la estructura del entorno global! Tenemos un entorno léxico que tiene un registro de entorno con dos enlaces sin inicializar. Pero la gran diferencia ahora es que el "entorno léxico externo" apunta al entorno léxico global. ¿Cómo es eso posible?

Al llamar a function1 y crear un nuevo entorno léxico, establecemos el valor del campo "entorno léxico externo" de los nuevos entornos al valor del campo [[Environment]] de function1 . Esto es donde se crea la cadena de alcance .

Ahora, después de ejecutar function1 , la memoria tiene esta estructura:

+------------------------------------------------------------------------+ | | v | +-(Global) lexical environment-+ +-Environment Record-+ +-----Function Object-+---+ +-------------+----------------+ +---------+----------+ +---------------+-----+---+ | Environment | *--------+--->|function1| *-----+---->|[[Environment]]| * | | Record | | +---------+----------+ +---------------+---------+ +> +-------------+----------------+ |function3| | | | name |function1| | | Outer | | +---------+---+------+ +---------------+---------+ | | lexical | (empty) | | | | environment | | | | +-------------+----------------+ +-------------------------+ | | | +----------------------------------------------------------------+--------+ | v | | | +-----lexical environment------+ +-Environment Record-+ v | | +-------------+----------------+ +---------+----------+ | | | Environment | *--------+--->|variable | ''foo'' | +-----Function Object-+---+ | | Record | | +---------+----------+ +---------------+-----+---+ | +-------------+----------------+ |function2| *-----+---->|[[Environment]]| * | | | Outer | | +---------+----------+ +---------------+---------+ | | lexical | * | | name |function2| | | environment | | | +---------------+---------+ | +-------------+--------+-------+ | | +-------------------------+

Similar a function1 , function2 tiene una referencia al entorno creado al llamar function2 . Además, function3 refiere a la función que creamos porque la devolvemos desde function1 .

Último paso: llamando a function3(''bar'') :

+------------------------------------------------------------------------+ | | v | +-(Global) lexical environment-+ +-Environment Record-+ +-----Function Object-+---+ +-------------+----------------+ +---------+----------+ +---------------+-----+---+ | Environment | *--------+--->|function1| *-----+---->|[[Environment]]| * | | Record | | +---------+----------+ +---------------+---------+ +> +-------------+----------------+ |function3| | | | name |function1| | | Outer | | +---------+---+------+ +---------------+---------+ | | lexical | (empty) | | | | environment | | | | +-------------+----------------+ +-------------------------+ | | | +----------------------------------------------------------------+--------+ | v | | | +-----lexical environment------+ +-Environment Record-+ v | | +-------------+----------------+ +---------+----------+ | | | Environment | *--------+--->|variable | ''foo'' | +-----Function Object-+---+ | | Record | | +---------+----------+ +---------------+-----+---+ |+>+-------------+----------------+ |function2| *-----+---->|[[Environment]]| * | || | Outer | | +---------+----------+ +---------------+---------+ || | lexical | * | | name |function2| || | environment | | | +---------------+---------+ || +-------------+--------+-------+ ++------------------------+ | | +-----lexical environment------+ +-Environment Record-+ | +-------------+----------------+ +---------+----------+ | | Environment | *--------+--->|argument | ''bar'' | | | Record | | +---------+----------+ | +-------------+----------------+ | | Outer | | | | lexical | * | | | environment | | | | +-------------+--------+-------+ +------------------------+

De forma similar, aquí se crea un nuevo entorno y su campo "entorno léxico externo" apunta al entorno creado cuando se llamó a function1 .

Ahora, buscar el valor del argument es sencillo, porque existe en el propio registro del entorno. Pero cuando se busca una variable , ocurre lo siguiente: como no existe en el propio registro del entorno, observa el registro de su "entorno léxico externo". Puede hacerlo porque tiene una referencia a ello.