javascript. Подъем функций

В javascript функцию можно построить либо на объявлении

function foo() {
  //...
}

либо на выражении

var bar = function () {
  //...
};

Функции-выражения подчеркивают тот факт, что они являются объектами. Вроде бы на этом отличий нет, но это не так. Выполним следующий кусок кода.

foo();

function foo() {
    console.log('function - declaration');
}


На выходе получим сообщение - function - declaration - то есть несмотря на то, что функция определена ниже места ее вызова, интерпретатор без проблем выполнит ее, это называется подъемом функций. Попробуем выполнить такой же кусочек, но только на основе функции-выражения.

foo();

var foo = function () {
    console.log('function - expression');
};


Хоп, на выходе получаем сообщение об ошибке

TypeError: foo is not a function

То есть в данном случае поднятия определения функции не произошло, в отличии от имени. Вот еще пример с поднятием. И в этом случае :

foo();

function foo() {
    console.log('function - declaration');
}

var foo = function foo() {
    console.log('function - expression');
};


и в этом:

foo();

var foo = function foo() {
    console.log('function - expression');
};

function foo() {
    console.log('function - declaration');
}


мы будем получать сообщение - function - declaration. Но вот если вызов происходит ниже, то картина меняется на оборот:

var foo = function foo() {
    console.log('function - expression');
};

function foo() {
    console.log('function - declaration');
}

foo();


или вот так:

function foo() {
    console.log('function - declaration');
}

var foo = function foo() {
    console.log('function - expression');
};

foo();


мы будем получать сообщение - function - expression.
Правило подъема действует и внутри самих функций. Вот небольшой примерчик:

bar();

function bar() {


    (function (global) {
        global.foo();
        foo();
    })(window);
   
    function foo() {
        console.log('local function - declaration');
    }

   
}

function foo() {
    console.log('global function - declaration');
}


На выходе получим следующие сообщения:

global function - declaration
local function - declaration
global function - declaration
local function - declaration
global function - declaration
local function - declaration