PDF de programación - you dont know js - 02 scope and closures

Imágen de pdf you dont know js - 02 scope and closures

you dont know js - 02 scope and closuresgráfica de visualizaciones

Publicado el 4 de Octubre del 2018
311 visualizaciones desde el 4 de Octubre del 2018
191,0 KB
38 paginas
Creado hace 1a (27/04/2018)
YOU DON'T KNOW JS - 02: Scope & Closures

Scope (alcance, ámbito) & Closures (cierres)

1. Que es un cierre?

Uno de los paradigmas más fundamentales de casi todos los lenguajes de programación es la capacidad de almacenar
valores en variables, y luego recuperarlos o modificarlos. De hecho, la capacidad de almacenar valores y extraer valores de
las variables es lo que da un estado de programa.

Sin tal concepto, un programa podría realizar algunas tareas, pero serían extremadamente limitadas y no terriblemente
interesantes.

Pero la inclusión de variables en nuestro programa engendra las preguntas más interesantes que vamos a abordar ahora:
¿dónde viven esas variables? En otras palabras, ¿dónde se almacenan? Y, lo más importante, ¿cómo los encuentra nuestro
programa cuando lo necesita?

Estas preguntas se refieren a la necesidad de un conjunto bien definido de reglas para almacenar las variables en algún
lugar y para encontrarlas más adelante. Llamaremos a ese conjunto de reglas: Alcance o ámbito.

Pero, ¿dónde y cómo se establecen estas reglas del alcance?

Teoría del Compilador

Puede ser evidente por sí mismo, o puede ser sorprendente, dependiendo de su nivel de interacción con varios
lenguajes, pero a pesar de que JavaScript cae dentro de la categoría general de lenguajes "dinámicos" o "interpretados", es
de hecho un lenguaje compilado. No se compila con suficiente antelación, al igual que muchos lenguajes compilados
tradicionalmente, ni tampoco son los resultados de la compilación portátiles entre varios sistemas distribuidos.

Pero, sin embargo, el motor JavaScript realiza muchos de los mismos pasos, aunque en formas más sofisticadas de las
que comúnmente conocemos, de cualquier compilador de lenguaje tradicional.

En el proceso tradicional de lenguaje compilado, un trozo de código fuente, su programa, se somete a tres pasos
típicamente antes de que se ejecute, más o menos llamado "compilación":

1. Tokenizing/Lexing: fragmentar una cadena de caracteres en trozos significativos (al lenguaje) llamados

tokens(fichas). Por ejemplo, considere el programa: var a = 2;. Este programa probablemente se dividiría en los
siguientes tokens: var, a, =, 2 y ;. El espacio en blanco puede o no persistir como un símbolo, dependiendo de si es
significativo o no.

Nota: La diferencia entre el tokenizing y el lexing es sutil y académica, pero se centra en si estos token se identifican o no
de una manera sin estado o con estado. En pocas palabras, si el token invocara reglas de análisis de estado para
determinar si a debe ser considerado un token distinto o sólo una parte de otro token, eso sería lexing.

2. Análisis sintáctico: coge un flujo (matriz) de tokens y lo convierte en un árbol de elementos anidados, que

representan colectivamente la estructura gramatical del programa. Este árbol se llama "AST" (Abstract Syntax Tree
o Arbol abstracto sintáctico ).

El árbol para var a = 2; puede comenzar con un nodo de nivel superior llamado VariableDeclaration, con un nodo hijo
llamado Identifier (cuyo valor es a) y otro hijo llamado AssignementExpresión que tiene un hijo llamado NumericLiteral
(cuyo valor es 2).

3. Generación de código: el proceso de tomar un AST y convertirlo en código ejecutable, esta parte varía

enormemente dependiendo del idioma, la plataforma a la que se dirija, etc.

Por lo tanto, en lugar de entrar en detalles, simplemente nos limitaremos a decir que hay una manera de tomar nuestro
AST descrito anteriormente para var a = 2; y convertirlo en un conjunto de instrucciones de máquina para crear una
variable llamada realmente a (incluyendo la reserva de memoria, etc.), y luego almacenar un valor en un a.

Nota: Los detalles de cómo el motor maneja los recursos del sistema son más profundos de lo que vamos a indagar, así
que daremos por sentado que el motor es capaz de crear y almacenar variables según sea necesario.

El motor JavaScript es mucho más complejo que esos tres pasos, como la mayoría de los compiladores de lenguajes. Por
ejemplo, en el proceso de análisis sintáctico y generación de código, existen ciertamente pasos para optimizar el
rendimiento de la ejecución, incluyendo el colapso de elementos redundantes, etc.

Así que, estoy describiendo aquí sólo a grandes rasgos. Pero creo que pronto verán por qué estos detalles que cubrimos,
incluso a un alto nivel, son relevantes.

Por un lado, los motores JavaScript no se dan el lujo (como otros compiladores de lenguaje) de tener mucho tiempo para
optimizar, porque la compilación de JavaScript no ocurre en una compilación que se construye paso a paso, como ocurre
con otros lenguajes.

Para JavaScript, la compilación que se produce ocurre, en muchos casos, en microsegundos (o menos!) antes de ejecutar
el código. Para asegurar el rendimiento más rápido, los motores JS utilizan todo tipo de trucos (como JITs, que compilan
"perezosos" e incluso hot re-compile, etc.) que están mucho más allá del "alcance" de nuestra discusión aquí.

Digamos, por simplicidad, que cualquier fragmento de JavaScript tiene que ser compilado antes (normalmente justo
antes) de que se ejecute. Por lo tanto, el compilador JS tomará el programa var a = 2; y lo compilará primero, y luego
estará listo para ejecutarlo, normalmente de inmediato.

Comprender el alcance

La forma en que abordaremos el aprendizaje sobre el alcance es pensar en el proceso en términos de reconversación.
Pero, ¿quién está teniendo la conversación?

El Reparto

Conozcamos al elenco de personajes que interactúan para procesar el programa var a = 2; por lo que entendemos sus
conversaciones que escucharemos en breve:

1. Motor: responsable de la compilación y ejecución de nuestro JavaScript de principio a fin. programa.
2. Compilador: uno de los amigos de Engine; maneja todo el trabajo sucio de analizar y generación de código (ver

sección anterior).

3. Alcance: otro amigo de Engine; recopila y mantiene una lista de búsqueda de todos los identificadores (variables)

declarados, y hace cumplir un conjunto estricto de reglas sobre cómo son accesibles en los códigos actualmente en
ejecución.

Para que entiendas completamente cómo funciona JavaScript, necesitas empezar a pensar como el Engine (y sus
amigos) piensan, hacer las preguntas que ellos hacen, y contestar esas mismas preguntas.

Atrás & Alante

Cuando veas el programa var a = 2; lo más probable es que pienses en eso como una frase. Pero así no es como lo ve
nuestro nuevo amigo Motor. De hecho, el Motor ve dos frases distintas, una que maneja el Compilador durante la
compilación, y otra que maneja el Motor durante la ejecución.

Por lo tanto, vamos a desglosar cómo el Motor y amigos se acercarán al programa var a = 2;.

La primera cosa que el compilador hará con este programa es realizar lexing para dividirlo en tokens, que luego se
traducirá en un árbol. Pero cuando el compilador llega a la generación de código, tratará este programa de una manera
algo diferente a lo que quizás se supone.

Una suposición razonable sería que el Compilador producirá código que podría resumirse en este pseudo-código:
"Asignar memoria para una variable, nombrarla a, luego fija el valor 2 en esa variable." Desafortunadamente, eso no es del
todo exacto.

El compilador procederá como:

1. Buscar var a, el Compilador le pide la alcance que vea si una variable ya existe para esa colección de alcances en

particular. Si es así, el Compilador ignora esta declaración y sigue adelante. De lo contrario, el Compilador pide al
alcance que declare una nueva variable llamada a para esa colección de alcances.

2. El compilador luego produce código para que el Motor lo ejecute más tarde, para manejar la asignación a = 2. El

Motor de código ejecutará primero la preguntará al alcance de si hay una variable llamada a "accesible" en la
colección de alcance actual. Si es así, el Motor usa esa variable. Si no, el Motor busca en otra parte (ver la sección de
alcance anidado más abajo).

Si el Motor eventualmente encuentra una variable, le asigna el valor 2. Si no, el motor lanzarár un error!

Resumiendo: se toman dos acciones distintas para una asignación de variable: Primero, el Compilador declara una
variable (si no se ha declarado previamente en el ámbito actual), y segundo, en la ejecución, el Motor busca la variable en
el alcance y la asigna a él, si se encuentra.

El Compilador Habla

Necesitamos un poco más de terminología del compilador para continuar con la comprensión.

Cuando el Motor ejecuta el código que el Compilador produjo para el paso (2), tiene que buscar la variable a para ver si ha
sido declarada, y esta consulta está consultando al Alcance. Pero el tipo de búsqueda que realiza el Motor afecta al
resultado de la búsqueda.

En nuestro caso, se dice que el Motor estaría realizando una búsqueda "LHS" para la variable a. El otro tipo de búsqueda
se llama "RHS".

Apuesto a que puedes adivinar lo que significan la "L" y la "R". Estos términos significan "lado izquierdo" y "lado
derecho".

¿Lado... de qué? de una operación de asignación.

En otras palabras, una búsqueda LHS se realiza cuando una variable aparece en el lado izquierdo de una operación de
asignación y una búsqueda RHS se realiza cuando una variable aparece en el lado derecho de una operación de
asignación.

En realidad, seamos un poco más precisos. Una búsqueda RHS es indistinguible, a nuestros efectos, de una simple
búsqueda del valor de alguna variable, mientras que la búsqueda LHS está intentando encontrar el contenedor de
variables en sí mismo, para que pueda asignar. De esta manera, RHS no significa realmente "lado derecho de una
asignación" per se, sino que, más exactamente, significa "no lado izquierdo".

Simplificando poco por un momento, también podrías pensar que "RHS" en lugar de eso significa "recuperar su fuente
(valor)", implicando que RHS significa "ir a obtener el valor de...".

Analizemos esto más detenidamente.

Cuando yo diga:

console.log( a );

La referencia a un es una referencia RHS, porque n
  • Links de descarga
http://lwp-l.com/pdf13730

Comentarios de: you dont know js - 02 scope and closures (0)


No hay comentarios
 

Comentar...

Nombre
Correo (no se visualiza en la web)
Valoración
Comentarios
Es necesario revisar y aceptar las políticas de privacidad