Como segunda parte de Alcance de Variables vamos a ver como se comportan las funciones.

En la parte 1 vimos que las declaraciones de variables son alzadas al principio de la función por el interpretador. Bueno, las declaraciones de funciones también lo son.

function miFunction(){
    foo();

    function foo(){
       console.log('foo fue llamada!');
    }
}
 

De la misma manera que en la declaracion de variables, el interpretador alzó la declaracion de la función foo al principio:

function miFunction(){
    function foo(){
       console.log('foo fue llamada!');
    }

    foo();
}
 

En javascript podemos asignar funciones a variables, ya sean anónimas o nombradas, donde el alzado del interpretador puede ser un poco confuso.

Función Anónima

function miFuncion(){
    foo(); // TypeError "foo no es una función"


    // Expresion de función anónima

    var foo = function () {
        console.log('función llamada!');
    };

    foo(); // resulta en: función llamada!

}
 

Lo que pasó en ese caso es que el interpretador alzó la declaracion de la variable foo, pero no así su asignación:

function miFuncion(){
    var foo;
    foo(); // simplemente es una variable! foo === undefined


    foo = function () {
        console.log('función llamada!');
    };

    foo(); // ahora sí es una función

}
 

Función Nombrada

function miFuncion(){
    foo(); // TypeError "foo no es una función"

    baz(); // ReferenceError "baz no está definida"


    // Expresion de función nombrada asignada a una variable

    var foo = function baz() {
        console.log('función llamada!');
    };

    foo(); // resulta en: función llamada!

    baz(); // ReferenceError "baz no está definida"

}
 

Sucede lo mismo, con la diferencia que no podemos llamar a la función nombrada desde afuera ya que su alcance no se encuentra en nuestra función, es decir, baz directamente no fue alzada porque ni siquiera se encuentra al alcance de miFuncion, no sabe que existe.
Veamos como fue interpretado:

function miFuncion(){
    var foo;
    foo(); // simplemente no es una función todavía.

    baz(); // baz no existe, no fue declarada.


    foo = function baz() {
        console.log('función llamada!');
    };

    foo(); // ahora sí es una función.

    baz(); // sigue sin existir en este alcance.

}
 

Como escribir código conociendo todo esto?

Entender como es interpretado nuestro código nos ayuda a ser mas cautelosos al desarrollar evitando problemas futuros. Mi recomendación es que intenten tener un solo var al principio de cada función con todas las declaraciones, ya que al fin y al cabo, va a ser interpretado de la misma manera.

Por último les dejo traducido lo que dice el standard ECMAScript Standard (pdf):

Si la declaración de la variable se produce dentro de una función, las variables se definen con alcance local en esa función. De lo contrario, se definen con un alcance global (es decir, se crean como los miembros del objeto global). Las variables se crean cuando el ámbito de ejecución está introducido. Un bloque no define un nuevo alcance de ejecución. Sólo program y function producen un nuevo alcance. Las variables se inicializan en undefined cuando se crean. Una variable con un inicializador se le asigna el valor cuando la instrucción se ejecuta, no cuando la variable se crea.