Que es hoisting
La palabra a la que hace referencia hoisting – elevamiento – es a la forma en la que java script determina el comportamiento de las variables y funciones en tiempo de compilación.
Sin embargo, el termino puede llevar a malos entendidos debido a que suponemos que JS eleva las declaraciones y funciones hacia el “scope” de la función o programa, cuando esto no sucede en realidad debido a que JS asigna memoria a variables y funciones para después ejecutar el código.
Uso de hoisting en funciones
Es por eso que una de las ventajas de hoisting es poder mandar llamar a funciones y variables sin siquiera ser declararlas, como se muestra a continuación.
1 2 3 4 5 |
function getNombre(nombre){ // Recibo nombre el cual será impreso desde consola console.log("El nombre es: " + nombre); // Cuando recibo el nombre lo mando a imprimir } getNombre("Diego"); // Cuando declaro la función mando llamarla y le asigno al parámetro Diego. |
Por lo que se esperaría que el siguiente código funcione con normalidad.
Es por la misma razón en que JS coloca las declaraciones de funciones antes que cualquier segmento de código del programa y se pueda mandar llamar la función antes de su declaración del código como se muestra en la siguiente función.
1 2 3 4 5 6 7 8 |
getNombre("Diego"); // Ahora mando a llamar a la función antes de su declaración // y me da el mismo resultado. function getNombre(nombre){ console.log("El nombre es: " + nombre); /*Cuando declaro la función manda llamarla y le asigno al parámetro Diego el resultado es.: El nombre es: Diego.*/ } |
Al tener similitud sintáctica y estructura general de la familia de lenguaje C se esperaría que al momento de la ejecución este código imprima un error, debido a que se desconoce al no tener una previa declaración.
Sin embargo, al ser un lenguaje interpretado (que no requiere de ningún otro paso antes de la ejecución), el programa dejaría de funcionar hasta encontrarse con un error en el programa.
Incluso si el programa contiene errores pero no son detectados al ejecutarse algunos de estos bloques de código, este, seguiría funcionando.
Distintos usos de hoisting en variables.
Para el caso de las variables con hoisting en JS se pueden mandar llamar y usar antes de declararlas como se muestra en el ejemplo siguiente:
1 2 3 4 5 6 7 |
(function (){ //Utilizamos una function similar a Java. costoRefresco = 7; // asignamos el valor a una variable sin previa declaración. costoRefresco+= 2; //Le sumamos a la misma variable 2 mas su valor previamente definido. total = costoRefresco; // Le asignamos a total el valor de costoRefresco. console.log("Total: "+total); //Imprimimos el valor total en la consola. var costoRefresco, total; // Declaramos nuestras variables con el modelo hoisting de JS. })(); |
La siguiente función utiliza hoisting al inicializar y utilizar las variables sin previa inicialización, después se suma el valor dos, se asigna el valor de costoRefresco a total y este se imprime en la consola, por ultimo se realizan las declaraciones de las variables previamente utilizadas.
Usar la estructura de código en JS
Sin embargo, no podemos utilizar las variables sin inicialización, por lo que, si utilizamos una variable sin inicializarla su valor por defecto será undefined, como se muestra en el siguiente ejemplo este comportamiento:
1 2 3 4 5 6 7 8 9 |
(function (){ costoRefresco = 7; // Inicializamos la variable costoRefresco costoRefresco+= costoPapas; /* Sumamos en la variable costoRefresco su valor mas el valor de la variable costoPapas sin inicialización. */ total = costoRefresco; // Asignamos a total el valor de la variable costoRefresco. console.log("Total: "+total); var costoRefresco, total,costoPapas=10; /* Declaramos nuestras variables como permite hoisting así como inicializamos el valor de costoPapas. */ })(); |
Al momento de sumar el costoRefresco con costoPapas y ejecutar el script arroja como resultado NaN (Not – a – Number) ya que costoPapas no a sido inicializado y al imprimir el total que es la suma de estos dos, este ultimo “transfiere” a esta variable el undefined.
A continuación veremos otro ejemplo en el que la ausencia de inicialización hace que costoPapas sea undefined:
1 2 3 4 5 6 7 8 9 10 |
(function (){ var costoPapas; // Comprobaremos que declarando, pero no inicializando // costoPapas tiene un valor undefinied. costoRefresco = 7; total = costoRefresco; console.log("Total: "+total + " " + costoPapas); // Imprimimos el valor total concatenando la impresión del valor de costoPapas. var costoRefresco, total; // Declaramos nuestras variables. costoPapas=10; // Inicializamos el valor de nuestra variables costoPapas. })(); |
En este caso es similar al primer ejemplo, sin embargo, aunque se ha declarado la variable costoPapas al inicio del scope, al imprimirse sigue sin inicializarse por lo que el compilador no puede determinar el valor de costoPapas y manda como resultado hacia la consola: 7 undefined.
El cual indica que costoRefresco es igual a 7 debido a su inicialización y que costoPapas es undefined debido a la ausencia de este último.
Scope vs Hoisting.
El scope como su palabra lo dice es el alcance de una variable la cual puede ser local o global, cuando queremos acceder desde cualquier parte del código a una variable se debe declarar global, de lo contrario optamos por declararla local ya que será en ese ámbito donde funcionará.
Dicho esto se puede ocasionar un problema al utilizarse dentro de los ámbitos global y local, como se muestra a continuación.
1 2 3 4 5 6 7 8 |
var saludo="hola"; // Declaramos e inicializamos nuestra variable global. (function (){ console.log(saludo); // Intentamos imprimir esa variable global var saludo="hola como estas?" // Declaramos e inicializamos nuestra variable local con el mismo nombre. console.log(saludo); // Mandamos llamar a nuestra variable local. })(); console.log(saludo); // Mandamos llamar nuestra variable global. |
Este ejemplo muestra cómo queremos intentar mandar llamar a nuestra variable global dentro del scope de nuestra función, sin embargo, debemos tener cuidado al momento de declarar las variables así como asignarles nombres claros y significativos.
Al momento de mandar llamar dentro de la función, saludo ya a sido asignada como undefined ya que dentro del ámbito local no ha sido inicializada y JS no sabe aún qué valor tendrá dicha variable.
Código completo en el repositorio github en la siguiente liga:
https://github.com/diegoabundis/hoisting
¿Este articulo es viejo? Tiene malas practicas de programación en Javascript
Leo en el codigo fuente variables sin estar definida por VAR (esto daria error en linting o compilacion del codigo con webpack)
Ya no se usa VAR, ahora se usa LET y CONST (https://dev.to/johnwolfe820/should-you-never-truly-use-var-bdi)
¿Porque tanto codigo autoejecutable?
Si el artículo es un poco viejo, sin embargo es importante dejar claro que es muy diferente hablar de buenas practicas a errores de código.
Este código no genera errores ya que las variables globales son permitidas en el motor de JS, al igual que las variables locales declaradas con var.
En este artículo lo importante es que se logre identificar como el hoisting va de la mano del alcance de las variables y es importante mostrar la diferencia de variables globales, locales y de bloque (sin var, con var y let)