Entiende el Hoisting en JavaScript con Ejemplos Prácticos

Tiempo
~7m

Hoisting es un concepto fundamental del lenguaje JavaScript debido a que te ayuda a entender cómo tu código es ejecutado y por ello, es uno de los temas que se preguntan con frecuencia en las entrevistas (en serio) .

Aunque el concepto es muy sencillo, la mayoría de las veces se malinterpreta. En este artículo vas a aprender qué es hoisting con la ayuda de algunos ejemplos.

Lo que vas a aprender

Después de leer este artículo vas entender:

  • El contexto de ejecución y sus fases.
  • Cómo funciona el hoisting con variables (var) y funciones (function)
  • Casos especiales de hoisting (const y let).
  • Qué es la Temporal Dead Zone.

Ejemplos

Considera este ejemplo:

Cuya salida es:

Es bastante sencillo, ¿verdad?

El código se ejecuta línea por línea.

Echemos un vistazo a lo que sucede:

  • Se crea la variable source y se le asigna un valor a escuelafrontend.com .
  • Se encuentra la línea de código console.log y el valor de source se imprime en la consola: escuelafrontend.com .
  • Del mismo modo, la siguiente línea es la definición de la función print. Seguido de la llamada real a la función print(). Esto resulta en las declaraciones dentro de la función que se ejecuta y la cadena desde print: escuelafrontend.com se imprime en la consola.

Pero, ¿es realmente tan sencilla la ejecución de código en JavaScript?

Echa un vistazo a esta variación del mismo ejemplo:

Aquí estamos llamando la variable source en la consola y la función print antes de que sean declaradas.

¿Crees que este código arrojará un error?

¿Cuál crees que es la salida esperada para este ejemplo?

Tómate un momento para pensar antes de ver la respuesta más abajo.

.

.

.

.

.

.

.

.

En la mayoría de los lenguajes de programación esto lanzaría una excepción.

Pero bueno, JavaScript lo permite. ¿Cómo? Debido al hoisting.

El concepto más popular de hoisting es:

💡

Hoisting en JavaScript te permite acceder a funciones y variables antes de que hayan sido creadas.

Este concepto no es tan preciso, así que para entender cómo funciona el hoisting necesitamos entender el contexto de ejecución.

Contexto de Ejecución

El contexto de ejecución es el entorno que prepara el motor de JavaScript para ejecutar el código que escribimos.

En pocas palabras, es la información necesaria para ejecutar el código.

El contexto de ejecución se crea en dos fases:

Fase de Creación

  • El código es escaneado/parseado para las variables y funciones.
  • Se reserva espacio para las variables en memoria.
  • Las definiciones de las funciones se cargan en la memoria.

Fase de Ejecución

  • El código se ejecuta línea por línea con la información de la fase de creación.
  • Se asignan valores a las variables.
  • Se ejecutan las funciones.

Veamos estas fases para el ejemplo ilustrado anteriormente:

Fase de CreaciónLoading

Fase de EjecuciónLoading

Para comprobar si has entendido bien el concepto de hoisting y contexto de ejecución, veamos otro ejemplo:

Salida:

¿Te causa sorpresa el error en la salida? No debería.

Para entenderlo mejor, echa un vistazo a los siguientes diagramas.

Fase de CreaciónLoading
  • Las variables source y printFnExp se cargan en memoria.
  • La función print se carga en la memoria.

Fíjate bien en printFnExp: es una expresión de función. Esto indica que es una variable cuyo valor apunta a una función.

En términos simples, la función está asignada a una variable. Para llamar a la función que está asignada a una variable, tenemos que escribir “nombreDeLaFuncion” seguido de paréntesis. Por ejemplo: printFnExp()

Fase de EjecuciónLoading
  • El valor 5 se asigna a source.
  • 5 se imprime en la consola.
  • Se llama a printFnExp. Sin embargo, arroja un error - Uncaught TypeError: printFnExp no es una función.

Esto sucede porque la variable fue “hoisteada”, pero su valor inicial sigue siendo undefined. Por lo tanto, obtenemos un error por intentar llamar a una función sobre un valor indefinido.

La sentencia que asigna la referencia de la función print a printFnExp no se ha ejecutado.`

Para solucionar este error, vea los cambios en el código que aparecen a continuación:

Salida:

Aquí se ha asignado a printFnExp la referencia de la función print. Por lo tanto, ahora es posible invocar la expresión de la función así - printFnExp();

💡

Nota: Hay más en el contexto de ejecución que lo mencionado en este artículo. He cubierto sólo lo suficiente para que se entienda el concepto de hoisting.

Casos Excepcionales

El hoisting funciona de forma diferente si la declaración de la variable se realiza mediante let o const.

En el caso de var el valor se inicializa a indefinido durante la fase de creación. Sin embargo, en el caso de let y const el valor sólo se inicializa durante la fase de ejecución.

Mira el ejemplo siguiente:

Salida:

Como el valor de source no se inicializa durante la fase de creación, source no tiene ninguna referencia al valor en memoria. Debido a esto, se lanza un error de referencia para la declaración console.log(source);

💡

Este concepto también se conoce como Temporal Dead Zone (zona muerta temporal). Significa que no se puede acceder a una variable hasta que se declare.

Veamos el mismo ejemplo con estos conocimientos.

Arriba estamos representando la Temporal Dead Zone para la variable source. Obtendremos un error de referencia si intentamos acceder a la fuente dentro de este bloque.

A continuación se muestra el uso correcto de let:

Durante la fase de ejecución, si no se proporciona ningún valor junto con la declaración, el valor se considera undefined.

Mira el ejemplo:

Salida:

Ejemplo con const:

Salida:

Una const indica un valor constante. Este valor no puede ser cambiado durante la ejecución del código. Por lo tanto, tiene sentido que requiera un valor inicializador en el momento de la declaración.

Uso correcto de const:

Salida:

Recapitulación y Conclusión

En resumen, el mejor concepto de hoisting sería

Hoisting es cuando las funciones y las variables se almacenan en memoria para un contexto de ejecución antes de ejecutar nuestro código.

Las funciones se almacenan con una referencia a las funciones completas, las variables declaradas con var con el valor de undefined, y las variables declaradas con let y const se almacenan sin inicializar.

Las mejores prácticas sugieren declarar las variables al principio del bloque de código. También es preferible utilizar let y const para la declaración de variables. Esto mejora la legibilidad del código.

Aunque el uso de la declaración de variables mediante var se ha convertido en algo obsoleto, es importante conocer este concepto, ya que es posible que te lo encuentres en algunas de las bases de código existentes o incluso en una entrevista donde tengas que refactorizar dicho código con las últimas características de JavaScript.

El conocimiento del hoisting te ayudará a evitar cualquier error y confusión relacionados con la declaración de variables y su uso.

Otros Recursos