JavaScriptandUIArchitectureBestPracticesSiarheiBarysiuks.barysiuk@sam-solutions.netOurroadmapIntroduction:Whatwillwecovertoday?•CodingpatternsJavaScript-specificbestpractices•DesignpatternsLanguageindependentpatterns,UIarchitectureCodingpatternsNamespacesTipoftheday“Globalvariablesshouldbeavoidedinordertolowerthepossibilityofvariablenamingcollisions.“Namespaces:Definingnamespace//definingtop-levelpackagevarMyApp=MyApp||{};//definingpackageMyApp.string=MyApp.string||{};//definingpackageMyApp.string.utils={ trim:function(str){ //codegoeshere }, reverse:function(str){ //codegoeshere }};//definingpackageMyApp.dom={ addEventListener:function(element,callback){ //codegoeshere }, removeEventListener:function(element,callback){ //codegoeshere } };Namespaces:UsageincodeMyApp.string.utils.reverse(...);MyApp.string.utils.trim(...);MyApp.dom.addEventListener(...);MyApp.dom.removeEventListener(...);Namespaces:namespace()function//definingtop-levelpackagevarMyApp=MyApp||{};//definespackagestructureMyApp.namespace=function(name){ if(name){ //somechecksifnameisvalid varnames=name.split(.); varcurrent=MyApp; for(variinnames){ if(!current[names[i]]){ current[names[i]]={}; } current=current[names[i]]; } returntrue; } returnfalse;};Namespaces:Definingnamespace//definingtop-levelpackagevarMyApp=MyApp||{};//definingpackageMyApp.string=MyApp.string||{};//definingpackageMyApp.string.utils={ trim:function(str){ //codegoeshere }, reverse:function(str){ //codegoeshere }};//definingpackageMyApp.namespace(string.utils);//definingpackageMyApp.string.utils.trim=function(str){ //codegoeshere console.log(trim); }; MyApp.string.utils.reverse=function(str){ //codegoeshere console.log(reverse); };Questions?Init-timebranchingTipoftheday“Branchsomepartsofthebrowser-specificcodeduringinitialization,whenthescriptloads,ratherthanduringruntimetoavoidperformancehit.”Init-timebranching:Definingbrowser-specificmethodsMyApp.namespace(dom);MyApp.dom.addListener=null;//allmajorbrowsersif(typeofwindow.addEventListener==='function'){ MyApp.dom.addListener=function(el,type,fn){el.addEventListener(type,fn,false);};}//IEelseif(typeofdocument.attachEvent==='function'){ MyApp.dom.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);};}//olderbrowserselse{ MyApp.dom.addListener=function(el,type,fn){el['on'+type]=fn;};}Questions?LazydefinitionTipoftheday“Thelazydefinitionpatternisverysimilartothepreviousinit-timebranchingpattern.Thedifferenceisthatthebranchinghappensonlywhenthefunctioniscalledforthefirsttime.”Lazydefinition:Definingbrowser-specificmethodsvarMyApp=MyApp||{};MyApp.dom={addListener:function(el,type,fn){if(typeofel.addEventListener==='function'){MyApp.dom.addListener=function(el,type,fn){el.addEventListener(type,fn,false);};}elseif(typeofel.attachEvent==='function'){MyApp.dom.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);};}else{MyApp.dom.addListener=function(el,type,fn){el['on'+type]=fn;};}MyApp.dom.addListener(el,type,fn);}};OverridefunctionfirsttimeQuestions?ConfigurationobjectTipoftheday“Insteadofhavingmanyparameters,youcanuseoneparameterandmakeitanobject.Thepropertiesoftheobjectaretheactualparameters.”varMyApp=MyApp||{};MyApp.namespace(dom);MyApp.dom.Button=function(text,type){//somecodehere}Configurationobject:OrdinaryconstructorMyApp.dom.Button=function(text,type,color,border,font){//somecodehere}Configurationobject:UsageofconfigurationobjectvarMyApp=MyApp||{};MyApp.namespace(dom);MyApp.dom.Button=function(text,settings){ vartype=settings.type||'submit'; varfont=settings.font||'Verdana'; //..otherprops //somecodehere}Questions?PrivatepropertiesandmethodsTipoftheday“Uselocalvariablesandmethodsinsideaconstructortoachievethe“private”levelofprotection.Usenamingconventions_doInternalOperationtoshowthatthefunctionisprivate/protected.”varMyApp=MyApp||{};MyApp.namespace(dom);MyApp.dom.Button=function(text,settings){ //..processproperties functionsetStyle(element,settings){ //settingstyletoelement }; varbutton=//... //.. setStyle(button,settings); this.clone=function(){ varclonedButton=//... //... setStyle(clonedButton,settings); } //somecodehere}Privatemethodsandproperties:PrivatemethodQuestions?Self-executingfunctionsTipoftheday“Self-executingfunctionsareespeciallysuitableforone-offinitializationtasksperformedwhenthescriptloads.”(function(){ //codegoeshere})();Self-executingfunctions:Usage(function(){ //... varjQuery=window.jQuery=window.$=function(selector,context){ //... returnnewjQuery.fn.init(selector,context); }; //... jQuery.fn=jQuery.prototype={ init:function(){ //... } }; })();Questions?ChainingTipoftheday“Prettyconvenientwaytocallseveralrelatedmethodsononelineasifthemethodsarethelinksinachain.”varobj=newMyApp.dom.Element('span');obj.setText('hello');obj.setStyle('color','red');obj.setStyle('font','Verdana');document.body.appendChild(obj);Chaining:Usagevarobj=newMyApp.dom.Element('span');obj.setText('hello').setStyle('color','red').setStyle('font','Verdana');document.body.appendChild(obj);