¿Qué es el ámbito léxico?


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

Author: Adrian Heine, 2009-06-26

12 answers

Los entiendo a través de ejemplos. :)

Primero, Ámbito léxico (también llamado Ámbito estático), 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 Ámbito dinámico, utilizada por la primera implementación de Lisp, de nuevo en sintaxis C-like:

void fun()
{
    printf("%d", x);
}

void dummy1()
{
    int x = 5;

    fun();
}

void dummy2()
{
    int x = 10;

    fun();
}

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

dummy1();

Se 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 ámbito externo es dinámico y depende de la llamada en cadena de las funciones.

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

Un ejemplo de por qué el compilador puede no deduzca el ámbito 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 verdad, entonces la cadena de llamadas se ve como:

dummy1 --> fun()

Si la condición es falsa:

dummy2 --> fun()

El ámbito externo de fun en ambos casos es el llamante más el llamante del llamante y así sucesivamente.

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

 566
Author: AraK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-29 10:30:38

Probemos la definición más corta posible:

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

Eso es todo lo que hay! Para ayudarme a entender lo que esto significa, escribí una entrada de blog en profundidad sobre ámbito de la función y el ámbito léxicoen JavaScript que se puede encontrar aquí. Tal vez esto podría servir a alguien si no también.

 207
Author: Pierre Spring,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-08 12:17:32

Ámbito define el área, donde las funciones, variables y tales están disponibles. La disponibilidad de una variable, por ejemplo, se define dentro de su contexto, digamos la función, archivo u objeto, se definen en. Usualmente llamamos a estas variables locales.

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

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

El ámbito dinámico define las variables globales que se pueden llamar o referenciar desde cualquier lugar después de haber sido definido. A veces se les llama variables globales, a pesar de que las variables globales en la mayoría de los lenguajes de programación son de alcance léxico. Esto significa, que se puede derivar de la lectura del código que la variable está disponible en este contexto. Tal vez uno tiene que seguir una cláusula uses o includes para encontrar la instatiación o definición, pero el código/compilador sabe acerca de la variable en este lugar.

En el ámbito dinámico, por el contrario, primero busca en la función local, luego se busca en la función que llamó a la función local, luego se 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 que la pila de llamadas puede ser diferente cada vez que se llama a una función dada, por lo que la función puede golpear diferentes variables dependiendo de dónde se llama. (ver aquí)

Para ver un ejemplo interesante para el ámbito dinámico ver aquí.

Para más detalles, véase aquí y aquí.

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 par de funciones registerClass()/getClass() más cercano a Delphi es el ámbito dinámico. Para su uso véase aquí.

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

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

 34
Author: Ralph M. Rickenbach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:26

El ámbito léxico (TAMBIÉN conocido como estático) se refiere a determinar el ámbito de una variable basándose únicamente en su posición dentro del corpus textual del código. Una variable siempre se refiere a su entorno de nivel superior. Es bueno entenderlo en relación con el ámbito dinámico.

 33
Author: Evan Meagher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-06-26 05:14:41
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 devolverá "Yo soy un global". Porque la función func () cuenta donde se definió originalmente que está bajo el alcance de la función whatismyscope.

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

Esto se llama ámbito léxico donde " las funciones se ejecutan usando la cadena de ámbito eso estaba en efecto cuando se definieron" - de acuerdo con la Guía de definición de JavaScript.

El ámbito léxico es un concepto muy muy poderoso.

Espero que esto ayude..:)

 32
Author: kta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-14 05:24:38

Me encantan las respuestas completamente completas e independientes del lenguaje de personas como @Arak. Dado que esta pregunta fue etiquetada JavaScript sin embargo, me gustaría introducir algunas notas muy específicas para este lenguaje.

En javascript nuestras opciones para el alcance son:

  • tal cual (sin ajuste del alcance)
  • léxico var _this = this; function callback(){ console.log(_this); }
  • encuadernado callback.bind(this)

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

Aquí hay un ejemplo que demuestra ambos enfoques. Usted hace esto cada vez que toma una decisión acerca de cómo alcance callbacks por lo que esto se aplica a las promesas, controladores de eventos, y más.

Léxico

Esto es lo que podría denominar 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
  }
  //...
};

Encuadernado

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 sé, comportamiento equivalente.

 29
Author: SimplGy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-16 22:12:01

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

 9
Author: Stan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-23 10:51:38

IBM lo define como:

La porción de un programa o unidad de segmento en la que una declaración aplicar. Un identificador declarado en una rutina se conoce dentro de ese rutina y dentro de todas las rutinas anidadas. Si una rutina anidada declara un artículo con el mismo nombre, el artículo externo no está disponible en el 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();
 9
Author: Robert Rocha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-03 18:54:39

Hay una parte importante de la conversación que rodea el Ámbito Léxico y Dinámico que falta: una explicación simple de la vida de la variable de ámbito - o cuando se puede acceder a la variable.

El alcance dinámico solo corresponde muy vagamente al alcance" global " en la forma en que tradicionalmente lo pensamos (la razón por la que menciono la comparación entre los dos es que ya se ha mencionado - y no me gusta particularmente el linked article's explanation); es probablemente mejor no hacer la comparación entre global y dynamic - aunque supuestamente, según el artículo enlazado, "...[it] is useful as a substitute for globally scope variables."

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

El ámbito léxico se ha definido muy bien a lo largo de las respuestas anteriores: las variables de ámbito léxico están disponibles-o, accesibles - en el nivel de la función en la que se definió.

Sin embargo, como no es el foco del OP, el análisis dinámico no ha recibido mucha atención y la atención que ha recibido significa que probablemente necesita un poco más (eso no es una crítica de otras respuestas, sino más bien un "oh, esa respuesta nos hizo desear que hubiera un poco más"). Por lo tanto, 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 a la 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 ámbito dinámico (o ámbito dinámico), si el ámbito de un nombre de variable es un cierta función, entonces su alcance es el período de tiempo durante el cual el función se está ejecutando: mientras la función se está ejecutando, la variable nombre existe, y está ligado a su variable, pero después de la función devuelve el nombre de la variable no existe.

 4
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59

Ámbito léxico significa que una función busca variables en el contexto donde fue definida, y no en el ámbito inmediatamente alrededor de ella.

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 Lisp, y sucede que también se aplica en JS.

Corrí este código en 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 
 2
Author: ratiotile,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:37

Un ámbito 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 llamas a add () this> esto imprimirá 3.

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

 2
Author: Praveen Kishor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-04 03:29:09

Aquí hay un ángulo diferente sobre esta pregunta que podemos obtener dando un paso atrás y mirando 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 lenguaje y era responsable de calcular la salida, dado un programa y algo de entrada a él.

La interpretación implica mantener un registro 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 dada, 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. A continuación, sigue el flujo de control del programa para ejecutar la siguiente línea de código, y repite el procese hasta que termine el programa.

La forma de calcular 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 utiliza con frecuencia para describir la asignación del estado general del programa a un valor en el entorno. Tenga en cuenta que por "estado general" no queremos decir estado global, sino más bien la suma total de cada definición alcanzable, en cualquier momento de la ejecución)

Este es el marco en el que el ámbito el problema está definido. Ahora a la siguiente parte de cuáles son nuestras opciones.

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

Esta es la esencia de dynamic scoping, 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, se podría pensar en un programador usando su lenguaje y simplificar su tarea de realizar un seguimiento de los valores que una variable puede tomar. Hay demasiados caminos y demasiada complejidad involucrados en el razonamiento sobre el resultado la totalidad de la ejecución pasada. El ámbito léxicoayuda a hacer esto restringiendo el entorno actual a la porción de estado definida en el bloque actual, función u otra unidad de ámbito, y su padre (es decir, el bloque que encierra el reloj actual, o la función que llamó a la función presente).

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

 0
Author: er0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-25 18:46:47