Hoisting
El concepto de Hoisting fue pensado como una manera general de referirse a cómo funcionan los contextos de ejecución en JavaScript (específicamente las fases de creación y ejecución).
Cabe destacar que el hoisting no existía antes de la versión ES6 de JavaScript (2015). Sin embargo, el concepto es útil para entender cómo funcionan las variables y las funciones en JavaScript.
Concepto
El hoisting es el comportamiento por el cual las declaraciones de variables y definiciones funciones son movidas al comienzo de su contexto de ejecución durante la fase de creación.
En otras palabras, las variables y funciones son “elevadas” al comienzo de su contexto de ejecución, es decir, al principio del código.
Para comprender el hoisting, es importante conocer los contextos de ejecución y las fases de creación y ejecución. Por lo tanto, es recomendable leer primero el anexo Contexto de ejecución.
Variables
Como sabemos en JavaScript, podemos declarar variables mediante las palabras reservadas var
, let
y const
. Dependiendo de la palabra reservada que utilicemos, el comportamiento de hoisting será diferente.
Hoisting con var
Cuando el intérprete de JavaScript encuentra una declaración de variable con var
, inicializa su valor como undefined
.
1console.log(message); // undefined2
3var message = "Hola Mundo";4
5console.log(message); // Hola Mundo
Esto se debe a que el intérprete de JavaScript divide la declaración y la asignación de la variable en fases diferentes. Por lo cual, podríamos tener el mismo comportamiento si escribimos redefinieramos el código anterior de la siguiente manera:
1var message;2
3console.log(message); // undefined4
5message = "Hola Mundo";6
7console.log(message); // Hola Mundo
Veremos que message
es elevada al comienzo del contexto de ejecución, pero su valor no es asignado hasta después de la ejecución de la primera sentencia console.log
. Por lo tanto, la primera sentencia console.log
muestra undefined
.
Una variable declarada con var
nunca mostrará un error de referencia (ReferenceError
) si se intenta acceder a ella antes de su declaración.
Este comportamiento puede ser confuso y propenso a errores, razón por la cual se introdujeron las palabras reservadas let
y const
en la versión ES6 de JavaScript.
Hoisting con let
y const
Las variables declaradas con let
y const
también son elevadas al comienzo de su contexto de ejecución, pero no son inicializadas. Por lo tanto, si intentamos acceder a una variable declarada con let
o const
antes de su declaración, obtendremos un error de referencia (ReferenceError
).
1console.log(message); // ReferenceError: Cannot access 'message' before initialization2
3let message = "Hola Mundo";4
5console.log(message); // Hola Mundo
Es importante tener en cuenta que el intérprete si reconoce que la variable message
existe y es inicializada en algún punto del código, pero no permite acceder a ella antes de su declaración.
Esto se debe a la zona muerta temporal (Temporal Dead Zone o TDZ), la cual es el período entre la elevación de una variable y su inicialización. Durante este período, si intentamos acceder a una variable declarada con let
o const
, obtendremos un error de referencia (ReferenceError
).
Funciones
Las declaraciones de funciones también son elevadas, pero no las expresiones de funciones. Es decir, el hoisting de funciones se aplica a las funciones declaradas con la palabra reservada function
.
Al elevar una función, se nos permite llamarla antes de su declaración.
1greet(); // Hola Mundo2
3function greet() {4 console.log("Hola Mundo");5}
La razón por la cual las expresiones de funciones no son elevadas es porque son tratadas como cualquier otra variable.
1greet(); // TypeError: greet is not a function2
3var greet = function() {4 console.log("Hola Mundo");5}
Si intentamos invocar una expresión de función declarada con var
antes de su declaración, obtendremos un error de tipo (TypeError
), ya que la variable greet
es inicializada como undefined
.
1greet(); // ReferenceError: Cannot access 'greet' before initialization2
3let greet = function() {4 console.log("Hola Mundo");5}
Por otro lado, si intentamos invocar una expresión de función declarada con let
o const
antes de su declaración, obtendremos un error de referencia (ReferenceError
), ya que la variable greet
se encuentra en la zona muerta temporal (Temporal Dead Zone o TDZ).
Conclusión
El hoisting es un comportamiento que nos permite acceder a variables y funciones antes de su declaración. Sin embargo, es importante tener en cuenta que las variables declaradas con var
son inicializadas como undefined
, mientras que las variables declaradas con let
y const
no son inicializadas y se encuentran en la zona muerta temporal (Temporal Dead Zone o TDZ).
Como recomendación, si trabajamos con un proyecto Greenfield, es decir, un proyecto nuevo sin restricciones de compatibilidad con versiones anteriores de JavaScript, es preferible utilizar let
y const
.
En cambio, si trabajamos con un proyecto existente con restricciones de compatibilidad con versiones anteriores de JavaScript, es preferible realizar las declaraciones de variables al comienzo de su contexto de ejecución con var
.
En cuanto a las funciones, es una preferencia personal como aprovechar el hoisting.
- Algunos desarrolladores prefieren declarar todas las funciones al final del archivo, para tener una mejor lectura del código.
- Otros desarrolladores prefieren declarar las funciones en archivos separados, para tener un mejor control de la modularidad.