/// 2. Zápis objektovým literálem ///
var myApplication = {
getInfo:function(){ /**/ },
// můžeme rozšířit náš objektový literál a připravit
// další vložené objekty, které mohou obsahovat
// opět cokoli:
models : {},
views : {
pages : {}
},
collections : {}
};
//Můžeme si rovněž zvolit cestu přímého přidávání vlastností do jmenného prostoru:
myApplication.foo = function(){
return "bar";
}
myApplication.utils = {
toString:function(){
/*..*/
},
export: function(){
/*..*/
}
}
// Nekontroluje existenci 'myApplication' v globálním
// jmenném prostoru. To je špatný postup, při kterém
// snadno poškodíme existující proměnnou / NS stejného jména
var myApplication = {};
/*
Následující možnosti kontrolují existenci proměnné či namespace.
Pokud je definována, použijeme ji, jinak vytvoříme nový
objektový literál myApplication.
Možnost 1: var myApplication = myApplication || {};
Možnost 2 if(!MyApplication) MyApplication = {};
Možnost 3: var myApplication = myApplication = myApplication || {}
Možnost 4: myApplication || (myApplication = {});
Možnost 5: var myApplication = myApplication === undefined ? {} : myApplication;
*/
/* Existuje samozřejmě spousta variant jak a kde použít objektové literály k organizaci a strukturování kódu. U menších aplikací, kde chcete vystavit vnořené API konkrétního uzavřeného modulu, lze použít následující techniku, kdy vracíme rozhraní, které mohou využít další vývojáři. Je to obdoba vzoru pro moduly, kde jádro vzoru tvoří IIFE (viz další text) a vrácené rozhraní je objektový literál: */
var namespace = (function () {
// definováno v lokálním scope
var privateMethod1 = function () { /* ... */ }
var privateMethod2 = function () { /* ... */ }
var privateProperty1 = 'foobar';
return {
// vrácený objekt může být zanořen
// do více úrovní, ačkoli, jak tu už zaznělo,
// je tento způsob vhodnější pro malé aplikace
// (alespoň podle mého)
publicMethod1: privateMethod1,
//zanořený jmenný prostor s veřejnou vlastností
properties:{
publicProperty1: privateProperty1
},
//testujeme další jmenný prostor
utils:{
publicMethod2: privateMethod2
}
...
}
})();
// config example
var myConfig = {
language: 'english',
defaults: {
enableGeolocation: true,
enableSharing: false,
maxPhotos: 20
},
theme: {
skin: 'a',
toolbars: {
index: 'ui-navigation-toolbar',
pages: 'ui-custom-toolbar'
}
}
}
/// 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
/// 5. Namespace injection , něco jako DI ///
var myApp = myApp || {};
myApp.utils = {};
(function() {
var val = 5;
this.getValue = function() {
return val;
};
this.setValue = function(newVal) {
val = newVal;
}
// přidáme také nový jmenný prostor
this.tools = {};
}).apply(myApp.utils);
// Přidáme novou funkci do prostoru tools
// který jsme definovali výše
(function(){
this.diagnose = function(){
return 'diagnosis';
}
}).apply(myApp.utils.tools);
// všimněte si, že stejný postup může být použitý
// i u obyčejného IIFE, kdy předáme kontext jako parametr
// a budeme modifikovat tento kontext namísto implicitního
// 'this'
// testy
console.log(myApp); //the now populated namespace
console.log(myApp.utils.getValue()); // test get
myApp.utils.setValue(25); // test set
console.log(myApp.utils.getValue());
console.log(myApp.utils.tools.diagnose());