ProgramaciónJavaScript5. Hoisting

El Hoisting es un proceso del compilador de JavaScript, que consiste en que la declaración de las variables y las funciones son llevadas al inicio del código, sin importar su posición, para su procesamiento, sin embargo, la inicialización de las variables no es llevada al inicio del código para su compilación, sino solo su declaración, lo cual suele dar espacio a errores cuando se declara una variable sin inicializarla y se procesa en el código antes de haber llegado a su inicialización, lo cual nos suele dar una variable con valor undefined, ya que la variable sí fue almacenada en memoria, pero no se le asigno un valor hasta después de su ejecución.

Aquí un ejemplo de esto:

saludo();

function saludo() {
	console.log("Hola " + nombre);
}

var nombre = "Aaron";

El output de este código seria el siguiente:

Hola undefined

Debido a que como lo hemos dicho, la variable se tomo en cuenta y se le asigno memoria, sin embargo, el compilador no la inicializo y se le dio el valor de undefined, y con ese valor se ingreso a la función, y ya después de correr la función se le asigno el valor.

Este comportamiento se puede entender fácilmente si se comprenden estos dos puntos esenciales:

  • Las funciones siempre se mueven arriba del scope. Por lo tanto, podemos elegir donde declararlas y usarlas.
  • La declaración de las variables se mueven arriba del scope, pero no la asignación. Antes de usar una variable, habrá que crearla y asignarla.

En base al segundo punto, fue por eso que se cometió el error de usar la variable antes de inicializarla, pues sin problema el compilador le asigna memoria, pero no el valor hasta después.

Básicamente por pasos, lo que hizo el compilador fue esto:

  • Tenemos el código así:
saludo();
	
function saludo() {
	console.log("Hola " + nombre);
}
	
var nombre = "Aaron";
  • El compilador toma las funciones y variables y las “sube” en el código, sin inicializar variables:
var nombre;
	
function saludo() {
	console.log("Hola " + nombre);
}

saludo();
	
var nombre = "Aaron";
  • Le asigna memoria a la variable y le da el valor de undefined al suceder la asignación de memoria
var nombre = undefined;

function saludo() {
	console.log("Hola " + nombre);
}

saludo();
	
nombre = "Aaron";
  • Y como hemos visto, la variable se asigna como undefined y posteriormente su utiliza al llegar a la línea:
    saludos()
    
  • Pues ahí lo que hace es ejecutar la función que ya fue procesada, pero con un valor de la variable que aún no se le asigno, quedando como undefined.
  • Después de correr la función, le asigna el valor correcto a la variable ya declarada:
var nombre = "Aaron";
	
function saludo() {
	console.log("Hola " + nombre);
}
	
saludo();
  • Pero ya es demasiado tarde, pues la función ya fue ejecutada.

Es por eso que se tiene como buena practica declarar e inicializar tanto variables como funciones al inicio de nuestro programa, sin importar donde sean utilizadas, pues de esta manera se evita usarlas antes de ser inicializadas.

Debemos saber que el hoisting solo sucede con las palabras claves var y function, por lo tanto esto nos dice que solo se da en las versiones de ECMAScript 5 o Inferiores, ya que en la versión 6 y superiores se permite la declaración de variables con let y const, que son dos nuevas variables que no activan hoisting.

Lecturas recomendadas

¿Qué es el Hoisting?

Hoisting es un término para describir que las declaraciones de variables y funciones son desplazadas a la parte superior del scope más cercano, scope global o de función. Esto sucede solamente con las declaraciones y no con las asignaciones.

El código permanece igual, solo es una interpretación del motor de JavaScript. En el caso de las variables solamente sucede cuando son declaradas con var.

Hoisting en variables declaradas con var

En el siguiente código, la respuesta del console.log es undefined, porque al hacer referencia a una variable que no está declarada aún, JavaScript crea esta variable antes de declararla y le asigna un valor de undefined.

console.log(nombre) // undefined
var nombre = "Andres" 

// Hoisting
var nombre = undefined
console.log(nombre)
nombre = "Andres"

Hoisting en scope de bloque

Mira el siguiente código y piensa cuál sería el resultado del console.log.

if (true){
	var saludo = "hola"
	let despedida = "chao"
}

console.log(saludo)
console.log(despedida)

La respuesta es primero "hola" y luego un error de referencia. Esto sucede por el hoisting, la declaración de la variable saludo se eleva fuera del bloque en un scope superior, que puede ser un scope de función o global.

var saludo = undefined
if (true){
	saludo = "hola"
	let despedida = "chao"
}

console.log(saludo) // "hola"
console.log(despedida) // ReferenceError: despedida is not defined

Es por eso que var no tiene scope de bloque, y se debe tener cuidado porque puede provocar errores en el código.

Hoisting en funciones

Mira el siguiente código y piensa cuál sería el resultado del console.log.

console.log( saludar() )
function saludar() {
	return "Hola"
}

La respuesta es "Hola", porque al invocar una función que no está declarada, JavaScript la eleva y por eso podemos invocar una función antes de declararla.

// Hoisting
function saludar() {
	return "Hola"
}

console.log( saludar() ) // "Hola"

Pero, lo que realmente sucede es que JavaScript guarda la función en memoria en la fase de creación de un contexto de ejecución, no asigna undefined como con las variables.

Hoisting de variables dentro de una función

El hoisting desplaza las declaraciones a la parte superior del scope más cercano, en el caso de una función dentro de otra función, seguiría el siguiente comportamiento.

function scope() {
	console.log(nombre) // undefined
	console.log(edad) // undefined
	console.log(i) // undefined
	
	var nombre = "Andres"
	var edad = 20
	for (var i = 0; i< 6; i++) {
		//...
	}
}

JavaScript lo interpretaría como lo siguiente:

function scope() {
	var nombre = undefined
	var edad = undefined
	var i = undefined
		    
	console.log(nombre) // undefined
	console.log(edad) // undefined
	console.log(i) // undefined
		    
	nombre = "Andres"
	edad = 20
	for ( i = 0; i< 6; i++) {
		//
	}
}

Hosting en funciones asignadas a variables

Mira el siguiente código y piensa cuál sería el resultado del console.log.

console.log( saludar() )
var saludar = function saludar() {
	return "hola"
}

La respuesta es un error de tipo porque si asignas una función a una variable declarada con var, y la invocas antes declararla, la variable será de tipo undefined y no de función por el hoisting.

var saludar = undefined
console.log( saludar() ) // TypeError: saludar is not a function
saludar = function saludar() {
	return "hola"
}

Hoisting con let y const

Aunque te haya dicho que el hoisting solo ocurre con declaraciones con var, no es totalmente cierto. El hoisting hará que el intérprete de JavaScript eleve las declaraciones con let y const a la Temporal Dead Zone.

La Temporal Dead Zone es una región del código donde la variable está declarada, pero no es posible acceder a esta, provocando un error de tipo ReferenceError.

console.log(nameVar) // undefined
console.log(nameLet) // ReferenceError: nameLet is not defined
var nameVar = "myVar"
let nameLet = "myLet"

Buenas prácticas para usar hoisting

  • No utilices var en las declaraciones de variables.
  • Escribe primero las funciones y luego su invocación.
Built with LogoFlowershow