JavaScript, aunque se categoriza como lenguaje interpretado, ejecuta una fase de precompilación esencial antes de procesar cualquier instrucción. Este mecanismo, fundamental para comprender el ámbito léxico, genera comportamientos como la elevación de declaraciones que pueden resultar contraintuitivos.
Precompilación global
Al iniciar la ejecución de un script, el motor crea el contexto global y realiza estas operaciones secuenciales:
- Construcción del Objeto Global (OG): Se establece el entorno raíz donde residirán todas las referencias.
- Registro de variables: Las declaraciones
varse identifican y se añaden al OG con valorundefined. - Registro de funciones: Las declaraciones de función se almacenan completas en el OG.
Considera el siguiente código:
console.log(`Etapa 1: contador=${contador}, procesar=${procesar}, ejecutar=${ejecutar}`);
var contador;
function procesar() { return "procesando"; }
var ejecutar = function() { return "ejecutando"; };
console.log(`Etapa 2: contador=${contador}, procesar=${procesar}, ejecutar=${ejecutar}`);
contador = 100;
procesar = "texto";
ejecutar = 200;
console.log(`Etapa 3: contador=${contador}, procesar=${procesar}, ejecutar=${ejecutar}`);
Desglose paso a paso
- Precompilación: El motor genera el OG con:
contador: undefinedprocesar: function procesar(){...}ejecutar: undefined(la expresión de función no se eleva)
- Línea 1: Muestra
contador=undefined, procesar=[Function], ejecutar=undefined - Líneas 3-5: La declaración
var contadorya fue procesada. La funciónprocesarestá definida. La expresiónejecutarrecibe su valor de función. - Línea 7: Muestra
contador=undefined, procesar=[Function], ejecutar=[Function] - Líneas 9-11: Las asignaciones sobrescriben los valores originales.
- Línea 13: Muestra
contador=100, procesar=texto, ejecutar=200
Precompilación local en funciones
Cada invocación de función crea su propio contexto de ejecución y Objeto de Activación (OA). Los pasos son:
- Instanciación del OA: Objeto de activación específico para la función.
- Registro de parámetros y variables: Parámetros formales y declaraciones
varse añaden al OA con valorundefined. - Vinculación de argumentos: Los valores reales pasados se asignan a los parámetros.
- Registro de funciones internas: Las declaraciones de función dentro de la función se añaden al OA.
Ejemplo con ámbito de función:
function gestionar(dato) {
console.log(`Fase A: dato=${dato}, temporal=${temporal}, auxiliar=${auxiliar}, callback=${callback}`);
var temporal;
function auxiliar() { return "ayuda"; }
var callback = function() { return "retorno"; };
console.log(`Fase B: dato=${dato}, temporal=${temporal}, auxiliar=${auxiliar}, callback=${callback}`);
temporal = "actualizado";
auxiliar = "reemplazado";
callback = "final";
console.log(`Fase C: dato=${dato}, temporal=${temporal}, auxiliar=${auxiliar}, callback=${callback}`);
}
gestionar("inicial");
Análisis del proceso
- Precompilación global: Registra
gestionar: function - Precompilación local (al invocar
gestionar("inicial")):- OA inicial:
{ dato: undefined, temporal: undefined, callback: undefined } - Asignación de argumento:
{ dato: "inicial", ... } - Registro de función:
{ ..., auxiliar: function auxiliar(){...} }
- OA inicial:
- Línea 2: Muestra
dato=inicial, temporal=undefined, auxiliar=[Function], callback=undefined - Líneas 4-6: La asignación de la expresión de función a
callbackactualiza el OA. - Línea 8: Muestra
dato=inicial, temporal=undefined, auxiliar=[Function], callback=[Function] - Líneas 10-12: Las reasignaciones modifican los valores originales.
- Línea 14: Muestra
dato=inicial, temporal=actualizado, auxiliar=reemplazado, callback=final
Este mecanismo demuestra cómo el motor de JavaScript procesa declaraciones antes de la ejecución, creando la ilusión de que "se mueven" al inicio de su ámbito respectivo. Comprender esta fase es crucial para prevenir errores de referencia y debuggear código complejo.