JavaScript: alcance en palabras sencillas

¡Buen dia amigos!



El alcance es un concepto importante para determinar la accesibilidad de las variables. Este concepto está en el corazón de los cierres, dividiendo las variables en globales y locales.



En este artículo intentaré explicar en términos simples qué alcance tiene JavaScript.



1 Alcance



Antes de profundizar en los detalles del alcance, veamos un ejemplo rápido.



Digamos que hemos definido una variable:



const message = 'Hello'
console.log(message) // 'Hello'


Podemos enviar fácilmente su valor a la consola. Esto está claro.



Ahora coloquemos la declaración de la variable de mensaje en el bloque if:



if (true) {
    const message = 'Hello'
}
console.log(message) // ReferenceError: message is not defined


Esta vez, al intentar acceder a la variable, se lanza una excepción ReferenceError: message is not defined.



¿Por qué pasó esto?



Porque el bloque if ha creado un ámbito para la variable de mensaje. Y el mensaje solo está disponible dentro de este ámbito.







Por tanto, la disponibilidad de variables está limitada por el ámbito en el que se definen.



Entonces el alcance es el alcance de las variables.



2. Alcance del bloque



Un bloque de código en JavaScript define el alcance de las variables declaradas con las palabras clave const y let:



if (true) {
    //    if
    const message = 'Hello'
    console.log(message) // 'Hello'
}
console.log(message) // ReferenceError


El primer console.log () imprime de forma segura el valor de la variable de mensaje en la consola, ya que se accede a esta variable en el ámbito en el que está definida.



Sin embargo, llamar al segundo console.log () da como resultado un error porque la variable de mensaje no está disponible en su ámbito externo: el mensaje no existe en el contexto actual.



El alcance de bloque también se crea en declaraciones if, for, while.



Por ejemplo:



for (const color of ['green', 'red', 'blue']) {
    //    for
    const message = 'Hi'
    console.log(color) // 'green', 'red', 'blue'
    console.log(message) // 'Hi', 'Hi', 'Hi'
}
console.log(color) // ReferenceError
console.log(message) // ReferenceError


Las variables de color y mensaje solo existen dentro del bloque for.



Lo mismo es cierto para la declaración while:



while (/*  */) {
    //    while
    const message = 'Hi'
    console.log(message) // 'Hi'
}
console.log(message) // ReferenceError


El mensaje definido en while solo está disponible dentro de este bucle.



En JavaScript, puede crear bloques de código autónomos. También definen su propio alcance:



{
    const message = 'Hi'
    console.log(message) // 'Hi'
}
console.log(message) // ReferenceError


2.1. var no tiene alcance de bloque



Como vimos en los ejemplos anteriores, un bloque de código crea un ámbito para las variables declaradas con las palabras clave const y let. Sin embargo, esto no funciona para las variables declaradas con la palabra clave var.



Consideremos un ejemplo:



if (true) {
    //    if
    var count = 0
    console.log(count) // 0
}
console.log(count) // 0


La variable count está disponible dentro del bloque if, como se esperaba. Sin embargo, ¡también está disponible fuera de este bloque!



Esto se debe a que el bloque de código no crea un ámbito para las variables declaradas con la palabra clave var. Pero la función lo hace.



3. Alcance de la función



Las funciones en JavaScript crean un alcance para todas las variables, sin importar con qué palabra clave se declaren (var, const o let).



Por ejemplo:



function run() {
    //    run()
    var message = ', , !'
    console.log(message)
}
run() // ', , !'
console.log(message) // ReferenceError


La función run () crea un alcance. El mensaje variable está disponible dentro de la función, pero no fuera.



Asimismo, la función crea un ámbito para las variables declaradas con const y let, e incluso para otras funciones y expresiones de función:



function run() {
    //    run()
    const two = 2
    let one = 1
    function run2() {}
    var run3 = () => {}

    console.log(two)
    console.log(one)
    console.log(run2)
    console.log(run3)
}
run() // 2 1 ƒ run2() {} () => {}
console.log(two) // ReferenceError
console.log(one) // ReferenceError
console.log(run2) // ReferenceError
console.log(run3) // ReferenceError


4. Visibilidad del módulo



Los módulos ES6 también crean un ámbito para variables, funciones y clases.



El módulo circular crea un pi constante (para uso interno):



//    circle
const pi = 3.14

console.log(pi) // 3.14

//  pi


La variable pi se declara dentro del módulo de círculo y no se exporta desde allí.



Luego se importa el módulo circular:



import './circle'

console.log(pi) // ReferenceError


La variable pi no está disponible fuera del módulo de círculo (hasta que se exporta mediante exportar).



El alcance modular encapsula los módulos. Esto significa que las variables privadas (que no se exportan) se utilizan para las propias necesidades del módulo y están protegidas del acceso externo.



Así, podemos decir que el alcance es un mecanismo de encapsulación de bloques de código, funciones y módulos.



5. Los ámbitos se pueden anidar



Una característica interesante de los osciloscopios es que se pueden anidar entre sí.



En el siguiente ejemplo, la función run () crea un alcance, y dentro de él, un bloque if crea otro alcance:



function run() {
    //    run()
    const message = ', , !'

    if (true) {
        //    if
        const friend = ''
        console.log(message) // ', , !'
    }

    console.log(friend) // ReferenceError
}
run()


El alcance del bloque if está anidado dentro del alcance de la función run ().



Un ámbito que está dentro de otro ámbito se denomina ámbito interno. En el ejemplo anterior, este es el alcance del bloque if.



Un ámbito que contiene otro ámbito se denomina ámbito externo. En el ejemplo anterior, este es el alcance de la función run ().







¿Qué pasa con la disponibilidad variable? Una regla simple para recordar es:



Las variables del alcance externo están disponibles en el alcance interno.



Por lo tanto, la variable de mensaje está disponible dentro del bloque if.



6. Alcance global



El alcance global es el alcance más externo. Está disponible para cualquier ámbito interno o local. En un navegador, el alcance global se crea cuando se carga el archivo JavaScript especificado en el atributo src de la etiqueta de script:



<script src="script.js">




// script.js

// alcance global

let counter = 1



Las variables declaradas en el alcance global son variables globales. Están disponibles en cualquier otra área.



El alcance global es un mecanismo que permite que el tiempo de ejecución de JavaScript (navegador, Node.js) exponga objetos de host (es decir, propiedad del entorno) a aplicaciones como variables globales.



Por ejemplo, ventana y documento son variables globales (objetos) proporcionados por el navegador. En Node.js, dicha variable es, por ejemplo, el objeto de proceso.



7. Ámbito léxico



Definamos dos funciones, una de las cuales está anidada dentro de la otra:



function outer() {
    //    outer()
    let v = '     outer()!'

    function inner() {
        //    inner()
        console.log(v) // '     outer()!'
    }

    return inner
}

const f = outer()
f()


Eche un vistazo a la última línea: inner () se llama fuera del alcance de outer (). ¿Cómo sabe JavaScript que el valor impreso en la consola en la función inner () pertenece a la variable v declarada en la función external ()?



Respuesta: gracias al alcance léxico.



JavaScript implementa un mecanismo llamado alcance léxico o estático. El alcance léxico significa que la accesibilidad de las variables está determinada estáticamente por la posición de estas variables dentro del alcance de la función anidada: las variables del alcance de la función externa están disponibles en el alcance de la función anidada.



La definición formal de alcance léxico es la siguiente:



El ámbito léxico consta de ámbitos externos definidos estáticamente, es decir de regiones externas, fijadas mediante el uso de variables de esas regiones en funciones internas.



En el ejemplo anterior, el alcance léxico de la función inner () consiste en el alcance de la función external ().



Además, inner () es un cierre porque usa el valor de la variable del ámbito léxico.



8. Aislamiento de variables



Evidentemente, el alcance aísla las variables. Esto permite que diferentes ámbitos contengan variables con el mismo nombre.



Puede utilizar las variables recuento, índice, actual, valor, etc. en diferentes áreas sin la amenaza de colisiones (conflictos de nombres).



Por ejemplo:



function foo() {
    //    foo()
    let count = 1
    console.log(count) // 1
}

function bar() {
    //    bar()
    let count = 2
    console.log(count) // 2
}

foo()
bar()


Conclusión



El alcance determina la disponibilidad de variables. Una variable declarada en el ámbito actual está disponible solo dentro de él.



En JavaScript, los ámbitos se crean mediante bloques, funciones y módulos.



Las variables declaradas con las palabras clave const y let pueden ser de bloque, funcionales o modulares, mientras que las variables declaradas con la palabra clave var no tienen alcance de bloque.



Los ámbitos se pueden anidar. Las variables declaradas en el alcance externo están disponibles en el alcance interno.



El ámbito léxico consta de ámbitos externos definidos estáticamente. Cualquier función, independientemente del lugar de ejecución, tiene acceso a variables desde su ámbito léxico (esta es la esencia de los cierres).



Espero que el artículo te haya sido útil. Gracias por su atención.



All Articles