style link attribute javascript scoping lexical-scope

javascript - link - title html



¿Qué es el ámbito léxico? (13)

Alcance léxico significa que en un grupo anidado de funciones, las funciones internas tienen acceso a las variables y otros recursos de su alcance principal. Esto significa que las funciones secundarias están vinculadas de forma léxica al contexto de ejecución de sus padres. El alcance léxico también se conoce como alcance estático.

function grandfather() { var name = ''Hammad''; // likes is not accessible here function parent() { // name is accessible here // likes is not accessible here function child() { // Innermost level of the scope chain // name is also accessible here var likes = ''Coding''; } } }

Lo que notará sobre el alcance léxico es que funciona hacia adelante, lo que significa que se puede acceder al nombre por los contextos de ejecución de sus hijos. Pero no funciona al revés para sus padres, lo que significa que no se puede acceder a la variable "me gusta" por sus padres. Esto también nos dice que las variables que tienen el mismo nombre en diferentes contextos de ejecución ganan prioridad de arriba a abajo de la pila de ejecución. Una variable, que tenga un nombre similar a otra variable, en la función más interna (contexto más alto de la pila de ejecución) tendrá mayor prioridad.

Tenga en cuenta que esto se toma de here

¿Podría alguien, por favor, darme una breve introducción al alcance léxico?


Ámbito léxico significa que una función busca variables en el contexto donde se definió, y no en el ámbito que la rodea.

Mira cómo funciona el ámbito léxico en Lisp si quieres más detalles. La respuesta seleccionada por Kyle Cronin en Variables dinámicas y léxicas en Common Lisp es mucho más clara que las respuestas aquí.

Casualmente, solo aprendí sobre esto en una clase de Lisp, y sucede que también se aplica en JS.

Corrí este código en la consola de chrome.

// javascript equivalent Lisp var x = 5; //(setf x 5) console.debug(x); //(print x) function print_x(){ //(defun print-x () console.debug(x); // (print x) } //) (function(){ //(let var x = 10; // ((x 10)) console.debug(x); // (print x) print_x(); // (print-x) })(); //)

salida:

5 10 5


Alcance léxico: las variables declaradas fuera de una función son variables globales y son visibles en todas partes en un programa de JavaScript. Las variables declaradas dentro de una función tienen un alcance de función y son visibles solo para el código que aparece dentro de esa función.


Aquí hay un ángulo diferente en esta pregunta que podemos obtener al dar un paso atrás y observar el papel del alcance en el marco más amplio de la interpretación (ejecutar un programa). En otras palabras, imagine que estaba construyendo un intérprete (o compilador) para un idioma y que era responsable de calcular la salida, dado un programa y algunas aportaciones al mismo.

La interpretación implica mantener un seguimiento de tres cosas:

1) Estado: es decir, variables y ubicaciones de memoria referenciadas en el montón y la pila.

2) Operaciones en ese estado, es decir, cada línea de código en su programa

3) El entorno en el que se ejecuta una operación determinada, es decir, la proyección de estado en una operación.

Un intérprete comienza en la primera línea de código de un programa, calcula su entorno, ejecuta la línea en ese entorno y captura su efecto en el estado del programa. Luego sigue el flujo de control del programa para ejecutar la siguiente línea de código y repite el proceso hasta que el programa termina.

La forma en que calcula el entorno para cualquier operación es a través de un conjunto formal de reglas definidas por el lenguaje de programación. El término "enlace" se usa con frecuencia para describir el mapeo del estado general del programa a un valor en el entorno. Tenga en cuenta que por "estado general" no nos referimos al estado global, sino a la suma total de todas las definiciones alcanzables, en cualquier punto de la ejecución.

Este es el marco en el que se define el problema de alcance. Ahora a la siguiente parte de cuáles son nuestras opciones.

  • Como implementador del intérprete, puede simplificar su tarea haciendo que el entorno sea lo más cercano posible al estado del programa. En consecuencia, el entorno de una línea de código se definiría simplemente por el entorno de la línea de código anterior con los efectos de esa operación aplicada, independientemente de si la línea anterior era una asignación, una llamada de función, el retorno de una función, o una estructura de control como un bucle while.

Esta es la esencia del alcance dinámico , en el que el entorno en el que se ejecuta cualquier código está vinculado al estado del programa definido por su contexto de ejecución.

  • O bien , podría pensar en un programador que use su lenguaje y simplificar su tarea de mantener un registro de los valores que una variable puede tomar. Hay demasiados caminos y demasiada complejidad involucrados en el razonamiento sobre el resultado de la totalidad de la ejecución pasada. El alcance léxico ayuda a hacer esto al restringir el entorno actual a la porción de estado definida en el bloque, función u otra unidad de alcance actual, y su padre (es decir, el bloque que contiene el reloj actual o la función que llamó la función actual).

En otras palabras, con el ámbito léxico, el entorno que ve cualquier código está vinculado al estado asociado con un ámbito definido explícitamente en el idioma, como un bloque o una función.


El alcance define el área, donde las funciones, variables y demás están disponibles. La disponibilidad de una variable, por ejemplo, se define dentro de su contexto, digamos la función, el archivo o el objeto en el que están definidas. Generalmente llamamos a estas variables locales.

La parte léxica significa que puede derivar el alcance de la lectura del código fuente.

El alcance léxico también se conoce como alcance estático.

El alcance dinámico define variables globales que pueden ser llamadas o referenciadas desde cualquier lugar después de ser definidas. A veces, se denominan variables globales, aunque las variables globales en la mayoría de los lenguajes de programación tienen un alcance léxico. Esto significa que puede derivarse de la lectura del código de que la variable está disponible en este contexto. Tal vez uno tiene que seguir una cláusula de usos o de inclusión para encontrar la instalación o definición, pero el código / compilador conoce la variable en este lugar.

En el ámbito dinámico, por el contrario, primero busca en la función local, luego busca en la función que llamó a la función local, luego busca en la función que llamó a esa función, y así sucesivamente, hasta la pila de llamadas. "Dinámico" se refiere al cambio, en el sentido de que la pila de llamadas puede ser diferente cada vez que se llama a una función determinada y, por lo tanto, la función puede afectar a diferentes variables dependiendo de dónde se llame. (ver here )

Para ver un ejemplo interesante de alcance dinámico, vea here .

Para más detalles ver here y here .

Algunos ejemplos en Delphi / Object Pascal

Delphi tiene alcance léxico.

unit Main; uses aUnit; // makes available all variables in interface section of aUnit interface var aGlobal: string; // global in the scope of all units that use Main; type TmyClass = class strict private aPrivateVar: Integer; // only known by objects of this class type // lexical: within class definition, // reserved word private public aPublicVar: double; // known to everyboday that has access to a // object of this class type end; implementation var aLocalGlobal: string; // known to all functions following // the definition in this unit end.

El Delphi más cercano al alcance dinámico es el par de funciones RegisterClass () / GetClass (). Para su uso ver here .

Digamos que no se puede predecir la hora en que se llama a RegisterClass ([TmyClass]) para registrar una determinada clase leyendo el código (se llama en un método de clic de botón llamado por el usuario), el código que llama a GetClass (''TmyClass'') se obtendrá un resultado o no La llamada a RegisterClass () no tiene que estar en el ámbito léxico de la unidad mediante GetClass ();

Otra posibilidad para el alcance dinámico son los métodos anónimos (cierres) en Delphi 2009, ya que conocen las variables de su función de llamada. No sigue recursivamente la ruta de llamada desde allí y, por lo tanto, no es completamente dinámico.


El alcance léxico (AKA estático) se refiere a la determinación del alcance de una variable basándose únicamente en su posición dentro del cuerpo textual del código. Una variable siempre se refiere a su entorno de nivel superior. Es bueno entenderlo en relación al alcance dinámico.


Hay una parte importante de la conversación en torno al alcance léxico y dinámico que falta: una explicación clara de la vida útil de la variable con ámbito, o cuando se puede acceder a la variable.

El alcance dinámico solo se corresponde de manera muy general con el alcance "global" en la forma en que tradicionalmente lo pensamos (la razón por la que mentioned la comparación entre los dos es que ya se ha mentioned , y no me gusta especialmente la explicación del artículo here ) ); Probablemente sea mejor que no hagamos la comparación entre global y dinámico, aunque supuestamente, según el artículo vinculado, "... [es] útil como sustituto de las variables de alcance global".

Entonces, en un lenguaje sencillo, ¿cuál es la distinción importante entre los dos mecanismos de alcance?

El alcance léxico se ha definido muy bien en las respuestas anteriores: las variables con alcance léxico están disponibles, o accesibles, en el nivel local de la función en la que se definió.

Sin embargo, como no es el foco del OP, el alcance dinámico no ha recibido mucha atención y la atención que ha recibido significa que probablemente necesite un poco más (eso no es una crítica de otras respuestas, sino más bien un "oh, Esa respuesta hizo que deseamos que hubiera un poco más "). Entonces, aquí hay un poco más:

El alcance dinámico significa que una variable es accesible para el programa más grande durante la vida útil de la llamada de función, o mientras la función se está ejecutando. Realmente, Wikipedia realmente hace un buen trabajo con la explicación de la diferencia entre los dos. Para no ofuscarlo, aquí está el texto que describe el alcance dinámico:

... [I] n alcance dinámico (o alcance dinámico), si el alcance de un nombre de variable es una función determinada, entonces su alcance es el período de tiempo durante el cual la función se está ejecutando: mientras la función se está ejecutando, existe el nombre de la variable , y está vinculado a su variable, pero después de que la función devuelve, el nombre de la variable no existe.


Los entiendo a través de ejemplos. :)

Primero, Lexical Scope (también llamado Static Scope), en sintaxis similar a C:

void fun() { int x = 5; void fun2() { printf("%d", x); } }

Cada nivel interno puede acceder a sus niveles externos.

Hay otra forma, llamada Dynamic Scope, utilizada por la primera implementación de Lisp, nuevamente en la sintaxis C-like:

void fun() { printf("%d", x); } void dummy1() { int x = 5; fun(); } void dummy2() { int x = 10; fun(); }

Aquí la fun puede acceder a x en dummy1 o dummy2 , o cualquier x en cualquier función que llame a fun con x declarado en ella.

dummy1();

imprimirá 5,

dummy2();

imprimirá 10.

El primero se llama estático porque se puede deducir en tiempo de compilación, el segundo se llama dinámico porque el alcance externo es dinámico y depende de la cadena de llamadas de las funciones.

Encuentro el alcance estático más fácil para el ojo. La mayoría de los idiomas fueron así eventualmente incluso Lisp (puede hacer ambas cosas, ¿verdad?). El alcance dinámico es como pasar referencias de todas las variables a la función llamada.

Un ejemplo de por qué el compilador no puede deducir el alcance dinámico externo de una función, considere nuestro último ejemplo, si escribimos algo como esto:

if(/* some condition */) dummy1(); else dummy2();

La cadena de llamadas depende de una condición de tiempo de ejecución. Si es cierto, entonces la cadena de llamadas se ve así:

dummy1 --> fun()

Si la condición es falsa:

dummy2 --> fun()

El ámbito externo de la fun en ambos casos es la persona que llama más la persona que llama, y ​​así sucesivamente .

Solo por mencionar que el lenguaje C no permite funciones anidadas ni alcance dinámico.


Me encantan las respuestas completas e independientes del idioma de gente como @Arak. Sin embargo, como esta pregunta fue etiquetada como JavaScript , me gustaría agregar algunas notas muy específicas a este idioma.

En javascript nuestras opciones para el alcance son:

  • tal cual (sin ajuste de alcance)
  • var _this = this; function callback(){ console.log(_this); } var _this = this; function callback(){ console.log(_this); }
  • callback.bind(this) enlazado. vincular callback.bind(this)

Vale la pena señalar, creo, que JavaScript realmente no tiene un alcance dinámico . .bind ajusta this palabra clave, y eso está cerca, pero técnicamente no es lo mismo.

Aquí hay un ejemplo que demuestra ambos enfoques. Haces esto cada vez que tomas una decisión sobre el alcance de las devoluciones de llamada, por lo que esto se aplica a promesas, controladores de eventos y más.

Lexical

Aquí está lo que podría Lexical Scoping de las devoluciones de llamada en JavaScript:

var downloadManager = { initialize: function() { var _this = this; // Set up `_this` for lexical access $(''.downloadLink'').on(''click'', function () { _this.startDownload(); }); }, startDownload: function(){ this.thinking = true; // request the file from the server and bind more callbacks for when it returns success or failure } //... };

Unido

Otra forma de alcance es usar Function.prototype.bind :

var downloadManager = { initialize: function() { $(''.downloadLink'').on(''click'', function () { this.startDownload(); }.bind(this)); // create a function object bound to `this` } //...

Estos métodos son, por lo que yo sé, equivalentes en su comportamiento.


Un alcance léxico en Javascript significa que una variable definida fuera de una función puede ser accesible dentro de otra función definida después de la declaración de la variable. Pero lo contrario no es cierto, las variables definidas dentro de una función no serán accesibles fuera de esa función.

Este concepto es muy utilizado en cierres en Javascript.

Digamos que tenemos el siguiente código.

var x = 2; var add = function() { var y = 1; return x + y; };

Ahora, cuando se llama a add () -> esto se imprimirá 3.

Entonces, la función add () está accediendo a la variable global x que se define antes que a la función del método add. Esto se llama debido al alcance léxico en javascript.


Vamos a probar la definición más corta posible:

El alcance léxico define cómo se resuelven los nombres de las variables en funciones anidadas: las funciones internas contienen el alcance de las funciones principales, incluso si la función principal ha regresado .

Eso es todo lo que hay que hacer!


IBM define como:

La parte de un programa o unidad de segmento en la que se aplica una declaración. Un identificador declarado en una rutina se conoce dentro de esa rutina y dentro de todas las rutinas anidadas. Si una rutina anidada declara un elemento con el mismo nombre, el elemento externo no está disponible en la rutina anidada.

Ejemplo 1:

function x() { /* Variable ''a'' is only available to function ''x'' and function ''y''. In other words the area defined by ''x'' is the lexical scope of variable ''a'' */ var a = "I am a"; function y() { console.log( a ) } y(); } // outputs ''I am a'' x();

Ejemplo 2:

function x() { var a = "I am a"; function y() { /* If a nested routine declares an item with the same name, the outer item is not available in the nested routine. */ var a = ''I am inner a''; console.log( a ) } y(); } // outputs ''I am inner a'' x();


var scope = "I am global"; function whatismyscope(){ var scope = "I am just a local"; function func() {return scope;} return func; } whatismyscope()()

El código anterior devolverá "Soy solo un local". No volverá "Soy un global". Debido a que la función func () cuenta donde se definió originalmente, que está bajo el alcance de la función whatismyscope.

No molestará a lo que sea que se llame (incluso el alcance global / desde otra función), por eso no se imprimirá el valor de alcance global Soy global.

Esto se denomina ámbito léxico donde "las funciones se ejecutan utilizando la cadena de alcance que estaba vigente cuando se definieron ", de acuerdo con la Guía de definición de JavaScript.

El alcance léxico es un concepto muy muy poderoso.

Espero que esto ayude..:)