Elevación de variables (hoisting) en JavaScript

Post original en JASoft.org: http://www.jasoft.org/Blog/post/Elevacion-de-variables-(hoisting)-en-JavaScript.aspx

GruaEn esta ocasión quiero hablar de un efecto quizá poco conocido pero importante del modo en que procesa el código JavaScript.

En JavaScript existen variables globales, las cuales tienen sus ventajas en un lenguaje como este, pero también están llenas de peligros, y variables locales, cuyo ámbito se circunscribe exclusivamente a las funciones en las que se declaran.

Podemos utilizar una variable global desde dentro de una función cualquiera, ya que están accesibles desde cualquier lugar de la página, por ejemplo:

//Variable global
var name = "Jose";

function HelloWorld(){
  alert(name);
}

HelloWorld();

Al hacer esto saltará el mensaje con el nombre que hay en la variable. Bastante obvio.

Bien, pero ¿qué pasa si definimos una variable con el mismo nombre dentro de la función?:

//Variable global
var name = "Jose";

function HelloWorld(){
  //Variable local
  var name = "Pepe";
  alert(name);
}

HelloWorld();

Las reglas de precedencia de variables en JavaScript dicen que las variables locales preceden a las globales, por lo que en este caso veríamos aparecer por pantalla la palabra “Pepe” que es el valor de la variable local.

Sin embargo ahora vamos a hacerle un sutil cambio al código anterior y haremos lo siguiente:

//Variable global
var name = "Jose";

function HelloWorld(){
   alert(name);
   //Variable local
   var name = "Pepe";
}

HelloWorld();

¿Qué veremos ahora por pantalla?

Por lógica parece que deberíamos ver “Jose”, ya que en el momento de llamar al alert todavía no se ha declarado la variable local, y por lo tanto se debería acceder a la global ¿verdad? Pues no.

Lo que veremos por pantalla es un bonito “undefined”:

Undefined

¿Por qué ocurre esto?

Declaración vs Definición de variables en JavaScript

Una variable en JavaScript se declara de dos formas diferentes: mediante la palabra clave “var”, o bien directamente nombrándola por primera vez cuando se le asigna un valor (sin poner var delante, lo cual es muy mala práctica, por cierto).

El hecho de declarar una variable no implica tener que definirla, ya que la podemos declarar pero no necesariamente asignarle un valor:

var variable1;  //Se declara pero no se define
variable1 = “1”; //Se define asignándole un valor

var variable2 = 2; //Se declara y se define todo a la vez

Ahora que tenemos claro este concepto, podemos entender mejor lo que ocurre en el ejemplo anterior para que se muestre un undefined por pantalla.

El efecto de elevación

Aunque JavaScript es un lenguaje interpretado y procesa las líneas de código una a una según se las va encontrando, en realidad no es del todo así. En el caso de las variables que hay dentro de una función lo que hace el intérprete es declararlas todas a la vez al principio de la función, independientemente de donde estén realmente declaradas dentro de ésta. Por eso, en el ejemplo anterior aunque la variable está declarada y definida abajo del todo, cuando la vamos a mostrar nos devuelve un “undefined”: el intérprete “eleva” la declaración implícitamente al principio de la función, así que el código anterior es equivalente a este:

//Variable global
var name = "Jose";

function HelloWorld(){
   //Variable local
   var name;
   alert(name);
   name = "Pepe";
}

HelloWorld();

Si vemos el código de esta manera entonces el resultado cobra todo el sentido del mundo ¿verdad?

Así que precisamente por este efecto se considera una buena práctica el declarar todas las variables locales de nuestras funciones siempre al principio, independientemente de donde las vayamos a definir o utilizar. Esto nos evitará efectos desagradables como este.

Es un efecto que es interesante conocer y que puede evitarnos algún “bug” raro que nos sería muy difícil corregir si no somos conscientes de su existencia.

¡Espero que te sea útil!

Para saber más: Fundamentos de JavaScript y AJAX para desarrolladores y diseñadores web

Sin categoría

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *