Hoisting en Javascript

Recientemente un viejo colega (@f5inet) me pedía una breve introducción al uso de las variables en Javascript. Explicándole por encima las normas básicas, llegué a uno de los puntos que más confusión despiertan y que son una fuente frecuente de errores para los programadores noveles: el hoisting.

El hoisting (“elevación”) en Javascript es una de esas particularidades del lenguaje sobre la que la comunidad de desarrolladores no llega a ponerse de acuerdo en si se trata de un bug o una feature.

Para John Resig, manejado correctamente, es un poderoso aliado a la hora de gestionar los ámbitos que alcanzan nuestras variables; para otros como Douglas Crackford, su descuido se convierte inmediatamente en inconsistencias en nuestros códigos y errores potenciales difíciles después de identificar y depurar.

Qué es el hoisting?

En Javascript, cuando se define una variable en el interior de una función, el intérprete interno pasa a ubicarla al comienzo de su contexto (la eleva). Podemos imaginarnos así a nuestras funciones como recipientes de agua hirviendo donde las partículas más pequeñas (las variables) buyen hacia la superficie; el resto de elementos, incluidos los valores de esas variables, son más pesados y se quedan donde están.

Ejemplos

Tomemos el siguiente código:

function foo(){
 bar();
 var x = 1;
}

Pese a que hemos declarado la variable x un punto concreto del código, el intérprete Javascript mueve dicha declaración a lo más alto de su contexto. Internamente, el código se ejecutaría de la siguiente manera:

function foo(){
 var x;
 bar();
 x = 1;
}

La variable es declarada antes que se ejecute cualquier otra acción, lo que puede llegar a ocasionar comportamientos no esperados:

var x = 'Hello World'; // variable global
 
function foo(){
 alert( x ); // esperamos el valor global
 var x = 'New Value'; // redefinimos la variable en contexto local
 alert( x );  // esperamos el nuevo valor local
}
 
foo();

Posiblemente este código no funcione como se deseábamos: el primer alert() no devuelve el valor ‘Hello World’ pese a que la variable había sido declarada anteriormente como global. En su lugar, obtenemos un inesperado undefined. La razón es que la posterior declaración de x, internamente se eleva hasta el inicio de su función (buye), por lo que pasa a estar definida de forma local pero sin un valor aún asignado. El anterior código equivale a este mucho más claro:

var x = 'Hello World';
 
function foo(){
 var x;
 alert( x );
 x = 'New Value';
 alert( x );
}
 
foo();

La recomendación de los expertos es siempre declarar las variables locales al principio de su actual ámbito para evitar errores. De esta forma ganamos además legibilidad del código ya que agrupamos así todas nuestras variables en un mismo lugar permitiéndonos de un vistazo conocer el tipo de datos que esperan:

function foo(){
 var myObj = {};
 var myArray = [];
 var number1, number2, number3;
 var string1, string2, string3;
 
 // Some code here...
}

Como apunte final, aclarar que el término hoisting no está definido dentro del actual ECMAScript, sin embargo es comunmente utilizando para describir el particular comportamiento que Javascript hace de las variables en el interior de las funciones.

Acerca de Carlos Benítez

Programador Web y arquitecto Javascript. Experto en jQuery, accesibilidad y usabilidad. Fundador de www.etnassoft.com.
Esta entrada fue publicada en Javascript y etiquetada , , , . Guarda el enlace permanente. Sígueme en Twitter

Últimos libros gratuitos añadidos a OpenLibra

{6} Comentarios.

  1. 08feb2011/
    12:20 h /
    davidgarsan

    Muy interesante tu blog.
    Lo acabo de descubrir accidentalmente…
    Un remedio de la abuela, la que fuma, para evitar accidentes como el de tu segundo ejemplo es usar el ámbito al referirse a una variable declarada globalmente, fuera de una función.
    En este caso alert(window.x).

    • 08feb2011/
      13:05 h /

      Hola David;
      efectivamente, si la idea es referirse a la variable global, podemos acceder a ella a través del objeto window (contexto general del navegador).
      Sin embargo, la idea aquí es no confundirse con el ámbito en el que se declaran las variables para así evitar comportamientos raros :)

      Tú ejemplo quedaría:

      var a = 'foo';
      (function hola(){
        console.log( window.a ); // foo
        var a = 'bar';
        console.log( a ); // bar
      })();
      

      Un saludo!

  2. 08feb2011/
    12:33 h /
    davidgarsan

    Bendito namespacing de todos modos…

  3. 25sep2013/
    3:16 h /

    function gracias(){
    var etnassoft = “Carlos Benitez”;
    i= 0;
    for(i; i<5; i++){
    alert("muchas gracias"+ " " + etnassoft);
    }
    }

    gracias();

  4. 08oct2013/
    17:54 h /

    Esto esta bueno , aun pienso que mi codigo en js es un asco pero espero poco a poco tener un codigo minimalista pero funcional :B

Deja un comentario

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

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Licencia Creative Commons 3.0

®Copyright 2011. Cotenido web bajo licencia Creative Commons 3.0

Códigos bajo licencias MIT y GPL. Ver página de licencias para más información