freeCodeCamp/guide/spanish/javascript/scopes/index.md

7.7 KiB

title localeTitle
Scopes Alcances

Si ha estado programando en JavaScript por un tiempo, indudablemente se ha encontrado con un concepto conocido como scope . ¿Qué es el scope ? ¿Por qué deberías tomarte el tiempo para aprenderlo?

En lenguaje de programador, el scope es el contexto actual de ejecución . ¿Confuso? Echemos un vistazo a la siguiente pieza de código:

var foo = 'Hi, I am foo!'; 
 
 var baz = function () { 
  var bar = 'Hi, I am bar too!'; 
    console.log(foo); 
 } 
 
 baz(); // Hi, I am foo! 
 console.log(bar); // ReferenceError... 

Este es un ejemplo simple, pero hace un buen trabajo de ilustrar lo que se conoce como alcance léxico . JavaScript, y casi cualquier otro lenguaje de programación tiene un alcance léxico . Existe otro tipo de alcance conocido como Ámbito dinámico , pero no lo discutiremos.

Ahora, el término ámbito léxico suena sofisticado, pero como verás, en principio es muy simple. En un ámbito léxico, hay dos tipos de ámbitos: el ámbito global y el ámbito local .

Antes de escribir la primera línea de código en su programa, se crea un ámbito global para usted. Esto contiene todas las variables que declara en su programa fuera de cualquier función .

En el ejemplo anterior, la variable foo está en el alcance global del programa, mientras que la bar variables se declara dentro de una función y, por lo tanto, está en el alcance local de esa función .

Vamos a desglosar el ejemplo línea por línea. Si bien podría estar confundido en este momento, le prometo que tendrá una comprensión mucho mejor cuando termine de leer esto.

En la línea 1 estamos declarando la variable foo . Nada demasiado lujoso aquí. Llamemos a esto una referencia de tamaño de la mano izquierda (LHS) a foo , porque estamos asignando un valor a foo y está en el lado izquierdo del signo equal .

En la línea 3, estamos declarando una función y asignándola a la variable baz . Esta es otra referencia de LHS a baz . Le estamos asignando un valor (recuerde, ¡las funciones también son valores!). Esta función se llama entonces en la línea 8. Esto es un RHS, o una referencia del lado derecho a baz . Estamos recuperando el valor de baz , que en este caso es una función y luego lo invocamos. Otra referencia de RHS a baz sería si asignáramos su valor a otra variable, por ejemplo foo = baz . Esta sería una referencia de LHS a foo y una referencia de RHS a baz .

Las referencias de LHS y RHS pueden parecer confusas, pero son importantes para discutir el alcance. Piénselo de esta manera: una referencia de LHS está asignando un valor a la variable, mientras que una referencia de RHS está recuperando el valor de la variable. Son solo una forma más breve y conveniente de decir "recuperar el valor" y "asignar un valor".

Analicemos ahora lo que está sucediendo dentro de la función misma.

Cuando el compilador compila el código dentro de una función, ingresa al alcance local de la función.

En la línea 4, se declara la bar variable. Esta es una referencia de LHS a la bar . En la siguiente línea, tenemos una referencia de RHS para foo dentro de console.log() . Recuerde, estamos recuperando el valor de foo y luego pasándolo como un argumento al método console.log() .

Cuando tenemos una referencia RHS a foo , el compilador busca la declaración de la variable foo . El compilador no lo encuentra en la función en sí, ni en el ámbito local de la función, por lo que sube un nivel: al ámbito global .

En este punto, probablemente esté pensando que el alcance tiene algo que ver con las variables. Eso es correcto. Un ámbito puede considerarse como un contenedor para variables. Todas las variables que se crean dentro de un ámbito local solo son accesibles en ese ámbito local. Sin embargo, todos los ámbitos locales pueden acceder al ámbito global. (Sé que probablemente estés aún más confundido ahora, pero solo aguanta algunos párrafos más).

Entonces el compilador sube al alcance global para encontrar una referencia de LHS a la variable foo . Encuentra uno en la línea 1, por lo que recupera el valor de la referencia de LHS, que es una cadena: 'Hi, I am foo!' . Esta cadena se envía al método console.log() y se envía a la consola.

El compilador ha terminado de ejecutar el código dentro de la función, por lo que volvemos a la línea 9. En la línea 9, tenemos una referencia RHS para la bar variables.

Ahora, la bar se declaró en el ámbito local de baz , pero hay una referencia de RHS para la bar en el ámbito global. Dado que no hay una referencia de LHS para la bar en el ámbito global, el compilador no puede encontrar un valor para la bar y lanza un ReferenceError.

Pero, podría preguntarse, si la función puede buscar variables externas, o si un alcance local puede asomarse al alcance global para encontrar referencias de LHS, ¿por qué el alcance global no puede ver un alcance local? Bueno, así es como funciona el alcance léxico.

... // global scope 
 var baz = function() { 
  ... // baz's scope 
 } 
 ... /// global scope 

Este es el mismo código de arriba que ilustra el alcance. Esto forma una especie de jerarquía que sube al alcance global:

baz -> global .

Entonces, si hay una referencia RHS para una variable dentro del alcance de baz , se puede cumplir con una referencia LHS para esa variable en el alcance global. Pero lo contrario no es cierto .

¿Y si tuviéramos otra función dentro de baz ?

... // global scope 
 var baz = function() { 
  ... // baz's scope 
 
  var bar = function() { 
     ... // bar's scope. 
  } 
 
 } 
 ... /// global scope 

En este caso, la jerarquía o la cadena de alcance se vería así:

bar -> baz -> global

Cualquier referencia de RHS dentro del alcance local de la bar se puede completar con las referencias de LHS en el alcance global o el alcance de baz , pero una referencia de la RHS en el alcance de baz no se puede completar con una referencia de LHS en el alcance de la bar .

Solo puedes atravesar una cadena de alcance, no subir.

Hay otras dos cosas importantes que debe saber sobre los ámbitos de JavaScript.

  1. Los ámbitos son declarados por funciones, no por bloques.
  2. Las funciones pueden ser referenciadas hacia adelante, las variables no pueden.

Observe (cada comentario describe el alcance en la línea en la que está escrito):

`` ` // outer () está en el ámbito aquí porque las funciones pueden ser referenciadas hacia adelante

function outer() { 
 
    // only inner() is in scope here 
    // because only functions are forward-referenced 
 
    var a = 1; 
 
    //now 'a' and inner() are in scope 
 
    function inner() { 
        var b = 2 
 
        if (a == 1) { 
            var c = 3; 
        } 
 
        // 'c' is still in scope because JavaScript doesn't care 
        // about the end of the 'if' block, only function inner() 
    } 
 
    // now b and c are out of scope 
    // a and inner() are still in scope 
 
 } 
 
 // here, only outer() is in scope 

`` `

Referencias

  1. Alcances y cierres de Kyle Simpson. Entra en más detalles de cómo funciona el mecanismo de alcance, y también tiene una descripción superficial de cómo funciona el compilador de JavaScript, así que si estás interesado en eso, ¡definitivamente dale una lectura! Es gratis en GitHub y se puede comprar en O'Reilly.
  2. Secretos del JavaScript Ninja por John Resig y Bear Bibeault. Una gran guía para una comprensión más profunda de JavaScript.