///  Immediately-invoked Function Expressions (IIFE)s ///

// Nejjednodušší verze IIFE může vypadat třeba takto:

// (anonymní) bezprostředně vyvolaný funkční výraz
(function(){ /*...*/})();

// pojmenovaný bezprostředně vyvolaný funkční výraz
(function foobar(){ /*..*/}());

// "self-executing function" by vypadala spíš takto, což je velký rozdíl
function foobar(){ foobar(); }

// ------------- //

// Lehce rozšířená verze prvního příkladu může vypadat třeba takto:
var namespace = namespace || {};

// zde je objekt "namespace" předán jako parametr funkce
// k němuž dodáme patřičné metody a vlastnosti
(function( o ){
    o.foo = "foo";
    o.bar = function(){
        return "bar";
    };
})(namespace);

console.log(namespace);

// ------------- //

// namespace (jméno našeho prostoru) a undefined jsou zde předávány
// proto, abychom se ujistili, že 1. prostor bude modifikován lokálně
// a není přepisován zvnějšku
// 2. aby hodnota "undefined" byla v našem kontextu opravdu nedefinovaná.
// Důvodem jsou problémy s undefined, který ve verzích před ES5 bylo možné
// změnit.
(function ( namespace, undefined ) {

    // soukromé vlastnosti
    var foo = "foo",
        bar = "bar";

    // veřejné metody a vlastnosti
    namespace.foobar = "foobar";
    namespace.sayHello = function () {
        speak("hello world");
    };

    // soukromá metoda
    function speak(msg) {
        console.log("You said: " + msg);
    };

    // zkontrolujeme, jestli "namespace" existuje v globálním objektu window
    // pokud ne, přiřadíme do window.namespace
    // prázdný objekt
}(window.namespace = window.namespace || {});

// otestujeme veřejné metody a vlastnosti
console.log(namespace.foobar); // foobar
namescpace.sayHello(); // hello world

// přidáme nové
namespace.foobar2 = "foobar";
console.log(namespace.foobar2);


// ------------- //
// pojďme přidat nové funkce do jmenného prostoru
(function( namespace, undefined ){
    // veřejná metoda
    namespace.sayGoodbye = function(){
        console.log(namespace.foo);
        console.log(namespace.bar);
        speak('goodbye');
    }
}( window.namespace = window.namespace || {});

namespace.sayGoodbye(); //goodbye