Hoisting en JavaScript

En la mayoría de los lenguajes de programación, el ámbito / alcance de una variable está en el bloque donde fue definida (block-level scope), por ejemplo, dentro de un bloque de instrucciones if, for, while; sin embargo en JavaScript (ECMAScript 5.1) esto no es así, puesto que el alcance de una variable es el de la función en la cual fue declarada (function-level scope).

¿Qué es hoisting?

El hoisting o “elevamiento” es una de las particularidades de JavaScript y se da cuando definimos una variable en el interior de una función (en el scope), entonces el intérprete interno pasa a declararla al comienzo de su contexto (la eleva); veamos el siguiente ejemplo:

    (function () {
        for(var x = 0; x < 3; x += 1) {
            console.log(x);
        }
        console.log(x, "todavía existe!!");
    }());

❓ ¿Que es lo que ocurrió?, como se mencionó anteriormente, el intérprete interno se encarga de elevar la declaración de variables al comienzo del contexto de ejecución. Veamos lo que realmente hace el navegador cuando interpreta el código anterior:

    (function () {
        var x; // <- la variable es elevada
        for(x = 0; x < 3; x += 1) {
            console.log(x);
        }
        console.log(x, "todavía existe!!");
    }());
Ahora observemos con más detalle el siguiente ejemplo:
    var x = 5;

    (function () {
        console.log("x:", x); //se espera 5
        var x = 10;
        console.log("x:", x); //se espera 10
    }());

Nuevamente ocurre algo inesperado, ya que la primera vez que imprimimos la variable se esperaba el valor de la variable global (5), sin embargo obtenemos undefined.💡 Veamos cómo lo interpreta el navegador:

    var x = 5;

    (function () {
        var x; // <- la variable es elevada
        console.log("x:", x); //-> undefined
        x = 10;
        console.log("x:", x); //-> 10
    }());
image hoisting
Probemos el siguiente caso con funciones:
    console.log("fn1", fn1()); //que imprime?
    console.log("fn2", fn2()); //que imprime?

    //function expression
    var fn1 = function() { return 1; };

    //function declaration
    function fn2() { return 2; }

😮 Nuevamente el hoisting haciendo de las suyas. Cuando creamos una función utilizando la sintaxis function declaration, la declaración y la definición de la función son elevadas, sin embargo cuando utilizamos la sintaxis para function expression, sólo se eleva la variable, pero no su valor.

    var fn1; // <- la variable es elevada
    function fn2() { return 2; } // <- declaración y definición son elevadas

    console.log("fn1", fn1()); //throw TypeError: undefined is not a function
    console.log("fn2", fn2()); //2

    //function expression
    fn1 = function() { return 1; };

Resumiendo

Como la declaración de variables es procesada antes de que cualquier código sea ejecutado, declarar una variable en cualquier parte es lo mismo que declararla al inicio. Esto también significa que una variable puede ser usada antes de su declaración. A éste comportamiento se le conoce como hoisting y es cuando la declaración de la variable se mueve al inicio del contexto de ejecución. Por lo mencionado anteriormente, en JavaScript es recomendado declarar las variables al inicio del ámbito (scope) de ejecución, es decir, al inicio de la función.

⭐ Recomiendo que lean los artículos JavaScript Scoping and Hoisting de Benn Cherry, y JavaScript Hoisting Explained por Jeffrey Way.

A tener en cuenta

En la mayoría de los lenguajes de programación, el ámbito / alcance de una variable está en el bloque donde fue definida (block-level scope), por ejemplo, dentro de un bloque de instrucciones if, for, while; sin embargo en JavaScript no es así, puesto que el alcance de una variable es el de la función en la cual fue declarada (function-level scope).

Esto cambia con Harmony (ECMAScript 6), ya que soporta block scoping por medio de la palabra clave let, con la desventaja de que es obligatorio especificar el tipo de script a ejecutar, “application/javascript;version=1.7” (a la fecha que escribo este artículo, let no funciona en chrome 35.0.1916.153- pero sí en mozilla 29.0.1+)

Happy coding!

2 thoughts on “Hoisting en JavaScript

Comentarios

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s