Comprensión de la precompilación y hoisting en JavaScript

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:

  1. Construcción del Objeto Global (OG): Se establece el entorno raíz donde residirán todas las referencias.
  2. Registro de variables: Las declaraciones var se identifican y se añaden al OG con valor undefined.
  3. 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

  1. Precompilación: El motor genera el OG con:
    • contador: undefined
    • procesar: function procesar(){...}
    • ejecutar: undefined (la expresión de función no se eleva)
  2. Línea 1: Muestra contador=undefined, procesar=[Function], ejecutar=undefined
  3. Líneas 3-5: La declaración var contador ya fue procesada. La función procesar está definida. La expresión ejecutar recibe su valor de función.
  4. Línea 7: Muestra contador=undefined, procesar=[Function], ejecutar=[Function]
  5. Líneas 9-11: Las asignaciones sobrescriben los valores originales.
  6. 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:

  1. Instanciación del OA: Objeto de activación específico para la función.
  2. Registro de parámetros y variables: Parámetros formales y declaraciones var se añaden al OA con valor undefined.
  3. Vinculación de argumentos: Los valores reales pasados se asignan a los parámetros.
  4. 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

  1. Precompilación global: Registra gestionar: function
  2. 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(){...} }
  3. Línea 2: Muestra dato=inicial, temporal=undefined, auxiliar=[Function], callback=undefined
  4. Líneas 4-6: La asignación de la expresión de función a callback actualiza el OA.
  5. Línea 8: Muestra dato=inicial, temporal=undefined, auxiliar=[Function], callback=[Function]
  6. Líneas 10-12: Las reasignaciones modifican los valores originales.
  7. 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.

Etiquetas: JavaScript Hoisting scope-chain activation-object global-object

Publicado el 8-4 21:56