Command Palette

Search for a command to run...

Scope y Ámbito Léxico en JavaScript

Domina cómo funciona el scope en JavaScript, los diferentes tipos de ámbito, el scope léxico, y cómo JavaScript determina el alcance de variables y funciones a través de las cadenas de scope.

Lectura: 13 min
Nivel: Principiante

TL;DR - Resumen rápido

  • Scope es el contexto donde las variables y funciones son accesibles
  • Tipos de scope: global, de función, de bloque y léxico
  • Scope global: variables accesibles desde cualquier parte del código
  • Scope de función: variables accesibles solo dentro de la función
  • Scope de bloque: variables accesibles solo dentro del bloque (let/const)
  • Ámbito léxico: funciones acceden a variables del ámbito donde fueron definidas

¿Qué es el scope?

El scope (alcance) es el contexto en el que las variables y funciones son visibles y accesibles. Determina qué partes de tu código pueden acceder a qué variables. En JavaScript, el scope es fundamental para entender cómo funcionan las variables, las funciones, y cómo JavaScript determina qué valor usar cuando se referencia una variable.

Cuando JavaScript busca una variable, sigue un proceso llamado "scope resolution" (resolución de scope). Busca primero en el scope actual, luego en el scope padre, y así sucesivamente hasta llegar al scope global. Este proceso es lo que permite que las funciones anidadas accedan a variables de funciones externas, pero no al revés.

Scope y memoria

El scope no solo determina accesibilidad, sino también el ciclo de vida de las variables. Las variables en un scope local se crean cuando el scope se activa y se destruyen cuando el scope termina, liberando memoria.

Tipos de scope en JavaScript

JavaScript tiene varios tipos de scope que determinan dónde y cómo las variables son accesibles. Entender estos tipos es esencial para escribir código predecible y evitar bugs relacionados con el alcance de variables.

tipos-scope.js
Loading code...

El ejemplo muestra los diferentes tipos de scope en acción. Las variables globales son accesibles desde cualquier parte, las variables de función solo dentro de su función, y las variables de bloque solo dentro del bloque donde fueron declaradas. Cada tipo de scope tiene reglas específicas sobre cómo las variables son creadas, accedidas y destruidas.

  • <strong>Scope global:</strong> Variables accesibles desde cualquier parte del código
  • <strong>Scope de función:</strong> Variables accesibles solo dentro de la función
  • <strong>Scope de bloque:</strong> Variables accesibles solo dentro del bloque &#123;...&#125;
  • <strong>Scope léxico:</strong> Determinado por dónde se escribe el código, no dónde se ejecuta
  • <strong>Scope de módulo:</strong> Variables privadas dentro de un módulo ES6

Scope global

El scope global es el scope más externo en JavaScript. Las variables declaradas fuera de cualquier función o bloque están en el scope global y son accesibles desde cualquier parte del código. En los navegadores, el scope global está asociado con el objeto window, mientras que en Node.js está asociado con el objeto global.

scope-global.js
Loading code...

El ejemplo muestra cómo las variables globales son accesibles desde cualquier función o bloque. La variable globalVar está en el scope global, por lo que puede ser accedida tanto dentro de funcionInterna como en el scope global. Sin embargo, el abuso de variables globales es considerado una mala práctica porque puede causar conflictos de nombres y hacer el código difícil de mantener.

Evita variables globales

Las variables globales pueden causar conflictos cuando múltiples scripts o bibliotecas se ejecutan en la misma página. Prefiere encapsular tu código usando módulos, IIFE, o funciones para evitar contaminar el scope global.

Scope de función

El scope de función es el scope creado por cada función en JavaScript. Las variables declaradas con var dentro de una función tienen scope de función, lo que significa que son accesibles en cualquier parte de la función, incluso antes de su declaración (debido al hoisting). Las funciones crean su propio scope, lo que permite encapsulación y evita conflictos de nombres.

scope-funcion.js
Loading code...

El ejemplo muestra cómo el scope de funciona funciona. Las variables declaradas dentro de miFuncion no son accesibles desde fuera de la función. Sin embargo, las funciones anidadas pueden acceder a las variables de la función externa, creando una cadena de scope. Esto es fundamental para las closures, que permiten que las funciones "recuerden" el entorno donde fueron creadas.

El scope de función proporciona encapsulación: las variables son privadas dentro de la función. Las variables var se elevan al inicio de la función (hoisting), haciéndolas accesibles en cualquier parte de la función incluso antes de su declaración. Las funciones anidadas pueden acceder al scope externo, creando la base para las closures. Cada función tiene su propio scope independiente, permitiendo que múltiples funciones tengan variables con el mismo nombre sin conflictos.

IIFE y scope de función

Las IIFE (Immediately Invoked Function Expressions) usan el scope de función para crear ámbitos privados temporales. Esto era fundamental antes de ES6 para evitar contaminación global.

Scope de bloque

El scope de bloque fue introducido en ES6 con let y const. A diferencia de var, que tiene scope de función, las variables declaradas con let y const tienen scope de bloque, lo que significa que solo son accesibles dentro del bloque donde fueron declaradas. Los bloques son delimitados por llaves {...}.

scope-bloque.js
Loading code...

El ejemplo muestra la diferencia entre var (scope de función) y let/const (scope de bloque). La variable varVar "escapa" del bloque if porque tiene scope de función, mientras que letVar y constVar solo son accesibles dentro del bloque. El scope de bloque hace el código más predecible y reduce bugs sutiles.

Prefiere let y const

Usa let y const en lugar de var para aprovechar el scope de bloque. Esto hace que tu código sea más seguro, predecible y menos propenso a bugs relacionados con el scope.

Ámbito léxico (Lexical Scope)

El ámbito léxico (lexical scope) es la regla que determina el scope basándose en dónde se escribe el código, no dónde se ejecuta. En JavaScript, las funciones acceden a las variables del ámbito donde fueron definidas, no del ámbito donde son invocadas. Esta característica es fundamental para las closures y es una de las diferencias clave entre JavaScript y otros lenguajes con scope dinámico.

ambito-lexico.js
Loading code...

El ejemplo muestra el ámbito léxico en acción. La función interna accede a la variable externa del ámbito donde fue definida, no del ámbito donde es invocada. Aunque interna se invoca desde el scope global, sigue teniendo acceso a las variables del scope de externa porque fue definida dentro de ese scope.

El ámbito léxico es la diferencia clave entre definición y ejecución: el scope se determina por dónde se define el código, no dónde se ejecuta. También conocido como static scoping, este comportamiento hace que el código sea más predecible y fácil de razonar. El ámbito léxico es la base fundamental para que las funciones recuerden su entorno a través de closures, a diferencia del scope dinámico que usan algunos otros lenguajes de programación donde el scope se determina en tiempo de ejecución.

Base de closures

El ámbito léxico es lo que hace posible las closures. Las closures existen porque las funciones "recuerdan" las variables del ámbito léxico donde fueron definidas, incluso después de que ese ámbito haya terminado de ejecutarse.

Cadenas de scope (Scope Chains)

La cadena de scope (scope chain) es el proceso que JavaScript usa para buscar variables. Cuando JavaScript busca una variable, comienza en el scope actual y sube por la cadena de scope hasta encontrarla o llegar al scope global. Si no la encuentra en ningún scope, lanza un ReferenceError.

cadenas-scope.js
Loading code...

El ejemplo muestra cómo JavaScript busca variables a través de la cadena de scope. Cuando funcionTres busca variable, JavaScript primero busca en su propio scope, luego en el scope de funcionDos, luego en el scope de funcionUno, y finalmente en el scope global. Este proceso es transparente para el programador pero fundamental para entender cómo JavaScript resuelve referencias a variables.

  1. <strong>Scope actual:</strong> JavaScript busca primero en el scope actual
  2. <strong>Scope padre:</strong> Si no encuentra, busca en el scope inmediato superior
  3. <strong>Ascendente:</strong> Continúa subiendo por la cadena de scope
  4. <strong>Scope global:</strong> Último scope en la cadena
  5. <strong>Error:</strong> Si no encuentra en ningún scope, lanza ReferenceError

Performance

Acceder a variables en scopes más profundos de la cadena es ligeramente más lento que acceder a variables en el scope actual. Sin embargo, esta diferencia es insignificante en la mayoría de los casos y no deberías optimizar prematuramente.

Resumen

Resumen: Scope y Ámbito Léxico

Conceptos principales:

  • Scope es el contexto donde variables son accesibles
  • Scope global: accesible desde cualquier parte del código
  • Scope de función: variables dentro de la función (var)
  • Scope de bloque: variables dentro del bloque (let/const)
  • Ámbito léxico: determinado por dónde se define el código
  • Cadena de scope: proceso de búsqueda de variables

Mejores prácticas:

  • Usa let y const para scope de bloque
  • Evita variables globales cuando sea posible
  • Usa módulos ES6 para encapsulación
  • Aprovecha el scope léxico para closures
  • Entiende la cadena de scope para debugging
  • Usa IIFE solo cuando necesites scope temporal