Você está na página 1de 188

26/04/2015 LearningJavaScriptDesignPatterns

LearningJavaScriptDesignPatterns
AbookbyAddyOsmani

Volume1.6.2

Tweet 7,895

CopyrightAddyOsmani2015.

LearningJavaScriptDesignPatternsisreleasedunderaCreativeCommonsAttributionNoncommercial
NoDerivativeWorks3.0unportedlicense.ItisavailableforpurchaseviaOReillyMediabutwill
remainavailableforbothfreeonlineandasaphysical(oreBook)purchaseforreaderswishingto
supporttheproject.

Preface
Designpatternsarereusablesolutionstocommonlyoccurringproblemsinsoftwaredesign.Theyare
bothexcitingandafascinatingtopictoexploreinanyprogramminglanguage.

Onereasonforthisisthattheyhelpusbuilduponthecombinedexperienceofmanydevelopersthat

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 1/188
26/04/2015 LearningJavaScriptDesignPatterns

camebeforeusandensurewestructureourcodeinanoptimizedway,meetingtheneedsofproblems
wereattemptingtosolve.

Designpatternsalsoprovideusacommonvocabularytodescribesolutions.Thiscanbesignificantly
simplerthandescribingsyntaxandsemanticswhenwereattemptingtoconveyawayofstructuringa
solutionincodeformtoothers.

InthisbookwewillexploreapplyingbothclassicalandmoderndesignpatternstotheJavaScript
programminglanguage.

TargetAudience
Thisbookistargetedatprofessionaldeveloperswishingtoimprovetheirknowledgeofdesignpatterns
andhowtheycanbeappliedtotheJavaScriptprogramminglanguage.

Someoftheconceptscovered(closures,prototypalinheritance)willassumealevelofbasicprior
knowledgeandunderstanding.Ifyoufindyourselfneedingtoreadfurtheraboutthesetopics,alistof
suggestedtitlesisprovidedforconvenience.

Ifyouwouldliketolearnhowtowritebeautiful,structuredandorganizedcode,Ibelievethisisthe
bookforyou.

Acknowledgments
Iwillalwaysbegratefulforthetalentedtechnicalreviewerswhohelpedreviewandimprovethisbook,
includingthosefromthecommunityatlarge.Theknowledgeandenthusiasmtheybroughttothe
projectwassimplyamazing.Theofficialtechnicalreviewerstweetsandblogsarealsoaregularsource
ofbothideasandinspirationandIwholeheartedlyrecommendcheckingthemout.

NicholasZakas(http://nczonline.net,@slicknet)
AndreHansson(http://andreehansson.se,@peolanha)
LukeSmith(http://lucassmith.name,@ls_n)
EricFerraiuolo(http://ericf.me/,@ericf)
PeterMichaux(http://michaux.ca,@petermichaux)
AlexSexton(http://alexsexton.com,@slexaxton)

IwouldalsoliketothankRebeccaMurphey(http://rmurphey.com,@rmurphey)forprovidingthe
inspirationtowritethisbookandmoreimportantly,continuetomakeitbothavailableonGitHuband
viaOReilly.

Finally,IwouldliketothankmywonderfulwifeEllie,forallofhersupportwhileIwasputting
togetherthispublication.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 2/188
26/04/2015 LearningJavaScriptDesignPatterns

Credits
Whilstsomeofthepatternscoveredinthisbookwereimplementedbasedonpersonalexperience,many
ofthemhavebeenpreviouslyidentifiedbytheJavaScriptcommunity.Thisworkisassuchthe
productionofthecombinedexperienceofanumberofdevelopers.SimilartoStoyanStefanovslogical
approachtopreventinginterruptionofthenarrativewithcredits(inJavaScriptPatterns),Ihavelisted
creditsandsuggestedreadingforanycontentcoveredinthereferencessection.

Ifanyarticlesorlinkshavebeenmissedinthelistofreferences,pleaseacceptmyheartfeltapologies.If
youcontactmeIllbesuretoupdatethemtoincludeyouonthelist.

Reading
Whilstthisbookistargetedatbothbeginnersandintermediatedevelopers,abasicunderstandingof
JavaScriptfundamentalsisassumed.Shouldyouwishtolearnmoreaboutthelanguage,Iamhappyto
recommendthefollowingtitles:

JavaScript:TheDefinitiveGuidebyDavidFlanagan
EloquentJavaScriptbyMarijnHaverbeke
JavaScriptPatternsbyStoyanStefanov
WritingMaintainableJavaScriptbyNicholasZakas
JavaScript:TheGoodPartsbyDouglasCrockford

TableOfContents
Introduction
WhatisaPattern?
PatternityTesting,ProtoPatterns&TheRuleOfThree
TheStructureOfADesignPattern
WritingDesignPatterns
AntiPatterns
CategoriesOfDesignPattern
SummaryTableOfDesignPatternCategorization
JavaScriptDesignPatterns
ConstructorPattern
ModulePattern
RevealingModulePattern
SingletonPattern
ObserverPattern
MediatorPattern
PrototypePattern
CommandPattern
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 3/188
26/04/2015 LearningJavaScriptDesignPatterns

FacadePattern
FactoryPattern
MixinPattern
DecoratorPattern
FlyweightPattern
JavaScriptMV*Patterns
MVCPattern
MVPPattern
MVVMPattern
ModernModularJavaScriptDesignPatterns
AMD
CommonJS
ESHarmony
DesignPatternsInjQuery
CompositePattern
AdapterPattern
FacadePattern
ObserverPattern
IteratorPattern
LazyInitializationPattern
ProxyPattern
BuilderPattern
jQueryPluginDesignPatterns
JavaScriptNamespacingPatterns
Conclusions
References

Introduction
Oneofthemostimportantaspectsofwritingmaintainablecodeisbeingabletonoticetherecurring
themesinthatcodeandoptimizethem.Thisisanareawhereknowledgeofdesignpatternscanprove
invaluable.

Inthefirstpartofthisbook,wewillexplorethehistoryandimportanceofdesignpatternswhichcan
reallybeappliedtoanyprogramminglanguage.Ifyourealreadysoldonorarefamiliarwiththis
history,feelfreetoskiptothechapterWhatisaPattern?tocontinuereading.

DesignpatternscanbetracedbacktotheearlyworkofanarchitectnamedChristopherAlexander.He
wouldoftenwritepublicationsabouthisexperienceinsolvingdesignissuesandhowtheyrelatedto
buildingsandtowns.Oneday,itoccurredtoAlexanderthatwhenusedtimeandtimeagain,certain
designconstructsleadtoadesiredoptimaleffect.

IncollaborationwithSaraIshikawaandMurraySilverstein,Alexanderproducedapatternlanguage
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 4/188
26/04/2015 LearningJavaScriptDesignPatterns

thatwouldhelpempoweranyonewishingtodesignandbuildatanyscale.Thiswaspublishedbackin
1977inapapertitledAPatternLanguage,whichwaslaterreleasedasacompletehardcoverbook.

Some30yearsago,softwareengineersbegantoincorporatetheprinciplesAlexanderhadwrittenabout
intothefirstdocumentationaboutdesignpatterns,whichwastobeaguidefornovicedevelopers
lookingtoimprovetheircodingskills.Itsimportanttonotethattheconceptsbehinddesignpatterns
haveactuallybeenaroundintheprogrammingindustrysinceitsinception,albeitinalessformalized
form.

Oneofthefirstandarguablymosticonicformalworkspublishedondesignpatternsinsoftware
engineeringwasabookin1995calledDesignPatterns:ElementsOfReusableObjectOrientedSoftware.This
waswrittenbyErichGamma,RichardHelm,RalphJohnsonandJohnVlissidesagroupthatbecame
knownastheGangofFour(orGoFforshort).

TheGoFspublicationisconsideredquiteinstrumentaltopushingtheconceptofdesignpatternsfurther
inourfieldasitdescribesanumberofdevelopmenttechniquesandpitfallsaswellasprovidingtwenty
threecoreObjectOrienteddesignpatternsfrequentlyusedaroundtheworldtoday.Wewillbecovering
thesepatternsinmoredetailinthesectionCategoriesofDesignPatterns.

Inthisbook,wewilltakealookatanumberofpopularJavaScriptdesignpatternsandexplorewhy
certainpatternsmaybemoresuitableforyourprojectsthanothers.Rememberthatpatternscanbe
appliednotjusttovanillaJavaScript(i.estandardJavaScriptcode),butalsotoabstractedlibrariessuch
asjQueryordojoaswell.Beforewebegin,letslookattheexactdefinitionofapatterninsoftware
design.

WhatisaPattern?
Apatternisareusablesolutionthatcanbeappliedtocommonlyoccurringproblemsinsoftwaredesign
inourcaseinwritingJavaScriptwebapplications.Anotherwayoflookingatpatternsareas
templatesforhowwesolveproblemsoneswhichcanbeusedinquiteafewdifferentsituations.

So,whyisitimportanttounderstandpatternsandbefamiliarwiththem?Designpatternshavethree
mainbenefits:

1. Patternsareprovensolutions:Theyprovidesolidapproachesto
solvingissuesinsoftwaredevelopmentusingproventechniquesthat
reflecttheexperienceandinsightsthedevelopersthathelpeddefine
thembringtothepattern.
2. Patternscanbeeasilyreused:Apatternusuallyreflectsanoutofthe
boxsolutionthatcanbeadaptedtosuitourownneeds.Thisfeature
makesthemquiterobust.
3. Patternscanbeexpressive:Whenwelookatapatterntheresgenerally

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 5/188
26/04/2015 LearningJavaScriptDesignPatterns

asetstructureandvocabularytothesolutionpresentedthatcanhelp
expressratherlargesolutionsquiteelegantly.

Patternsarenotanexactsolution.Itsimportantthatweremembertheroleofapatternismerelyto
provideuswithasolutionscheme.Patternsdontsolvealldesignproblemsnordotheyreplacegood
softwaredesigners,however,theydosupportthem.Nextwelltakealookatsomeoftheother
advantagespatternshavetooffer.

Reusingpatternsassistsinpreventingminorissuesthatcancausemajorproblemsinthe
applicationdevelopmentprocess.Whatthismeansiswhencodeisbuiltonprovenpatterns,
wecanaffordtospendlesstimeworryingaboutthestructureofourcodeandmoretime
focusingonthequalityofouroverallsolution.Thisisbecausepatternscanencourageusto
codeinamorestructuredandorganizedfashionavoidingtheneedtorefactoritfor
cleanlinesspurposesinthefuture.
Patternscanprovidegeneralizedsolutionswhicharedocumentedinafashionthatdoesnt
requirethemtobetiedtoaspecificproblem.Thisgeneralizedapproachmeansthat
regardlessoftheapplication(andinmanycasestheprogramminglanguage)weareworking
with,designpatternscanbeappliedtoimprovethestructureofourcode.
Certainpatternscanactuallydecreasetheoverallfilesizefootprintofourcodeby
avoidingrepetition.Byencouragingdeveloperstolookmorecloselyattheirsolutionsfor
areaswhereinstantreductionsinrepetitioncanbemade,e.g.reducingthenumberof
functionsperformingsimilarprocessesinfavorofasinglegeneralizedfunction,theoverall
sizeofourcodebasecanbedecreased.ThisisalsoknownasmakingcodemoreDRY.
Patternsaddtoadevelopersvocabulary,whichmakescommunicationfaster.
Patternsthatarefrequentlyusedcanbeimprovedovertimebyharnessingthecollective
experiencesotherdevelopersusingthosepatternscontributebacktothedesignpattern
community.Insomecasesthisleadstothecreationofentirelynewdesignpatternswhilstin
othersitcanleadtotheprovisionofimprovedguidelinesonhowspecificpatternscanbe
bestused.Thiscanensurethatpatternbasedsolutionscontinuetobecomemorerobustthan
adhocsolutionsmaybe.

Wealreadyusepatternseveryday
Tounderstandhowusefulpatternscanbe,letsreviewaverysimpleelementselectionproblemthatthe
jQuerylibrarysolvesforus.

ImaginethatwehaveascriptwhereforeachDOMelementfoundonapagewithclassfoowewishto
incrementacounter.Whatsthemostefficientwaytoqueryforthiscollectionofelements?Well,there
areafewdifferentwaysthisproblemcouldbetackled:

1. Selectalloftheelementsinthepageandthenstorereferencestothem.Next,filterthis
collectionanduseregularexpressions(oranothermeans)toonlystorethosewiththeclass
foo.
2. Useamodernnativebrowserfeaturesuchas querySelectorAll() toselectalloftheelements
withtheclassfoo.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 6/188
26/04/2015 LearningJavaScriptDesignPatterns

3. Useanativefeaturesuchas getElementsByClassName() tosimilarlygetbackthedesired


collection.

So,whichoftheseoptionsisthefastest?Itsactuallyoption3.byafactorof810timesthealternatives.
Inarealworldapplicationhowever,3.willnotworkinversionsofInternetExplorerbelow9andthus
itsnecessarytouse1.whereboth2.and3.arentsupported.

DevelopersusingjQuerydonthavetoworryaboutthisproblemhowever,asitsluckilyabstracted
awayforususingtheFacadepattern.Aswellreviewinmoredetaillater,thispatternprovidesasimple
setofabstractedinterfaces(e.g $el.css() , $el.animate() )toseveralmorecomplexunderlyingbodiesof
code.Asweveseen,thismeanslesstimehavingtobeconcernedaboutimplementationleveldetails.

Behindthescenes,thelibrarysimplyoptsforthemostoptimalapproachtoselectingelements
dependingonwhatourcurrentbrowsersupportsandwejustconsumetheabstractionlayer.

WereprobablyallalsofamiliarwithjQuerys $("selector") .Thisissignificantlymoreeasytousefor


selectingHTMLelementsonapageversushavingtomanuallyoptfor getElementById() ,
getElementsByClassName() , getElementByTagName() andsoon.

Althoughweknowthat querySelectorAll() attemptstosolvethisproblem,comparetheeffortinvolved


inusingjQuerysFacadeinterfacesvs.selectingthemostoptimalselectionpathsourselves.Theresno
contest!Abstractionsusingpatternscanofferrealworldvalue.

Wellbelookingatthisandmoredesignpatternslateroninthebook.

PatternityTesting,Proto
Patterns&TheRuleOfThree
Rememberthatnoteveryalgorithm,bestpracticeorsolutionrepresentswhatmightbeconsidereda
completepattern.Theremaybeafewkeyingredientsherethataremissingandthepatterncommunity
isgenerallywaryofsomethingclaimingtobeoneunlessithasbeenheavilyvetted.Evenifsomethingis
presentedtouswhichappearstomeetthecriteriaforapattern,itshouldnotbeconsideredoneuntilit
hasundergonesuitableperiodsofscrutinyandtestingbyothers.

LookingbackupontheworkbyAlexanderoncemore,heclaimsthatapatternshouldbothbeaprocess
andathing.Thisdefinitionisobtuseonpurposeashefollowsbysayingthatitistheprocesswhich
shouldcreatethething.Thisisareasonwhypatternsgenerallyfocusonaddressingavisually
identifiablestructurei.eweshouldbeabletovisuallydepict(ordraw)apicturerepresentingthe
structurethatplacingthepatternintopracticeresultsin.

Instudyingdesignpatterns,itsnotirregulartocomeacrossthetermprotopattern.Whatisthis?Well,
apatternthathasnotyetbeenknowntopassthepatternitytestsisusuallyreferredtoasaproto
pattern.Protopatternsmayresultfromtheworkofsomeonethathasestablishedaparticularsolution

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 7/188
26/04/2015 LearningJavaScriptDesignPatterns

thatisworthyofsharingwiththecommunity,butmaynothaveyethadtheopportunitytohavebeen
vettedheavilyduetoitsveryyoungage.

Alternatively,theindividual(s)sharingthepatternmaynothavethetimeorinterestofgoingthrough
thepatternityprocessandmightreleaseashortdescriptionoftheirprotopatterninstead.Brief
descriptionsorsnippetsofthistypeofpatternareknownaspatlets.

Theworkinvolvedinfullydocumentingaqualifiedpatterncanbequitedaunting.Lookingbackat
someoftheearliestworkinthefieldofdesignpatterns,apatternmaybeconsideredgoodifitdoes
thefollowing:

Solvesaparticularproblem:Patternsarenotsupposedtojustcaptureprinciplesor
strategies.Theyneedtocapturesolutions.Thisisoneofthemostessentialingredientsfora
goodpattern.
Thesolutiontothisproblemcannotbeobvious:Wecanfindthatproblemsolving
techniquesoftenattempttoderivefromwellknownfirstprinciples.Thebestdesignpatterns
usuallyprovidesolutionstoproblemsindirectlythisisconsideredanecessaryapproachfor
themostchallengingproblemsrelatedtodesign.
Theconceptdescribedmusthavebeenproven:Designpatternsrequireproofthatthey
functionasdescribedandwithoutthisproofthedesigncannotbeseriouslyconsidered.Ifa
patternishighlyspeculativeinnature,onlythebravemayattempttouseit.
Itmustdescribearelationship:Insomecasesitmayappearthatapatterndescribesatype
ofmodule.Althoughanimplementationmayappearthisway,theofficialdescriptionofthe
patternmustdescribemuchdeepersystemstructuresandmechanismsthatexplainits
relationshiptocode.

Wewouldbeforgivenforthinkingthataprotopatternwhichfailstomeetguidelinesisntworth
learningfrom,however,thisisfarfromthetruth.Manyprotopatternsareactuallyquitegood.Imnot
sayingthatallprotopatternsareworthlookingat,buttherearequiteafewusefulonesinthewildthat
couldassistuswithfutureprojects.Usebestjudgmentwiththeabovelistinmindandyoullbefinein
yourselectionprocess.

Oneoftheadditionalrequirementsforapatterntobevalidisthattheydisplaysomerecurring
phenomenon.Thisisoftensomethingthatcanbequalifiedinatleastthreekeyareas,referredtoasthe
ruleofthree.Toshowrecurrenceusingthisrule,onemustdemonstrate:

1. Fitnessofpurposehowisthepatternconsideredsuccessful?
2. Usefulnesswhyisthepatternconsideredsuccessful?
3. Applicabilityisthedesignworthyofbeingapatternbecauseithaswiderapplicability?If
so,thisneedstobeexplained.Whenreviewingordefiningapattern,itisimportanttokeep
theaboveinmind.

TheStructureOfADesignPattern
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 8/188
26/04/2015 LearningJavaScriptDesignPatterns

Youmaybecuriousabouthowapatternauthormightapproachoutliningstructure,implementation
andpurposeofanewpattern.Apatternisinitiallypresentedintheformofarulethatestablishesa
relationshipbetween:

Acontext
Asystemofforcesthatarisesinthatcontextand
Aconfigurationthatallowstheseforcestoresolvethemselvesincontext

Withthisinmind,letsnowtakealookatasummaryofthecomponentelementsforadesignpattern.A
designpatternshouldhavea:

Patternnameandadescription
Contextoutlinethecontextsinwhichthepatterniseffectiveinrespondingtotheusers
needs.
Problemstatementastatementoftheproblembeingaddressedsowecanunderstandthe
intentofthepattern.
Solutionadescriptionofhowtheusersproblemisbeingsolvedinanunderstandablelist
ofstepsandperceptions.
Designadescriptionofthepatternsdesignandinparticular,theusersbehaviorin
interactingwithit
Implementationaguidetohowthepatternwouldbeimplemented
Illustrationsavisualrepresentationofclassesinthepattern(e.g.adiagram))
Examplesanimplementationofthepatterninaminimalform
Corequisiteswhatotherpatternsmaybeneededtosupportuseofthepatternbeing
described?
Relationswhatpatternsdoesthispatternresemble?doesitcloselymimicanyothers?
Knownusageisthepatternbeingusedinthewild?Ifso,whereandhow?
Discussionstheteamorauthorsthoughtsontheexcitingbenefitsofthepattern

Designpatternsarequiteapowerfulapproachtogettingallofthedevelopersinanorganizationor
teamonthesamepagewhencreatingormaintainingsolutions.Ifconsideringworkingonapatternof
yourown,rememberthatalthoughtheymayhaveaheavyinitialcostintheplanningandwriteup
phases,thevaluereturnedfromthatinvestmentcanbequiteworthit.Alwaysresearchthoroughly
beforeworkingonnewpatternshowever,asyoumayfinditmorebeneficialtouseorbuildontopof
existingprovenpatternsthanstartingafresh.

WritingDesignPatterns
Althoughthisbookisaimedatthosenewtodesignpatterns,afundamentalunderstandingofhowa
designpatterniswrittencanofferanumberofusefulbenefits.Forstarters,wecangainadeeper
appreciationforthereasoningbehindwhyapatternisneeded.Wecanalsolearnhowtotellifapattern
(orprotopattern)isuptoscratchwhenreviewingitforourownneeds.

Writinggoodpatternsisachallengingtask.Patternsnotonlyneedto(ideally)provideasubstantial

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 9/188
26/04/2015 LearningJavaScriptDesignPatterns

quantityofreferencematerialforendusers,buttheyalsoneedtobeabletodefendwhytheyare
necessary.

Havingreadtheprevioussectiononwhatapatternis,wemaythinkthatthisinitselfisenoughtohelp
usidentifypatternsweseeinthewild.Thisisactuallynotcompletelytrue.Itsnotalwaysclearifa
pieceofcodewerelookingatisfollowingasetpatternorjustaccidentallyhappenstoappearlikeit
does.

Whenwerelookingatabodyofcodewethinkmaybeusingapattern,weshouldconsiderwriting
downsomeoftheaspectsofthecodethatwebelievefallsunderaparticularexistingpatternorsetof
patterns.

Inmanycasesofpatternanalysiswecanfindthatwerejustlookingatcodethatfollowsgood
principlesanddesignpracticesthatcouldhappentooverlapwiththerulesforapatternbyaccident.
Remembersolutionsinwhichneitherinteractionsnordefinedrulesappeararenotpatterns.

IfinterestedinventuringdownthepathofwritingyourowndesignpatternsIrecommendlearning
fromotherswhohavealreadybeenthroughtheprocessanddoneitwell.Spendtimeabsorbingthe
informationfromanumberofdifferentdesignpatterndescriptionsandtakeinwhatsmeaningfulto
you.

Explorestructureandsemanticsthiscanbedonebyexaminingtheinteractionsandcontextofthe
patternsyouareinterestedinsoyoucanidentifytheprinciplesthatassistinorganizingthosepatterns
togetherinusefulconfigurations.

Onceweveexposedourselvestoawealthofinformationonpatternliterature,wemaywishtobegin
writingourpatternusinganexistingformatandseeifwecanbrainstormnewideasforimprovingitor
integratingourideasinthere.

AnexampleofadeveloperthatdidthisisinrecentyearsisChristianHeilmann,whotooktheexisting
ModulepatternandmadesomefundamentallyusefulchangestoittocreatetheRevealingModulepattern
(thisisoneofthepatternscoveredlaterinthisbook).

ThefollowingaretipsIwouldsuggestifinterestedincreatinganewdesignpattern:

Howpracticalisthepattern?:Ensurethepatterndescribesprovensolutionstorecurring
problemsratherthanjustspeculativesolutionswhichhaventbeenqualified.
Keepbestpracticesinmind:Thedesigndecisionswemakeshouldbebasedonprinciples
wederivefromanunderstandingofbestpractices.
Ourdesignpatternsshouldbetransparenttotheuser:Designpatternsshouldbeentirely
transparenttoanytypeofuserexperience.Theyareprimarilytheretoservethedevelopers
usingthemandshouldnotforcechangestobehaviorintheuserexperiencethatwouldnot
beincurredwithouttheuseofapattern.
Rememberthatoriginalityisnotkeyinpatterndesign:Whenwritingapattern,wedonot
needtobetheoriginaldiscovererofthesolutionsbeingdocumentednordoyouhaveto
worryaboutourdesignoverlappingwithminorpiecesofotherpatterns.Iftheapproachis
strongenoughtohavebroadusefulapplicability,ithasachanceofbeingrecognizedasa

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 10/188
26/04/2015 LearningJavaScriptDesignPatterns

validpattern.
Patternneedastrongsetofexamples:Agoodpatterndescriptionneedstobefollowedby
anequallystrongsetofexamplesdemonstratingthesuccessfulapplicationofourpattern.To
showbroadusage,examplesthatexhibitgooddesignprinciplesareideal.

Patternwritingisacarefulbalancebetweencreatingadesignthatisgeneral,specificandaboveall,
useful.Trytoensurethatifwritingapatternyoucoverthewidestpossibleareasofapplicationandyou
shouldbefine.Ihopethatthisbriefintroductiontowritingpatternshasgivenyousomeinsightsthat
willassistyourlearningprocessforthenextsectionsofthisbook.

AntiPatterns
Ifweconsiderthatapatternrepresentsabestpractice,anantipatternrepresentsalessonthathasbeen
learned.Thetermantipatternswascoinedin1995byAndrewKoenigintheNovemberC++Reportthat
year,inspiredbytheGoFsbookDesignPatterns.InKoenigsreport,therearetwonotionsofanti
patternsthatarepresented.AntiPatterns:

Describeabadsolutiontoaparticularproblemwhichresultedinabadsituationoccurring
Describehowtogetoutofsaidsituationandhowtogofromtheretoagoodsolution

Onthistopic,Alexanderwritesaboutthedifficultiesinachievingagoodbalancebetweengooddesign
structureandgoodcontext:

Thesenotesareabouttheprocessofdesign;theprocessofinventingphysicalthingswhichdisplayanewphysical
order,organization,form,inresponsetofunction.everydesignproblembeginswithanefforttoachievefitness
betweentwoentities:theforminquestionanditscontext.Theformisthesolutiontotheproblem;thecontext
definestheproblem.

Whileitsquiteimportanttobeawareofdesignpatterns,itcanbeequallyimportanttounderstandanti
patterns.Letusqualifythereasonbehindthis.Whencreatinganapplication,aprojectslifecyclebegins
withconstructionhoweveronceyouvegottheinitialreleasedone,itneedstobemaintained.The
qualityofafinalsolutionwilleitherbegoodorbad,dependingonthelevelofskillandtimetheteam
haveinvestedinit.Heregoodandbadareconsideredincontextaperfectdesignmayqualifyasan
antipatternifappliedinthewrongcontext.

Thebiggerchallengeshappenafteranapplicationhashitproductionandisreadytogointo
maintenancemode.Adeveloperworkingonsuchasystemwhohasntworkedontheapplication
beforemayintroduceabaddesignintotheprojectbyaccident.Ifsaidbadpracticesarecreatedasanti
patterns,theyallowdevelopersameanstorecognizetheseinadvancesothattheycanavoidcommon
mistakesthatcanoccurthisisparalleltothewayinwhichdesignpatternsprovideuswithawayto
recognizecommontechniquesthatareuseful.

Tosummarize,anantipatternisabaddesignthatisworthyofdocumenting.Examplesofantipatterns
inJavaScriptarethefollowing:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 11/188
26/04/2015 LearningJavaScriptDesignPatterns

Pollutingtheglobalnamespacebydefiningalargenumberofvariablesintheglobalcontext
PassingstringsratherthanfunctionstoeithersetTimeoutorsetIntervalasthistriggersthe
useof eval() internally.
Modifyingthe Object classprototype(thisisaparticularlybadantipattern)
UsingJavaScriptinaninlineformasthisisinflexible
Theuseofdocument.writewherenativeDOMalternativessuchasdocument.createElement
aremoreappropriate.document.writehasbeengrosslymisusedovertheyearsandhasquite
afewdisadvantagesincludingthatifitsexecutedafterthepagehasbeenloadeditcan
actuallyoverwritethepagewereon,whilstdocument.createElementdoesnot.Wecansee
hereforaliveexampleofthisinaction.ItalsodoesntworkwithXHTMLwhichisanother
reasonoptingformoreDOMfriendlymethodssuchasdocument.createElementisfavorable.

Knowledgeofantipatternsiscriticalforsuccess.Onceweareabletorecognizesuchantipatterns,were
abletorefactorourcodetonegatethemsothattheoverallqualityofoursolutionsimprovesinstantly.

CategoriesOfDesignPattern

Aglossaryfromthewellknowndesignbook,DomainDrivenTerms,rightlystatesthat:

Adesignpatternnames,abstracts,andidentifiesthekeyaspectsofacommondesignstructurethatmakeituseful
forcreatingareusableobjectorienteddesign.Thedesignpatternidentifiestheparticipatingclassesandtheir
instances,theirrolesandcollaborations,andthedistributionofresponsibilities.

Eachdesignpatternfocusesonaparticularobjectorienteddesignproblemorissue.Itdescribeswhenitapplies,
whetherornotitcanbeappliedinviewofotherdesignconstraints,andtheconsequencesandtradeoffsofitsuse.
Sincewemusteventuallyimplementourdesigns,adesignpatternalsoprovidessample...codetoillustratean
implementation.

Althoughdesignpatternsdescribeobjectorienteddesigns,theyarebasedonpracticalsolutionsthathavebeen
implementedinmainstreamobjectorientedprogramminglanguages....

Designpatternscanbebrokendownintoanumberofdifferentcategories.Inthissectionwellreview
threeofthesecategoriesandbrieflymentionafewexamplesofthepatternsthatfallintothesecategories
beforeexploringspecificonesinmoredetail.

CreationalDesignPatterns
Creationaldesignpatternsfocusonhandlingobjectcreationmechanismswhereobjectsarecreatedina
mannersuitableforthesituationwereworkingin.Thebasicapproachtoobjectcreationmight

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 12/188
26/04/2015 LearningJavaScriptDesignPatterns

otherwiseleadtoaddedcomplexityinaprojectwhilstthesepatternsaimtosolvethisproblemby
controllingthecreationprocess.

Someofthepatternsthatfallunderthiscategoryare:Constructor,Factory,Abstract,Prototype,
SingletonandBuilder.

StructuralDesignPatterns
Structuralpatternsareconcernedwithobjectcompositionandtypicallyidentifysimplewaystorealize
relationshipsbetweendifferentobjects.Theyhelpensurethatwhenonepartofasystemchanges,the
entirestructureofthesystemdoesntneedtodothesame.Theyalsoassistinrecastingpartsofthe
systemwhichdontfitaparticularpurposeintothosethatdo.

Patternsthatfallunderthiscategoryinclude:Decorator,Facade,Flyweight,AdapterandProxy.

BehavioralDesignPatterns
Behavioralpatternsfocusonimprovingorstreamliningthecommunicationbetweendisparateobjectsin
asystem.

Somebehavioralpatternsinclude:Iterator,Mediator,ObserverandVisitor.

DesignPatternCategorization
Inmyearlyexperiencesoflearningaboutdesignpatterns,Ipersonallyfoundthefollowingtableavery
usefulreminderofwhatanumberofpatternshastoofferitcoversthe23DesignPatternsmentioned
bytheGoF.TheoriginaltablewassummarizedbyElyseNielsenbackin2004andIvemodifieditwhere
necessarytosuitourdiscussioninthissectionofthebook.

Irecommendusingthistableasreference,butdorememberthatthereareanumberofadditional
patternsthatarenotmentionedherebutwillbediscussedlaterinthebook.

Abriefnoteonclasses
Keepinmindthattherewillbepatternsinthistablethatreferencetheconceptofclasses.JavaScriptis
aclasslesslanguage,howeverclassescanbesimulatedusingfunctions.

ThemostcommonapproachtoachievingthisisbydefiningaJavaScriptfunctionwherewethencreate
anobjectusingthe new keyword. this canbeusedtohelpdefinenewpropertiesandmethodsforthe
objectasfollows:

1 //Acar"class"
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 13/188
26/04/2015 LearningJavaScriptDesignPatterns

2 functionCar(model){
3
4 this.model=model;
5 this.color="silver";
6 this.year="2012";
7
8 this.getInfo=function(){
9 returnthis.model+""+this.year;
10 };
11
12 }

WecantheninstantiatetheobjectusingtheCarconstructorwedefinedabovelikethis:

1 varmyCar=newCar("ford");
2
3 myCar.year="2010";
4
5 console.log(myCar.getInfo());

FormorewaystodefineclassesusingJavaScript,seeStoyanStefanovsusefulpostonthem.

Letusnowproceedtoreviewthetable.

Creational Basedontheconceptofcreatinganobject.
Class

Thismakesaninstanceofseveralderivedclassesbasedoninterfaced
FactoryMethod
dataorevents.

Object

Createsaninstanceofseveralfamiliesofclasseswithoutdetailing
AbstractFactory
concreteclasses.

Separatesobjectconstructionfromitsrepresentation,alwayscreatesthe
Builder
sametypeofobject.
Prototype Afullyinitializedinstanceusedforcopyingorcloning.

Singleton Aclasswithonlyasingleinstancewithglobalaccesspoints.


Structural Basedontheideaofbuildingblocksofobjects.

Class
Matchinterfacesofdifferentclassesthereforeclassescanworktogether
Adapter
despiteincompatibleinterfaces.
Object

Matchinterfacesofdifferentclassesthereforeclassescanworktogether
Adapter
despiteincompatibleinterfaces.

Separatesanobjectsinterfacefromitsimplementationsothetwocan
Bridge
varyindependently.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 14/188
26/04/2015 LearningJavaScriptDesignPatterns

Composite Astructureofsimpleandcompositeobjectswhichmakesthetotalobject
morethanjustthesumofitsparts.
Decorator Dynamicallyaddalternateprocessingtoobjects.

Facade Asingleclassthathidesthecomplexityofanentiresubsystem.
Afinegrainedinstanceusedforefficientsharingofinformationthatis
Flyweight
containedelsewhere.
Proxy Aplaceholderobjectrepresentingthetrueobject.


Behavioral Basedonthewayobjectsplayandworktogether.

Class
Awaytoincludelanguageelementsinanapplicationtomatchthe
Interpreter
grammaroftheintendedlanguage.
Template Createstheshellofanalgorithminamethod,thendefertheexactsteps
Method toasubclass.
Object

Chainof Awayofpassingarequestbetweenachainofobjectstofindtheobject
Responsibility thatcanhandletherequest.

Encapsulateacommandrequestasanobjecttoenable,loggingand/or
Command queuingofrequests,andprovideserrorhandlingforunhandled
requests.
Sequentiallyaccesstheelementsofacollectionwithoutknowingthe
Iterator
innerworkingsofthecollection.
Definessimplifiedcommunicationbetweenclassestopreventagroupof
Mediator
classesfromreferringexplicitlytoeachother.
Memento Captureanobjectsinternalstatetobeabletorestoreitlater.

Awayofnotifyingchangetoanumberofclassestoensureconsistency
Observer
betweentheclasses.

State Alteranobjectsbehaviorwhenitsstatechanges.
Encapsulatesanalgorithminsideaclassseparatingtheselectionfromthe
Strategy
implementation.
Visitor Addsanewoperationtoaclasswithoutchangingtheclass.

JavaScriptDesignPatterns

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 15/188
26/04/2015 LearningJavaScriptDesignPatterns

Inthissection,wewillexploreJavaScriptimplementationsofanumberofbothclassicandmodern
designpatterns.

Developerscommonlywonderwhetherthereisanidealpatternorsetofpatternstheyshouldbeusing
intheirworkflow.Thereisntatruesingleanswertothisquestion;eachscriptandwebapplicationwe
workonislikelytohaveitsownindividualneedsandweneedtothinkaboutwherewefeelapattern
canofferrealvaluetoanimplementation.

Forexample,someprojectsmaybenefitfromthedecouplingbenefitsofferedbytheObserverpattern
(whichreduceshowdependentpartsofanapplicationareononeanother)whilstothersmaysimplybe
toosmallfordecouplingtobeaconcernatall.

Thatsaid,oncewehaveafirmgraspofdesignpatternsandthespecificproblemstheyarebestsuitedto,
itbecomesmucheasiertointegratethemintoourapplicationarchitectures.

Thepatternswewillbeexploringinthissectionarethe:

ConstructorPattern
ModulePattern
RevealingModulePattern
SingletonPattern
ObserverPattern
MediatorPattern
PrototypePattern
CommandPattern
FacadePattern
FactoryPattern
MixinPattern
DecoratorPattern
FlyweightPattern

TheConstructorPattern
Inclassicalobjectorientedprogramminglanguages,aconstructorisaspecialmethodusedtoinitializea
newlycreatedobjectoncememoryhasbeenallocatedforit.InJavaScript,asalmosteverythingisan
object,weremostofteninterestedinobjectconstructors.

Objectconstructorsareusedtocreatespecifictypesofobjectsbothpreparingtheobjectforuseand
acceptingargumentswhichaconstructorcanusetosetthevaluesofmemberpropertiesandmethods
whentheobjectisfirstcreated.

ObjectCreation
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 16/188
26/04/2015 LearningJavaScriptDesignPatterns

ThethreecommonwaystocreatenewobjectsinJavaScriptareasfollows:

1 //Eachofthefollowingoptionswillcreateanewemptyobject:
2
3 varnewObject={};
4
5 //or
6 varnewObject=Object.create(Object.prototype);
7
8 //or
9 varnewObject=newObject();

WheretheObjectconstructorinthefinalexamplecreatesanobjectwrapperforaspecificvalue,or
wherenovalueispassed,itwillcreateanemptyobjectandreturnit.

Therearethenfourwaysinwhichkeysandvaluescanthenbeassignedtoanobject:

1 //ECMAScript3compatibleapproaches
2
3 //1.Dotsyntax
4
5 //Setproperties
6 newObject.someKey="HelloWorld";
7
8 //Getproperties
9 varvalue=newObject.someKey;
10
11
12
13 //2.Squarebracketsyntax
14
15 //Setproperties
16 newObject["someKey"]="HelloWorld";
17
18 //Getproperties
19 varvalue=newObject["someKey"];
20
21
22
23 //ECMAScript5onlycompatibleapproaches
24 //Formoreinformationsee:http://kangax.github.com/es5compattable/
25
26 //3.Object.defineProperty
27
28 //Setproperties
29 Object.defineProperty(newObject,"someKey",{
30 value:"formorecontroloftheproperty'sbehavior",
31 writable:true,
32 enumerable:true,
33 configurable:true
34 });
35
36 //Iftheabovefeelsalittledifficulttoread,ashorthandcould
37 //bewrittenasfollows:
38
39 vardefineProp=function(obj,key,value){
40 varconfig={
41 value:value,
42 writable:true,
43 enumerable:true,
44 configurable:true
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 17/188
26/04/2015 LearningJavaScriptDesignPatterns

45 };
46 Object.defineProperty(obj,key,config);
47 };
48
49 //Touse,wethencreateanewempty"person"object
50 varperson=Object.create(Object.prototype);
51
52 //Populatetheobjectwithproperties
53 defineProp(person,"car","Delorean");
54 defineProp(person,"dateOfBirth","1981");
55 defineProp(person,"hasBeard",false);
56
57 console.log(person);
58 //Outputs:Object{car:"Delorean",dateOfBirth:"1981",hasBeard:false}
59
60
61 //4.Object.defineProperties
62
63 //Setproperties
64 Object.defineProperties(newObject,{
65
66 "someKey":{
67 value:"HelloWorld",
68 writable:true
69 },
70
71 "anotherKey":{
72 value:"Foobar",
73 writable:false
74 }
75
76 });
77
78 //Gettingpropertiesfor3.and4.canbedoneusinganyofthe
79 //optionsin1.and2.

Aswewillseealittlelaterinthebook,thesemethodscanevenbeusedforinheritance,asfollows:

1 //Usage:
2
3 //Createaracecardriverthatinheritsfromthepersonobject
4 vardriver=Object.create(person);
5
6 //Setsomepropertiesforthedriver
7 defineProp(driver,"topSpeed","100mph");
8
9 //Getaninheritedproperty(1981)
10 console.log(driver.dateOfBirth);
11
12 //Getthepropertyweset(100mph)
13 console.log(driver.topSpeed);

BasicConstructors
Aswesawearlier,JavaScriptdoesntsupporttheconceptofclassesbutitdoessupportspecial
constructorfunctionsthatworkwithobjects.Bysimplyprefixingacalltoaconstructorfunctionwith
thekeywordnew,wecantellJavaScriptwewouldlikethefunctiontobehavelikeaconstructorand
instantiateanewobjectwiththemembersdefinedbythatfunction.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 18/188
26/04/2015 LearningJavaScriptDesignPatterns

Insideaconstructor,thekeywordthisreferencesthenewobjectthatsbeingcreated.Revisitingobject
creation,abasicconstructormaylookasfollows:

1 functionCar(model,year,miles){
2
3 this.model=model;
4 this.year=year;
5 this.miles=miles;
6
7 this.toString=function(){
8 returnthis.model+"hasdone"+this.miles+"miles";
9 };
10 }
11
12 //Usage:
13
14 //Wecancreatenewinstancesofthecar
15 varcivic=newCar("HondaCivic",2009,20000);
16 varmondeo=newCar("FordMondeo",2010,5000);
17
18 //andthenopenourbrowserconsoletoviewthe
19 //outputofthetoString()methodbeingcalledon
20 //theseobjects
21 console.log(civic.toString());
22 console.log(mondeo.toString());

Theaboveisasimpleversionoftheconstructorpatternbutitdoessufferfromsomeproblems.Oneis
thatitmakesinheritancedifficultandtheotheristhatfunctionssuchas toString() areredefinedfor
eachofthenewobjectscreatedusingtheCarconstructor.Thisisntveryoptimalasthefunctionshould
ideallybesharedbetweenalloftheinstancesoftheCartype.

ThankfullyasthereareanumberofbothES3andES5compatiblealternativestoconstructingobjects,
itstrivialtoworkaroundthislimitation.

ConstructorsWithPrototypes
Functions,likealmostallobjectsinJavaScript,containaprototypeobject.WhenwecallaJavaScript
constructortocreateanobject,allthepropertiesoftheconstructorsprototypearethenmadeavailable
tothenewobject.Inthisfashion,multipleCarobjectscanbecreatedwhichaccessthesameprototype.
Wecanthusextendtheoriginalexampleasfollows:

1 functionCar(model,year,miles){
2
3 this.model=model;
4 this.year=year;
5 this.miles=miles;
6
7 }
8
9
10 //NoteherethatweareusingObject.prototype.newMethodratherthan
11 //Object.prototypesoastoavoidredefiningtheprototypeobject
12 Car.prototype.toString=function(){

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 19/188
26/04/2015 LearningJavaScriptDesignPatterns

13 returnthis.model+"hasdone"+this.miles+"miles";
14 };
15
16 //Usage:
17
18 varcivic=newCar("HondaCivic",2009,20000);
19 varmondeo=newCar("FordMondeo",2010,5000);
20
21 console.log(civic.toString());
22 console.log(mondeo.toString());

Above,asingleinstanceoftoString()willnowbesharedbetweenalloftheCarobjects.

TheModulePattern

Modules
Modulesareanintegralpieceofanyrobustapplicationsarchitectureandtypicallyhelpinkeepingthe
unitsofcodeforaprojectbothcleanlyseparatedandorganized.

InJavaScript,thereareseveraloptionsforimplementingmodules.Theseinclude:

TheModulepattern
Objectliteralnotation
AMDmodules
CommonJSmodules
ECMAScriptHarmonymodules

WewillbeexploringthelatterthreeoftheseoptionslateroninthebookinthesectionModernModular
JavaScriptDesignPatterns.

TheModulepatternisbasedinpartonobjectliteralsandsoitmakessensetorefreshourknowledgeof
themfirst.

ObjectLiterals
Inobjectliteralnotation,anobjectisdescribedasasetofcommaseparatedname/valuepairsenclosed
incurlybraces( {} ).Namesinsidetheobjectmaybeeitherstringsoridentifiersthatarefollowedbya
colon.Thereshouldbenocommausedafterthefinalname/valuepairintheobjectasthismayresultin
errors.

1 varmyObjectLiteral={
2
3 variableKey:variableValue,
4
5 functionKey:function(){
6 //...
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 20/188
26/04/2015 LearningJavaScriptDesignPatterns

7 }
8 };

Objectliteralsdontrequireinstantiationusingthe new operatorbutshouldntbeusedatthestartofa


statementastheopening { maybeinterpretedasthebeginningofablock.Outsideofanobject,new
membersmaybeaddedtoitusingassignmentasfollows myModule.property="someValue";

Belowwecanseeamorecompleteexampleofamoduledefinedusingobjectliteralnotation:

1 varmyModule={
2
3 myProperty:"someValue",
4
5 //objectliteralscancontainpropertiesandmethods.
6 //e.gwecandefineafurtherobjectformoduleconfiguration:
7 myConfig:{
8 useCaching:true,
9 language:"en"
10 },
11
12 //averybasicmethod
13 saySomething:function(){
14 console.log("WhereintheworldisPaulIrishtoday?");
15 },
16
17 //outputavaluebasedonthecurrentconfiguration
18 reportMyConfig:function(){
19 console.log("Cachingis:"+(this.myConfig.useCaching?"enabled":"disabled"
20 },
21
22 //overridethecurrentconfiguration
23 updateMyConfig:function(newConfig){
24
25 if(typeofnewConfig==="object"){
26 this.myConfig=newConfig;
27 console.log(this.myConfig.language);
28 }
29 }
30 };
31
32 //Outputs:WhereintheworldisPaulIrishtoday?
33 myModule.saySomething();
34
35 //Outputs:Cachingis:enabled
36 myModule.reportMyConfig();
37
38 //Outputs:fr
39 myModule.updateMyConfig({
40 language:"fr",
41 useCaching:false
42 });
43
44 //Outputs:Cachingis:disabled
45 myModule.reportMyConfig();

UsingobjectliteralscanassistinencapsulatingandorganizingyourcodeandRebeccaMurpheyhas
previouslywrittenaboutthistopicindepthshouldyouwishtoreadintoobjectliteralsfurther.

Thatsaid,ifwereoptingforthistechnique,wemaybeequallyasinterestedintheModulepattern.It
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 21/188
26/04/2015 LearningJavaScriptDesignPatterns

stillusesobjectliteralsbutonlyasthereturnvaluefromascopingfunction.

TheModulePattern
TheModulepatternwasoriginallydefinedasawaytoprovidebothprivateandpublicencapsulation
forclassesinconventionalsoftwareengineering.

InJavaScript,theModulepatternisusedtofurtheremulatetheconceptofclassesinsuchawaythat
wereabletoincludebothpublic/privatemethodsandvariablesinsideasingleobject,thusshielding
particularpartsfromtheglobalscope.Whatthisresultsinisareductioninthelikelihoodofour
functionnamesconflictingwithotherfunctionsdefinedinadditionalscriptsonthepage.

Privacy

TheModulepatternencapsulatesprivacy,stateandorganizationusingclosures.Itprovidesawayof
wrappingamixofpublicandprivatemethodsandvariables,protectingpiecesfromleakingintothe
globalscopeandaccidentallycollidingwithanotherdevelopersinterface.Withthispattern,onlya
publicAPIisreturned,keepingeverythingelsewithintheclosureprivate.

Thisgivesusacleansolutionforshieldinglogicdoingtheheavyliftingwhilstonlyexposingan
interfacewewishotherpartsofourapplicationtouse.Thepatternisquitesimilartoanimmediately
invokedfunctionalexpression(IIFEseethesectiononnamespacingpatternsformoreonthis)except
thatanobjectisreturnedratherthanafunction.

ItshouldbenotedthatthereisntreallyanexplicitlytruesenseofprivacyinsideJavaScriptbecause
unlikesometraditionallanguages,itdoesnthaveaccessmodifiers.Variablescanttechnicallybe
declaredasbeingpublicnorprivateandsoweusefunctionscopetosimulatethisconcept.Withinthe
Modulepattern,variablesormethodsdeclaredareonlyavailableinsidethemoduleitselfthanksto
closure.Variablesormethodsdefinedwithinthereturningobjecthoweverareavailabletoeveryone.

History

Fromahistoricalperspective,theModulepatternwasoriginallydevelopedbyanumberofpeople
includingRichardCornfordin2003.ItwaslaterpopularizedbyDouglasCrockfordinhislectures.
AnotherpieceoftriviaisthatifyouveeverplayedwithYahoosYUIlibrary,someofitsfeaturesmay
appearquitefamiliarandthereasonforthisisthattheModulepatternwasastronginfluenceforYUI
whencreatingtheircomponents.

Examples

LetsbeginlookingatanimplementationoftheModulepatternbycreatingamodulewhichisself
contained.

?
1 vartestModule=(function(){
2
3 varcounter=0;
4
5 return{

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 22/188
26/04/2015 LearningJavaScriptDesignPatterns

6
7 incrementCounter:function(){
8 returncounter++;
9 },
10
11 resetCounter:function(){
12 console.log("countervaluepriortoreset:"+counter);
13 counter=0;
14 }
15 };
16
17 })();
18
19 //Usage:
20
21 //Incrementourcounter
22 testModule.incrementCounter();
23
24 //Checkthecountervalueandreset
25 //Outputs:countervaluepriortoreset:1
26 testModule.resetCounter();

Here,otherpartsofthecodeareunabletodirectlyreadthevalueofour incrementCounter() or
resetCounter() .Thecountervariableisactuallyfullyshieldedfromourglobalscopesoitactsjustlikea

privatevariablewoulditsexistenceislimitedtowithinthemodulesclosuresothattheonlycodeable
toaccessitsscopeareourtwofunctions.Ourmethodsareeffectivelynamespacedsointhetestsection
ofourcode,weneedtoprefixanycallswiththenameofthemodule(e.g.testModule).

WhenworkingwiththeModulepattern,wemayfinditusefultodefineasimpletemplatethatweuse
forgettingstartedwithit.Heresonethatcoversnamespacing,publicandprivatevariables:

1 varmyNamespace=(function(){
2
3 varmyPrivateVar,myPrivateMethod;
4
5 //Aprivatecountervariable
6 myPrivateVar=0;
7
8 //Aprivatefunctionwhichlogsanyarguments
9 myPrivateMethod=function(foo){
10 console.log(foo);
11 };
12
13 return{
14
15 //Apublicvariable
16 myPublicVar:"foo",
17
18 //Apublicfunctionutilizingprivates
19 myPublicFunction:function(bar){
20
21 //Incrementourprivatecounter
22 myPrivateVar++;
23
24 //Callourprivatemethodusingbar
25 myPrivateMethod(bar);
26
27 }
28 };
29
30 })();
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 23/188
26/04/2015 LearningJavaScriptDesignPatterns

Lookingatanotherexample,belowwecanseeashoppingbasketimplementedusingthispattern.The
moduleitselfiscompletelyselfcontainedinaglobalvariablecalled basketModule .The basket arrayin
themoduleiskeptprivateandsootherpartsofourapplicationareunabletodirectlyreadit.Itonly
existswiththemodulesclosureandsotheonlymethodsabletoaccessitarethosewithaccesstoits
scope(ie. addItem() , getItemCount() etc).

?
1 varbasketModule=(function(){
2
3 //privates
4
5 varbasket=[];
6
7 functiondoSomethingPrivate(){
8 //...
9 }
10
11 functiondoSomethingElsePrivate(){
12 //...
13 }
14
15 //Returnanobjectexposedtothepublic
16 return{
17
18 //Additemstoourbasket
19 addItem:function(values){
20 basket.push(values);
21 },
22
23 //Getthecountofitemsinthebasket
24 getItemCount:function(){
25 returnbasket.length;
26 },
27
28 //Publicaliastoaprivatefunction
29 doSomething:doSomethingPrivate,
30
31 //Getthetotalvalueofitemsinthebasket
32 getTotal:function(){
33
34 varq=this.getItemCount(),
35 p=0;
36
37 while(q){
38 p+=basket[q].price;
39 }
40
41 returnp;
42 }
43 };
44 })();

Insidethemodule,youmayhavenoticedthatwereturnan object .Thisgetsautomaticallyassignedto


basketModule sothatwecaninteractwithitasfollows:

1 //basketModulereturnsanobjectwithapublicAPIwecanuse
2
3 basketModule.addItem({
4 item:"bread",
5 price:0.5
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 24/188
26/04/2015 LearningJavaScriptDesignPatterns

6 });
7
8 basketModule.addItem({
9 item:"butter",
10 price:0.3
11 });
12
13 //Outputs:2
14 console.log(basketModule.getItemCount());
15
16 //Outputs:0.8
17 console.log(basketModule.getTotal());
18
19 //However,thefollowingwillnotwork:
20
21 //Outputs:undefined
22 //Thisisbecausethebasketitselfisnotexposedasapartofour
23 //thepublicAPI
24 console.log(basketModule.basket);
25
26 //Thisalsowon'tworkasitonlyexistswithinthescopeofour
27 //basketModuleclosure,butnotthereturnedpublicobject
28 console.log(basket);

Themethodsaboveareeffectivelynamespacedinside basketModule .

Noticehowthescopingfunctionintheabovebasketmoduleiswrappedaroundallofourfunctions,
whichwethencallandimmediatelystorethereturnvalueof.Thishasanumberofadvantages
including:

Thefreedomtohaveprivatefunctionswhichcanonlybeconsumedbyourmodule.Asthey
arentexposedtotherestofthepage(onlyourexportedAPIis),theyreconsideredtruly
private.
Giventhatfunctionsaredeclarednormallyandarenamed,itcanbeeasiertoshowcallstacks
inadebuggerwhenwereattemptingtodiscoverwhatfunction(s)threwanexception.
AsT.JCrowderhaspointedoutinthepast,italsoenablesustoreturndifferentfunctions
dependingontheenvironment.Inthepast,IveseendevelopersusethistoperformUA
testinginordertoprovideacodepathintheirmodulespecifictoIE,butwecaneasilyoptfor
featuredetectionthesedaystoachieveasimilargoal.

ModulePatternVariations

Importmixins
Thisvariationofthepatterndemonstrateshowglobals(e.gjQuery,Underscore)canbepassedinas
argumentstoourmodulesanonymousfunction.Thiseffectivelyallowsustoimportthemandlocally
aliasthemaswewish.

1 //Globalmodule
2 varmyModule=(function(jQ,_){
3
4 functionprivateMethod1(){
5 jQ(".container").html("test");
6 }
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 25/188
26/04/2015 LearningJavaScriptDesignPatterns

7
8 functionprivateMethod2(){
9 console.log(_.min([10,5,100,2,1000]));
10 }
11
12 return{
13 publicMethod:function(){
14 privateMethod1();
15 }
16 };
17
18 //PullinjQueryandUnderscore
19 })(jQuery,_);
20
21 myModule.publicMethod();

Exports
Thisnextvariationallowsustodeclareglobalswithoutconsumingthemandcouldsimilarlysupport
theconceptofglobalimportsseeninthelastexample.

1 //Globalmodule
2 varmyModule=(function(){
3
4 //Moduleobject
5 varmodule={},
6 privateVariable="HelloWorld";
7
8 functionprivateMethod(){
9 //...
10 }
11
12 module.publicProperty="Foobar";
13 module.publicMethod=function(){
14 console.log(privateVariable);
15 };
16
17 returnmodule;
18
19 })();

ToolkitAndFrameworkspecificModulePatternImplementations

Dojo

Dojoprovidesaconveniencemethodforworkingwithobjectscalled dojo.setObject() .Thistakesasits


firstargumentadotseparatedstringsuchas myObj.parent.child whichreferstoapropertycalledchild
withinanobjectparentdefinedinsidemyObj.Using setObject() allowsustosetthevalueof
children,creatinganyoftheintermediateobjectsintherestofthepathpassediftheydontalreadyexist.

Forexample,ifwewantedtodeclare basket.core asanobjectofthe store namespace,thiscouldbe


achievedasfollowsusingthetraditionalway:

1 varstore=window.store||{};
2
3 if(!store["basket"]){
4 store.basket={};
5 }
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 26/188
26/04/2015 LearningJavaScriptDesignPatterns

6
7 if(!store.basket["core"]){
8 store.basket.core={};
9 }
10
11 store.basket.core={
12 //...restofourlogic
13 };

OrasfollowsusingDojo1.7(AMDcompatibleversion)andabove:

1 require(["dojo/_base/customStore"],function(store){
2
3 //usingdojo.setObject()
4 store.setObject("basket.core",(function(){
5
6 varbasket=[];
7
8 functionprivateMethod(){
9 console.log(basket);
10 }
11
12 return{
13 publicMethod:function(){
14 privateMethod();
15 }
16 };
17
18 })());
19
20 });

Formoreinformationon dojo.setObject() ,seetheofficialdocumentation.

ExtJS

ForthoseusingSenchasExtJS,anexampledemonstratinghowtocorrectlyusetheModulepatternwith
theframeworkcanbefoundbelow.

Here,weseeanexampleofhowtodefineanamespacewhichcanthenbepopulatedwithamodule
containingbothaprivateandpublicAPI.Withtheexceptionofsomesemanticdifferences,itsquite
closetohowtheModulepatternisimplementedinvanillaJavaScript:

1 //createnamespace
2 Ext.namespace("myNameSpace");
3
4 //createapplication
5 myNameSpace.app=function(){
6
7 //doNOTaccessDOMfromhere;elementsdon'texistyet
8 //privatevariables
9
10 varbtn1,
11 privVar1=11;
12
13 //privatefunctions
14 varbtn1Handler=function(button,event){

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 27/188
26/04/2015 LearningJavaScriptDesignPatterns

15 console.log("privVar1="+privVar1);
16 console.log("this.btn1Text="+this.btn1Text);
17 };
18
19 //publicspace
20 return{
21 //publicproperties,e.g.stringstotranslate
22 btn1Text:"Button1",
23
24 //publicmethods
25 init:function(){
26
27 if(Ext.Ext2){
28
29 btn1=newExt.Button({
30 renderTo:"btn1ct",
31 text:this.btn1Text,
32 handler:btn1Handler
33 });
34
35 }else{
36
37 btn1=newExt.Button("btn1ct",{
38 text:this.btn1Text,
39 handler:btn1Handler
40 });
41
42 }
43 }
44 };
45 }();

YUI

Similarly,wecanalsoimplementtheModulepatternwhenbuildingapplicationsusingYUI3.The
followingexampleisheavilybasedontheoriginalYUIModulepatternimplementationbyEric
Miraglia,butagain,isntvastlydifferentfromthevanillaJavaScriptversion:

1 Y.namespace("store.basket");
2 Y.store.basket=(function(){
3
4 varmyPrivateVar,myPrivateMethod;
5
6 //privatevariables:
7 myPrivateVar="IcanbeaccessedonlywithinY.store.basket.";
8
9 //privatemethod:
10 myPrivateMethod=function(){
11 Y.log("IcanbeaccessedonlyfromwithinYAHOO.store.basket");
12 }
13
14 return{
15 myPublicProperty:"I'mapublicproperty.",
16
17 myPublicMethod:function(){
18 Y.log("I'mapublicmethod.");
19
20 //Withinbasket,Icanaccess"private"varsandmethods:
21 Y.log(myPrivateVar);
22 Y.log(myPrivateMethod());
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 28/188
26/04/2015 LearningJavaScriptDesignPatterns

23
24 //ThenativescopeofmyPublicMethodisstoresowecan
25 //accesspublicmembersusing"this":
26 Y.log(this.myPublicProperty);
27 }
28 };
29
30 })();

jQuery

ThereareanumberofwaysinwhichjQuerycodeunspecifictopluginscanbewrappedinsidethe
Modulepattern.BenCherrypreviouslysuggestedanimplementationwhereafunctionwrapperisused
aroundmoduledefinitionsintheeventoftherebeinganumberofcommonalitiesbetweenmodules.

Inthefollowingexample,a library functionisdefinedwhichdeclaresanewlibraryandautomatically


bindsupthe init functionto document.ready whennewlibraries(ie.modules)arecreated.

1 functionlibrary(module){
2
3 $(function(){
4 if(module.init){
5 module.init();
6 }
7 });
8
9 returnmodule;
10 }
11
12 varmyLibrary=library(function(){
13
14 return{
15 init:function(){
16 //moduleimplementation
17 }
18 };
19 }());

Advantages

WeveseenwhytheConstructorpatterncanbeuseful,butwhyistheModulepatternagoodchoice?
Forstarters,itsalotcleanerfordeveloperscomingfromanobjectorientedbackgroundthantheideaof
trueencapsulation,atleastfromaJavaScriptperspective.

Secondly,itsupportsprivatedataso,intheModulepattern,publicpartsofourcodeareabletotouch
theprivateparts,howevertheoutsideworldisunabletotouchtheclasssprivateparts(nolaughing!
Oh,andthankstoDavidEngferforthejoke).

Disadvantages

ThedisadvantagesoftheModulepatternarethatasweaccessbothpublicandprivatemembers
differently,whenwewishtochangevisibility,weactuallyhavetomakechangestoeachplacethe
memberwasused.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 29/188
26/04/2015 LearningJavaScriptDesignPatterns

Wealsocantaccessprivatemembersinmethodsthatareaddedtotheobjectatalaterpoint.Thatsaid,
inmanycasestheModulepatternisstillquiteusefulandwhenusedcorrectly,certainlyhasthe
potentialtoimprovethestructureofourapplication.

Otherdisadvantagesincludetheinabilitytocreateautomatedunittestsforprivatemembersand
additionalcomplexitywhenbugsrequirehotfixes.Itssimplynotpossibletopatchprivates.Instead,
onemustoverrideallpublicmethodswhichinteractwiththebuggyprivates.Developerscanteasily
extendprivateseither,soitsworthrememberingprivatesarenotasflexibleastheymayinitially
appear.

ForfurtherreadingontheModulepattern,seeBenCherrysexcellentindeptharticleonit.

TheRevealingModulePattern
Nowthatwerealittlemorefamiliarwiththemodulepattern,letstakealookataslightlyimproved
versionChristianHeilmannsRevealingModulepattern.

TheRevealingModulepatterncameaboutasHeilmannwasfrustratedwiththefactthathehadto
repeatthenameofthemainobjectwhenwewantedtocallonepublicmethodfromanotheroraccess
publicvariables.HealsodislikedtheModulepatternsrequirementforhavingtoswitchtoobjectliteral
notationforthethingshewishedtomakepublic.

Theresultofhiseffortswasanupdatedpatternwherewewouldsimplydefineallofourfunctionsand
variablesintheprivatescopeandreturnananonymousobjectwithpointerstotheprivatefunctionality
wewishedtorevealaspublic.

AnexampleofhowtousetheRevealingModulepatterncanbefoundbelow:

1 varmyRevealingModule=(function(){
2
3 varprivateVar="BenCherry",
4 publicVar="Heythere!";
5
6 functionprivateFunction(){
7 console.log("Name:"+privateVar);
8 }
9
10 functionpublicSetName(strName){
11 privateVar=strName;
12 }
13
14 functionpublicGetName(){
15 privateFunction();
16 }
17
18
19 //Revealpublicpointersto
20 //privatefunctionsandproperties
21
22 return{

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 30/188
26/04/2015 LearningJavaScriptDesignPatterns

23 setName:publicSetName,
24 greeting:publicVar,
25 getName:publicGetName
26 };
27
28 })();
29
30 myRevealingModule.setName("PaulKinlan");

Thepatterncanalsobeusedtorevealprivatefunctionsandpropertieswithamorespecificnaming
schemeifwewouldprefer:

1 varmyRevealingModule=(function(){
2
3 varprivateCounter=0;
4
5 functionprivateFunction(){
6 privateCounter++;
7 }
8
9 functionpublicFunction(){
10 publicIncrement();
11 }
12
13 functionpublicIncrement(){
14 privateFunction();
15 }
16
17 functionpublicGetCount(){
18 returnprivateCounter;
19 }
20
21 //Revealpublicpointersto
22 //privatefunctionsandproperties
23
24 return{
25 start:publicFunction,
26 increment:publicIncrement,
27 count:publicGetCount
28 };
29
30 })();
31
32 myRevealingModule.start();

Advantages

Thispatternallowsthesyntaxofourscriptstobemoreconsistent.Italsomakesitmoreclearattheend
ofthemodulewhichofourfunctionsandvariablesmaybeaccessedpubliclywhicheasesreadability.

Disadvantages

Adisadvantageofthispatternisthatifaprivatefunctionreferstoapublicfunction,thatpublicfunction
cantbeoverriddenifapatchisnecessary.Thisisbecausetheprivatefunctionwillcontinuetoreferto
theprivateimplementationandthepatterndoesntapplytopublicmembers,onlytofunctions.

Publicobjectmemberswhichrefertoprivatevariablesarealsosubjecttothenopatchrulenotesabove.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 31/188
26/04/2015 LearningJavaScriptDesignPatterns

Asaresultofthis,modulescreatedwiththeRevealingModulepatternmaybemorefragilethanthose
createdwiththeoriginalModulepattern,socareshouldbetakenduringusage.

TheSingletonPattern
TheSingletonpatternisthusknownbecauseitrestrictsinstantiationofaclasstoasingleobject.
Classically,theSingletonpatterncanbeimplementedbycreatingaclasswithamethodthatcreatesa
newinstanceoftheclassifonedoesntexist.Intheeventofaninstancealreadyexisting,itsimply
returnsareferencetothatobject.

Singletonsdifferfromstaticclasses(orobjects)aswecandelaytheirinitialization,generallybecausethey
requiresomeinformationthatmaynotbeavailableduringinitializationtime.Theydontprovideaway
forcodethatisunawareofapreviousreferencetothemtoeasilyretrievethem.Thisisbecauseitis
neithertheobjectorclassthatsreturnedbyaSingleton,itsastructure.Thinkofhowclosured
variablesarentactuallyclosuresthefunctionscopethatprovidestheclosureistheclosure.

InJavaScript,Singletonsserveasasharedresourcenamespacewhichisolateimplementationcodefrom
theglobalnamespacesoastoprovideasinglepointofaccessforfunctions.

WecanimplementaSingletonasfollows:

1 varmySingleton=(function(){
2
3 //InstancestoresareferencetotheSingleton
4 varinstance;
5
6 functioninit(){
7
8 //Singleton
9
10 //Privatemethodsandvariables
11 functionprivateMethod(){
12 console.log("Iamprivate");
13 }
14
15 varprivateVariable="Imalsoprivate";
16
17 varprivateRandomNumber=Math.random();
18
19 return{
20
21 //Publicmethodsandvariables
22 publicMethod:function(){
23 console.log("Thepubliccanseeme!");
24 },
25
26 publicProperty:"Iamalsopublic",
27
28 getRandomNumber:function(){
29 returnprivateRandomNumber;
30 }
31
32 };

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 32/188
26/04/2015 LearningJavaScriptDesignPatterns

33
34 };
35
36 return{
37
38 //GettheSingletoninstanceifoneexists
39 //orcreateoneifitdoesn't
40 getInstance:function(){
41
42 if(!instance){
43 instance=init();
44 }
45
46 returninstance;
47 }
48
49 };
50
51 })();
52
53 varmyBadSingleton=(function(){
54
55 //InstancestoresareferencetotheSingleton
56 varinstance;
57
58 functioninit(){
59
60 //Singleton
61
62 varprivateRandomNumber=Math.random();
63
64 return{
65
66 getRandomNumber:function(){
67 returnprivateRandomNumber;
68 }
69
70 };
71
72 };
73
74 return{
75
76 //AlwayscreateanewSingletoninstance
77 getInstance:function(){
78
79 instance=init();
80
81 returninstance;
82 }
83
84 };
85
86 })();
87
88
89 //Usage:
90
91 varsingleA=mySingleton.getInstance();
92 varsingleB=mySingleton.getInstance();
93 console.log(singleA.getRandomNumber()===singleB.getRandomNumber());//true
94
95 varbadSingleA=myBadSingleton.getInstance();
96 varbadSingleB=myBadSingleton.getInstance();
97 console.log(badSingleA.getRandomNumber()!==badSingleB.getRandomNumber());
98
99 //Note:asweareworkingwithrandomnumbers,thereisa
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 33/188
26/04/2015 LearningJavaScriptDesignPatterns

100 //mathematicalpossibilitybothnumberswillbethesame,
101 //howeverunlikely.Theaboveexampleshouldotherwisestill
102 //bevalid.

WhatmakestheSingletonistheglobalaccesstotheinstance(generallythrough
)aswedont(atleastinstaticlanguages)call
MySingleton.getInstance() newMySingleton() directly.Thisis
howeverpossibleinJavaScript.

IntheGoFbook,theapplicabilityoftheSingletonpatternisdescribedasfollows:

Theremustbeexactlyoneinstanceofaclass,anditmustbeaccessibletoclientsfromawell
knownaccesspoint.
Whenthesoleinstanceshouldbeextensiblebysubclassing,andclientsshouldbeabletouse
anextendedinstancewithoutmodifyingtheircode.

Thesecondofthesepointsreferstoacasewherewemightneedcodesuchas:

1 mySingleton.getInstance=function(){
2 if(this._instance==null){
3 if(isFoo()){
4 this._instance=newFooSingleton();
5 }else{
6 this._instance=newBasicSingleton();
7 }
8 }
9 returnthis._instance;
10 };

Here, getInstance becomesalittlelikeaFactorymethodandwedontneedtoupdateeachpointinour


codeaccessingit. FooSingleton abovewouldbeasubclassof BasicSingleton andimplementthesame
interface.

WhyisdeferringexecutionconsideredimportantforaSingleton?:

InC++itservestoisolatefromtheunpredictabilityoftheorderofdynamicinitialization,
returningcontroltotheprogrammer.

Itisimportanttonotethedifferencebetweenastaticinstanceofaclass(object)andaSingleton:whilsta
Singletoncanbeimplementedasastaticinstance,itcanalsobeconstructedlazily,withouttheneedfor
resourcesnormemoryuntilthisisactuallyneeded.

Ifwehaveastaticobjectthatcanbeinitializeddirectly,weneedtoensurethecodeisalwaysexecuted
inthesameorder(e.gincase objCar needs objWheel duringitsinitialization)andthisdoesntscale
whenyouhavealargenumberofsourcefiles.

BothSingletonsandstaticobjectsareusefulbuttheyshouldntbeoverusedthesamewayinwhichwe
shouldntoveruseotherpatterns.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 34/188
26/04/2015 LearningJavaScriptDesignPatterns

Inpractice,theSingletonpatternisusefulwhenexactlyoneobjectisneededtocoordinateothersacross
asystem.Hereisoneexamplewiththepatternbeingusedinthiscontext:

1 varSingletonTester=(function(){
2
3 //options:anobjectcontainingconfigurationoptionsforthesingleton
4 //e.gvaroptions={name:"test",pointX:5};
5 functionSingleton(options){
6
7 //setoptionstotheoptionssupplied
8 //oranemptyobjectifnoneareprovided
9 options=options||{};
10
11 //setsomepropertiesforoursingleton
12 this.name="SingletonTester";
13
14 this.pointX=options.pointX||6;
15
16 this.pointY=options.pointY||10;
17
18 }
19
20 //ourinstanceholder
21 varinstance;
22
23 //anemulationofstaticvariablesandmethods
24 var_static={
25
26 name:"SingletonTester",
27
28 //Methodforgettinganinstance.Itreturns
29 //asingletoninstanceofasingletonobject
30 getInstance:function(options){
31 if(instance===undefined){
32 instance=newSingleton(options);
33 }
34
35 returninstance;
36
37 }
38 };
39
40 return_static;
41
42 })();
43
44 varsingletonTest=SingletonTester.getInstance({
45 pointX:5
46 });
47
48 //LogtheoutputofpointXjusttoverifyitiscorrect
49 //Outputs:5
50 console.log(singletonTest.pointX);

WhilsttheSingletonhasvaliduses,oftenwhenwefindourselvesneedingitinJavaScriptitsasignthat
wemayneedtoreevaluateourdesign.

Theyreoftenanindicationthatmodulesinasystemareeithertightlycoupledorthatlogicisoverly
spreadacrossmultiplepartsofacodebase.Singletonscanbemoredifficulttotestduetoissuesranging
fromhiddendependencies,thedifficultyincreatingmultipleinstances,difficultyinstubbing
dependenciesandsoon.
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 35/188
26/04/2015 LearningJavaScriptDesignPatterns

MillerMedeiroshaspreviouslyrecommendedthisexcellentarticleontheSingletonanditsvarious
issuesforfurtherreadingaswellasthecommentstothisarticle,discussinghowSingletonscanincrease
tightcoupling.Imhappytosecondtheserecommendationsasbothpiecesraisemanyimportantpoints
aboutthispatternthatarealsoworthnoting.

TheObserverPattern
TheObserverisadesignpatternwhereanobject(knownasasubject)maintainsalistofobjects
dependingonit(observers),automaticallynotifyingthemofanychangestostate.

Whenasubjectneedstonotifyobserversaboutsomethinginterestinghappening,itbroadcastsa
notificationtotheobservers(whichcanincludespecificdatarelatedtothetopicofthenotification).

Whenwenolongerwishforaparticularobservertobenotifiedofchangesbythesubjecttheyare
registeredwith,thesubjectcanremovethemfromthelistofobservers.

Itsoftenusefultoreferbacktopublisheddefinitionsofdesignpatternsthatarelanguageagnostictoget
abroadersenseoftheirusageandadvantagesovertime.ThedefinitionoftheObserverpattern
providedintheGoFbook,DesignPatterns:ElementsofReusableObjectOrientedSoftware,is:

Oneormoreobserversareinterestedinthestateofasubjectandregistertheirinterestwiththesubjectby
attachingthemselves.Whensomethingchangesinoursubjectthattheobservermaybeinterestedin,anotify
messageissentwhichcallstheupdatemethodineachobserver.Whentheobserverisnolongerinterestedinthe
subjectsstate,theycansimplydetachthemselves.

WecannowexpandonwhatwevelearnedtoimplementtheObserverpatternwiththefollowing
components:

Subject:maintainsalistofobservers,facilitatesaddingorremovingobservers
Observer:providesaupdateinterfaceforobjectsthatneedtobenotifiedofaSubjects
changesofstate
ConcreteSubject:broadcastsnotificationstoobserversonchangesofstate,storesthestateof
ConcreteObservers
ConcreteObserver:storesareferencetotheConcreteSubject,implementsanupdateinterface
fortheObservertoensurestateisconsistentwiththeSubjects

First,letsmodelthelistofdependentObserversasubjectmayhave:

1 functionObserverList(){
2 this.observerList=[];
3 }
4
5 ObserverList.prototype.add=function(obj){
6 returnthis.observerList.push(obj);
7 };
8

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 36/188
26/04/2015 LearningJavaScriptDesignPatterns

9 ObserverList.prototype.count=function(){
10 returnthis.observerList.length;
11 };
12
13 ObserverList.prototype.get=function(index){
14 if(index>1&&index<this.observerList.length){
15 returnthis.observerList[index];
16 }
17 };
18
19 ObserverList.prototype.indexOf=function(obj,startIndex){
20 vari=startIndex;
21
22 while(i<this.observerList.length){
23 if(this.observerList[i]===obj){
24 returni;
25 }
26 i++;
27 }
28
29 return1;
30 };
31
32 ObserverList.prototype.removeAt=function(index){
33 this.observerList.splice(index,1);
34 };

Next,letsmodeltheSubjectandtheabilitytoadd,removeornotifyobserversontheobserverlist.

1 functionSubject(){
2 this.observers=newObserverList();
3 }
4
5 Subject.prototype.addObserver=function(observer){
6 this.observers.add(observer);
7 };
8
9 Subject.prototype.removeObserver=function(observer){
10 this.observers.removeAt(this.observers.indexOf(observer,0));
11 };
12
13 Subject.prototype.notify=function(context){
14 varobserverCount=this.observers.count();
15 for(vari=0;i<observerCount;i++){
16 this.observers.get(i).update(context);
17 }
18 };

WethendefineaskeletonforcreatingnewObservers.The update functionalityherewillbeoverwritten


laterwithcustombehaviour.

1 //TheObserver
2 functionObserver(){
3 this.update=function(){
4 //...
5 };
6 }

InoursampleapplicationusingtheaboveObservercomponents,wenowdefine:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 37/188
26/04/2015 LearningJavaScriptDesignPatterns

Abuttonforaddingnewobservablecheckboxestothepage
Acontrolcheckboxwhichwillactasasubject,notifyingothercheckboxestheyshouldbe
checked
Acontainerforthenewcheckboxesbeingadded

WethendefineConcreteSubjectandConcreteObserverhandlersforbothaddingnewobserverstothe
pageandimplementingtheupdatinginterface.Seebelowforinlinecommentsonwhatthese
componentsdointhecontextofourexample.

HTML:

1 <buttonid="addNewObserver">AddNewObservercheckbox</button>
2 <inputid="mainCheckbox"type="checkbox"/>
3 <divid="observersContainer"></div>

Samplescript:

1 //Extendanobjectwithanextension
2 functionextend(extension,obj){
3 for(varkeyinextension){
4 obj[key]=extension[key];
5 }
6 }
7
8 //ReferencestoourDOMelements
9
10 varcontrolCheckbox=document.getElementById("mainCheckbox"),
11 addBtn=document.getElementById("addNewObserver"),
12 container=document.getElementById("observersContainer");
13
14
15 //ConcreteSubject
16
17 //ExtendthecontrollingcheckboxwiththeSubjectclass
18 extend(newSubject(),controlCheckbox);
19
20 //Clickingthecheckboxwilltriggernotificationstoitsobservers
21 controlCheckbox.onclick=function(){
22 controlCheckbox.notify(controlCheckbox.checked);
23 };
24
25 addBtn.onclick=addNewObserver;
26
27 //ConcreteObserver
28
29 functionaddNewObserver(){
30
31 //Createanewcheckboxtobeadded
32 varcheck=document.createElement("input");
33 check.type="checkbox";
34
35 //ExtendthecheckboxwiththeObserverclass
36 extend(newObserver(),check);
37
38 //Overridewithcustomupdatebehaviour
39 check.update=function(value){
40 this.checked=value;
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 38/188
26/04/2015 LearningJavaScriptDesignPatterns

41 };
42
43 //Addthenewobservertoourlistofobservers
44 //forourmainsubject
45 controlCheckbox.addObserver(check);
46
47 //Appendtheitemtothecontainer
48 container.appendChild(check);
49 }

Inthisexample,welookedathowtoimplementandutilizetheObserverpattern,coveringtheconcepts
ofaSubject,Observer,ConcreteSubjectandConcreteObserver.

DifferencesBetweenTheObserverAndPublish/SubscribePattern
WhilsttheObserverpatternisusefultobeawareof,quiteoftenintheJavaScriptworld,wellfindit
commonlyimplementedusingavariationknownasthePublish/Subscribepattern.Whilstverysimilar,
therearedifferencesbetweenthesepatternsworthnoting.

TheObserverpatternrequiresthattheobserver(orobject)wishingtoreceivetopicnotificationsmust
subscribethisinteresttotheobjectfiringtheevent(thesubject).

ThePublish/Subscribepatternhoweverusesatopic/eventchannelwhichsitsbetweentheobjects
wishingtoreceivenotifications(subscribers)andtheobjectfiringtheevent(thepublisher).Thisevent
systemallowscodetodefineapplicationspecificeventswhichcanpasscustomargumentscontaining
valuesneededbythesubscriber.Theideahereistoavoiddependenciesbetweenthesubscriberand
publisher.

ThisdiffersfromtheObserverpatternasitallowsanysubscriberimplementinganappropriateevent
handlertoregisterforandreceivetopicnotificationsbroadcastbythepublisher.

HereisanexampleofhowonemightusethePublish/Subscribeifprovidedwithafunctional
implementationpowering publish() , subscribe() and unsubscribe() behindthescenes:

1 //Averysimplenewmailhandler
2
3 //Acountofthenumberofmessagesreceived
4 varmailCounter=0;
5
6 //Initializesubscribersthatwilllistenoutforatopic
7 //withthename"inbox/newMessage".
8
9 //Renderapreviewofnewmessages
10 varsubscriber1=subscribe("inbox/newMessage",function(topic,data){
11
12 //Logthetopicfordebuggingpurposes
13 console.log("Anewmessagewasreceived:",topic);
14
15 //Usethedatathatwaspassedfromoursubject
16 //todisplayamessagepreviewtotheuser
17 $(".messageSender").html(data.sender);
18 $(".messagePreview").html(data.body);
19
20 });
21
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 39/188
26/04/2015 LearningJavaScriptDesignPatterns

22 //Here'sanothersubscriberusingthesamedatatoperform
23 //adifferenttask.
24
25 //Updatethecounterdisplayingthenumberofnew
26 //messagesreceivedviathepublisher
27
28 varsubscriber2=subscribe("inbox/newMessage",function(topic,data){
29
30 $('.newMessageCounter').html(++mailCounter);
31
32 });
33
34 publish("inbox/newMessage",[{
35 sender:"hello@google.com",
36 body:"Heythere!Howareyoudoingtoday?"
37 }]);
38
39 //Wecouldthenatalaterpointunsubscribeoursubscribers
40 //fromreceivinganynewtopicnotificationsasfollows:
41 //unsubscribe(subscriber1);
42 //unsubscribe(subscriber2);

Thegeneralideahereisthepromotionofloosecoupling.Ratherthansingleobjectscallingonthe
methodsofotherobjectsdirectly,theyinsteadsubscribetoaspecifictaskoractivityofanotherobject
andarenotifiedwhenitoccurs.

Advantages
TheObserverandPublish/Subscribepatternsencourageustothinkhardabouttherelationships
betweendifferentpartsofourapplication.Theyalsohelpusidentifywhatlayerscontainingdirect
relationshipswhichcouldinsteadbereplacedwithsetsofsubjectsandobservers.Thiseffectivelycould
beusedtobreakdownanapplicationintosmaller,morelooselycoupledblockstoimprovecode
managementandpotentialsforreuse.

FurthermotivationbehindusingtheObserverpatterniswhereweneedtomaintainconsistency
betweenrelatedobjectswithoutmakingclassestightlycoupled.Forexample,whenanobjectneedsto
beabletonotifyotherobjectswithoutmakingassumptionsregardingthoseobjects.

Dynamicrelationshipscanexistbetweenobserversandsubjectswhenusingeitherpattern.This
providesagreatdealofflexibilitywhichmaynotbeaseasytoimplementwhendisparatepartsofour
applicationaretightlycoupled.

Whilstitmaynotalwaysbethebestsolutiontoeveryproblem,thesepatternsremainoneofthebest
toolsfordesigningdecoupledsystemsandshouldbeconsideredanimportanttoolinanyJavaScript
developersutilitybelt.

Disadvantages
Consequently,someoftheissueswiththesepatternsactuallystemfromtheirmainbenefits.In
Publish/Subscribe,bydecouplingpublishersfromsubscribers,itcansometimesbecomedifficultto
obtainguaranteesthatparticularpartsofourapplicationsarefunctioningaswemayexpect.

Forexample,publishersmaymakeanassumptionthatoneormoresubscribersarelisteningtothem.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 40/188
26/04/2015 LearningJavaScriptDesignPatterns

Saythatwereusingsuchanassumptiontologoroutputerrorsregardingsomeapplicationprocess.If
thesubscriberperformingtheloggingcrashes(orforsomereasonfailstofunction),thepublisherwont
haveawayofseeingthisduetothedecouplednatureofthesystem.

Anotherdrawbackofthepatternisthatsubscribersarequiteignoranttotheexistenceofeachotherand
areblindtothecostofswitchingpublishers.Duetothedynamicrelationshipbetweensubscribersand
publishers,theupdatedependencycanbedifficulttotrack.

Publish/SubscribeImplementations
Publish/SubscribefitsinverywellinJavaScriptecosystems,largelybecauseatthecore,ECMAScript
implementationsareeventdriven.ThisisparticularlytrueinbrowserenvironmentsastheDOMuses
eventsasitsmaininteractionAPIforscripting.

Thatsaid,neitherECMAScriptnorDOMprovidecoreobjectsormethodsforcreatingcustomevents
systemsinimplementationcode(withtheexceptionofperhapstheDOM3CustomEvent,whichis
boundtotheDOMandisthusnotgenericallyuseful).

Luckily,popularJavaScriptlibrariessuchasdojo,jQuery(customevents)andYUIalreadyhaveutilities
thatcanassistineasilyimplementingaPublish/Subscribesystemwithverylittleeffort.Belowwecan
seesomeexamplesofthis:

1 //Publish
2
3 //jQuery:$(obj).trigger("channel",[arg1,arg2,arg3]);
4 $(el).trigger("/login",[{username:"test",userData:"test"}]);
5
6 //Dojo:dojo.publish("channel",[arg1,arg2,arg3]);
7 dojo.publish("/login",[{username:"test",userData:"test"}]);
8
9 //YUI:el.publish("channel",[arg1,arg2,arg3]);
10 el.publish("/login",{username:"test",userData:"test"});
11
12
13 //Subscribe
14
15 //jQuery:$(obj).on("channel",[data],fn);
16 $(el).on("/login",function(event){...});
17
18 //Dojo:dojo.subscribe("channel",fn);
19 varhandle=dojo.subscribe("/login",function(data){..});
20
21 //YUI:el.on("channel",handler);
22 el.on("/login",function(data){...});
23
24
25 //Unsubscribe
26
27 //jQuery:$(obj).off("channel");
28 $(el).off("/login");
29
30 //Dojo:dojo.unsubscribe(handle);
31 dojo.unsubscribe(handle);
32
33 //YUI:el.detach("channel");
34 el.detach("/login");

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 41/188
26/04/2015 LearningJavaScriptDesignPatterns

ForthosewishingtousethePublish/SubscribepatternwithvanillaJavaScript(oranotherlibrary)
AmplifyJSincludesaclean,libraryagnosticimplementationthatcanbeusedwithanylibraryortoolkit.
Radio.js(http://radio.uxder.com/),PubSubJS(https://github.com/mroderick/PubSubJS)orPureJS
PubSubbyPeterHiggins(https://github.com/phiggins42/bloodyjquery
plugins/blob/55e41df9bf08f42378bb08b93efcb28555b61aeb/pubsub.js)arealsosimilaralternativesworth
checkingout.

jQuerydevelopersinparticularhavequiteafewotheroptionsandcanopttouseoneofthemanywell
developedimplementationsrangingfromPeterHigginssjQueryplugintoBenAlmans(optimized)
Pub/SubjQuerygistonGitHub.Linkstojustafewofthesecanbefoundbelow.

BenAlmansPub/Subgisthttps://gist.github.com/661855(recommended)
RickWaldronsjQuerycorestyletakeontheabovehttps://gist.github.com/705311
PeterHigginspluginhttp://github.com/phiggins42/bloodyjquery
plugins/blob/master/pubsub.js.
AppendTosPub/SubinAmplifyJShttp://amplifyjs.com
BenTruymansgisthttps://gist.github.com/826794

SothatweareabletogetanappreciationforhowmanyofthevanillaJavaScriptimplementationsofthe
Observerpatternmightwork,letstakeawalkthroughofaminimalistversionofPublish/SubscribeI
releasedonGitHubunderaprojectcalledpubsubz.Thisdemonstratesthecoreconceptsofsubscribe,
publishaswellastheconceptofunsubscribing.

Iveoptedtobaseourexamplesonthiscodeasitstickscloselytoboththemethodsignaturesand
approachofimplementationIwouldexpecttoseeinaJavaScriptversionoftheclassicObserverpattern.

APublish/SubscribeImplementation

1 varpubsub={};
2
3 (function(myObject){
4
5 //Storagefortopicsthatcanbebroadcast
6 //orlistenedto
7 vartopics={};
8
9 //Antopicidentifier
10 varsubUid=1;
11
12 //Publishorbroadcasteventsofinterest
13 //withaspecifictopicnameandarguments
14 //suchasthedatatopassalong
15 myObject.publish=function(topic,args){
16
17 if(!topics[topic]){
18 returnfalse;
19 }
20
21 varsubscribers=topics[topic],
22 len=subscribers?subscribers.length:0;
23
24 while(len){
25 subscribers[len].func(topic,args);
26 }
27
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 42/188
26/04/2015 LearningJavaScriptDesignPatterns

28 returnthis;
29 };
30
31 //Subscribetoeventsofinterest
32 //withaspecifictopicnameanda
33 //callbackfunction,tobeexecuted
34 //whenthetopic/eventisobserved
35 myObject.subscribe=function(topic,func){
36
37 if(!topics[topic]){
38 topics[topic]=[];
39 }
40
41 vartoken=(++subUid).toString();
42 topics[topic].push({
43 token:token,
44 func:func
45 });
46 returntoken;
47 };
48
49 //Unsubscribefromaspecific
50 //topic,basedonatokenizedreference
51 //tothesubscription
52 myObject.unsubscribe=function(token){
53 for(varmintopics){
54 if(topics[m]){
55 for(vari=0,j=topics[m].length;i<j;i++){
56 if(topics[m][i].token===token){
57 topics[m].splice(i,1);
58 returntoken;
59 }
60 }
61 }
62 }
63 returnthis;
64 };
65 }(pubsub));

Example:UsingOurImplementation

Wecannowusetheimplementationtopublishandsubscribetoeventsofinterestasfollows:

1 //Anothersimplemessagehandler
2
3 //Asimplemessageloggerthatlogsanytopicsanddatareceivedthroughour
4 //subscriber
5 varmessageLogger=function(topics,data){
6 console.log("Logging:"+topics+":"+data);
7 };
8
9 //Subscriberslistenfortopicstheyhavesubscribedtoand
10 //invokeacallbackfunction(e.gmessageLogger)onceanew
11 //notificationisbroadcastonthattopic
12 varsubscription=pubsub.subscribe("inbox/newMessage",messageLogger);
13
14 //Publishersareinchargeofpublishingtopicsornotificationsof
15 //interesttotheapplication.e.g:
16
17 pubsub.publish("inbox/newMessage","helloworld!");
18
19 //or
20 pubsub.publish("inbox/newMessage",["test","a","b","c"]);
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 43/188
26/04/2015 LearningJavaScriptDesignPatterns

21
22 //or
23 pubsub.publish("inbox/newMessage",{
24 sender:"hello@google.com",
25 body:"Heyagain!"
26 });
27
28 //Wecanalsounsubscribeifwenolongerwishforoursubscribers
29 //tobenotified
30 pubsub.unsubscribe(subscription);
31
32 //Onceunsubscribed,thisforexamplewon'tresultinour
33 //messageLoggerbeingexecutedasthesubscriberis
34 //nolongerlistening
35 pubsub.publish("inbox/newMessage","Hello!areyoustillthere?");

Example:UserInterfaceNotifications

Next,letsimaginewehaveawebapplicationresponsiblefordisplayingrealtimestockinformation.

Theapplicationmighthaveagridfordisplayingthestockstatsandacounterfordisplayingthelast
pointofupdate.Whenthedatamodelchanges,theapplicationwillneedtoupdatethegridandcounter.
Inthisscenario,oursubject(whichwillbepublishingtopics/notifications)isthedatamodelandour
subscribersarethegridandcounter.

Whenoursubscribersreceivenotificationthatthemodelitselfhaschanged,theycanupdatethemselves
accordingly.

Inourimplementation,oursubscriberwilllistentothetopicnewDataAvailabletofindoutifnew
stockinformationisavailable.Ifanewnotificationispublishedtothistopic,itwilltrigger gridUpdate to
addanewrowtoourgridcontainingthisinformation.Itwillalsoupdatealastupdatedcountertolog
thelasttimedatawasadded

1 //ReturnthecurrentlocaltimetobeusedinourUIlater
2 getCurrentTime=function(){
3
4 vardate=newDate(),
5 m=date.getMonth()+1,
6 d=date.getDate(),
7 y=date.getFullYear(),
8 t=date.toLocaleTimeString().toLowerCase();
9
10 return(m+"/"+d+"/"+y+""+t);
11 };
12
13 //Addanewrowofdatatoourfictionalgridcomponent
14 functionaddGridRow(data){
15
16 //ui.grid.addRow(data);
17 console.log("updatedgridcomponentwith:"+data);
18
19 }
20
21 //Updateourfictionalgridtoshowthetimeitwaslast
22 //updated
23 functionupdateCounter(data){
24
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 44/188
26/04/2015 LearningJavaScriptDesignPatterns

25 //ui.grid.updateLastChanged(getCurrentTime());
26 console.log("datalastupdatedat:"+getCurrentTime()+"with"+data);
27
28 }
29
30 //Updatethegridusingthedatapassedtooursubscribers
31 gridUpdate=function(topic,data){
32
33 if(data!==undefined){
34 addGridRow(data);
35 updateCounter(data);
36 }
37
38 };
39
40 //CreateasubscriptiontothenewDataAvailabletopic
41 varsubscriber=pubsub.subscribe("newDataAvailable",gridUpdate);
42
43 //Thefollowingrepresentsupdatestoourdatalayer.Thiscouldbe
44 //poweredbyajaxrequestswhichbroadcastthatnewdataisavailable
45 //totherestoftheapplication.
46
47 //PublishchangestothegridUpdatedtopicrepresentingnewentries
48 pubsub.publish("newDataAvailable",{
49 summary:"Applemade$5billion",
50 identifier:"APPL",
51 stockPrice:570.91
52 });
53
54 pubsub.publish("newDataAvailable",{
55 summary:"Microsoftmade$20million",
56 identifier:"MSFT",
57 stockPrice:30.85
58 });

Example:DecouplingapplicationsusingBenAlmansPub/Subimplementation

Inthefollowingmovieratingsexample,wellbeusingBenAlmansjQueryimplementationof
Publish/Subscribetodemonstratehowwecandecoupleauserinterface.Noticehowsubmittingarating
onlyhastheeffectofpublishingthefactthatnewuserandratingdataisavailable.

Itsleftuptothesubscriberstothosetopicstothendelegatewhathappenswiththatdata.Inourcase
werepushingthatnewdataintoexistingarraysandthenrenderingthemusingtheUnderscorelibrarys
.template() methodfortemplating.

HTML/Templates

1 <scriptid="userTemplate"type="text/html">
2 <li><%=name%></li>
3 </script>
4
5
6 <scriptid="ratingsTemplate"type="text/html">
7 <li><strong><%=title%></strong>wasrated<%=rating%>/5</li>
8 </script>
9
10
11 <divid="container">
12
13 <divclass="sampleForm">
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 45/188
26/04/2015 LearningJavaScriptDesignPatterns

14 <p>
15 <labelfor="twitter_handle">Twitterhandle:</label>
16 <inputtype="text"id="twitter_handle"/>
17 </p>
18 <p>
19 <labelfor="movie_seen">Nameamovieyou'veseenthisyear:</label>
20 <inputtype="text"id="movie_seen"/>
21 </p>
22 <p>
23
24 <labelfor="movie_rating">Ratethemovieyousaw:</label>
25 <selectid="movie_rating">
26 <optionvalue="1">1</option>
27 <optionvalue="2">2</option>
28 <optionvalue="3">3</option>
29 <optionvalue="4">4</option>
30 <optionvalue="5"selected>5</option>
31
32 </select>
33 </p>
34 <p>
35
36 <buttonid="add">Submitrating</button>
37 </p>
38 </div>
39
40
41
42 <divclass="summaryTable">
43 <divid="users"><h3>Recentusers</h3></div>
44 <divid="ratings"><h3>Recentmoviesrated</h3></div>
45 </div>
46
47 </div>

JavaScript
?

1 ;(function($){
2
3 //Precompiletemplatesand"cache"themusingclosure
4 var
5 userTemplate=_.template($("#userTemplate").html()),
6 ratingsTemplate=_.template($("#ratingsTemplate").html());
7
8 //Subscribetothenewusertopic,whichaddsauser
9 //toalistofuserswhohavesubmittedreviews
10 $.subscribe("/new/user",function(e,data){
11
12 if(data){
13
14 $('#users').append(userTemplate(data));
15
16 }
17
18 });
19
20 //Subscribetothenewratingtopic.Thisiscomposedofatitleand
21 //rating.Newratingsareappendedtoarunninglistofaddeduser
22 //ratings.
23 $.subscribe("/new/rating",function(e,data){
24
25 if(data){
26
27 $("#ratings").append(ratingsTemplate(data));
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 46/188
26/04/2015 LearningJavaScriptDesignPatterns

28
29 }
30
31 });
32
33 //Handlerforaddinganewuser
34 $("#add").on("click",function(e){
35
36 e.preventDefault();
37
38 varstrUser=$("#twitter_handle").val(),
39 strMovie=$("#movie_seen").val(),
40 strRating=$("#movie_rating").val();
41
42 //Informtheapplicationanewuserisavailable
43 $.publish("/new/user",{name:strUser});
44
45 //Informtheappanewratingisavailable
46 $.publish("/new/rating",{title:strMovie,rating:strRating});
47
48 });
49
50 })(jQuery);

Example:DecouplinganAjaxbasedjQueryapplication

Inourfinalexample,weregoingtotakeapracticallookathowdecouplingourcodeusingPub/Sub
earlyoninthedevelopmentprocesscansaveussomepotentiallypainfulrefactoringlateron.

QuiteofteninAjaxheavyapplications,oncewevereceivedaresponsetoarequestwewanttoachieve
morethanjustoneuniqueaction.Onecouldsimplyaddalloftheirpostrequestlogicintoasuccess
callback,buttherearedrawbackstothisapproach.

Highlycoupledapplicationssometimesincreasetheeffortrequiredtoreusefunctionalityduetothe
increasedinterfunction/codedependency.Whatthismeansisthatalthoughkeepingourpostrequest
logichardcodedinacallbackmightbefineifwerejusttryingtograbaresultsetonce,itsnotas
appropriatewhenwewanttomakefurtherAjaxcallstothesamedatasource(anddifferentend
behavior)withoutrewritingpartsofthecodemultipletimes.Ratherthanhavingtogobackthrough
eachlayerthatcallsthesamedatasourceandgeneralizingthemlateron,wecanusepub/subfromthe
startandsavetime.

UsingObservers,wecanalsoeasilyseparateapplicationwidenotificationsregardingdifferentevents
downtowhateverlevelofgranularitywerecomfortablewithsomethingwhichcanbelesselegantly
doneusingotherpatterns.

Noticehowinoursamplebelow,onetopicnotificationismadewhenauserindicatestheywantto
makeasearchqueryandanotherismadewhentherequestreturnsandactualdataisavailablefor
consumption.Itsleftuptothesubscriberstothendecidehowtouseknowledgeoftheseevents(orthe
datareturned).Thebenefitsofthisarethat,ifwewanted,wecouldhave10differentsubscribers
utilizingthedatareturnedindifferentwaysbutasfarastheAjaxlayerisconcerned,itdoesntcare.Its
soledutyistorequestandreturndatathenpassitontowhoeverwantstouseit.Thisseparationof
concernscanmaketheoveralldesignofourcodealittlecleaner.

HTML/Templates:
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 47/188
26/04/2015 LearningJavaScriptDesignPatterns
?
1 <formid="flickrSearch">
2
3 <inputtype="text"name="tag"id="query"/>
4
5 <inputtype="submit"name="submit"value="submit"/>
6
7 </form>
8
9
10
11 <divid="lastQuery"></div>
12
13 <olid="searchResults"></ol>
14
15
16
17 <scriptid="resultTemplate"type="text/html">
18 <%_.each(items,function(item){%>
19 <li><imgsrc="<%=item.media.m%>"/></li>
20 <%});%>
21 </script>

JavaScript:
?

1 ;(function($){
2
3 //Precompiletemplateand"cache"itusingclosure
4 varresultTemplate=_.template($("#resultTemplate").html());
5
6 //Subscribetothenewsearchtagstopic
7 $.subscribe("/search/tags",function(e,tags){
8 $("#lastQuery")
9 .html("<p>Searchedfor:<strong>"+tags+"</strong></p>");
10 });
11
12 //Subscribetothenewresultstopic
13 $.subscribe("/search/resultSet",function(e,results){
14
15 $("#searchResults").empty().append(resultTemplate(results));
16
17 });
18
19 //Submitasearchqueryandpublishtagsonthe/search/tagstopic
20 $("#flickrSearch").submit(function(e){
21
22 e.preventDefault();
23 vartags=$(this).find("#query").val();
24
25 if(!tags){
26 return;
27 }
28
29 $.publish("/search/tags",[$.trim(tags)]);
30
31 });
32
33
34 //Subscribetonewtagsbeingpublishedandperform
35 //asearchqueryusingthem.Oncedatahasreturned
36 //publishthisdatafortherestoftheapplication
37 //toconsume
38
39 $.subscribe("/search/tags",function(e,tags){
40
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 48/188
26/04/2015 LearningJavaScriptDesignPatterns

41 $.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallbac
42 tags:tags,
43 tagmode:"any",
44 format:"json"
45 },
46
47 function(data){
48
49 if(!data.items.length){
50 return;
51 }
52
53 $.publish("/search/resultSet",{items:data.items});
54 });
55
56 });
57
58
59 })(jQuery);

TheObserverpatternisusefulfordecouplinganumberofdifferentscenariosinapplicationdesignand
ifyouhaventbeenusingit,Irecommendpickinguponeoftheprewrittenimplementationsmentioned
todayandjustgivingitatryout.Itsoneoftheeasierdesignpatternstogetstartedwithbutalsooneof
themostpowerful.

TheMediatorPattern
InthesectionontheObserverpattern,wewereintroducedtoawayofchannelingmultipleevent
sourcesthroughasingleobject.ThisisalsoknownasPublish/SubscribeorEventAggregation.Its
commonfordeveloperstothinkofMediatorswhenfacedwiththisproblem,soletsexplorehowthey
differ.

Thedictionaryreferstoamediatorasaneutralpartythatassistsinnegotiationsandconflictresolution.In
ourworld,amediatorisabehavioraldesignpatternthatallowsustoexposeaunifiedinterfacethrough
whichthedifferentpartsofasystemmaycommunicate.

Ifitappearsasystemhastoomanydirectrelationshipsbetweencomponents,itmaybetimetohavea
centralpointofcontrolthatcomponentscommunicatethroughinstead.TheMediatorpromotesloose
couplingbyensuringthatinsteadofcomponentsreferringtoeachotherexplicitly,theirinteractionis
handledthroughthiscentralpoint.Thiscanhelpusdecouplesystemsandimprovethepotentialfor
componentreusability.

Arealworldanalogycouldbeatypicalairporttrafficcontrolsystem.Atower(Mediator)handleswhat
planescantakeoffandlandbecauseallcommunications(notificationsbeinglistenedoutforor
broadcast)aredonefromtheplanestothecontroltower,ratherthanfromplanetoplane.Acentralized
controlleriskeytothesuccessofthissystemandthatsreallytheroleaMediatorplaysinsoftware
design.

AnotheranalogywouldbeDOMeventbubblingandeventdelegation.Ifallsubscriptionsinasystem
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 49/188
26/04/2015 LearningJavaScriptDesignPatterns

aremadeagainstthedocumentratherthanindividualnodes,thedocumenteffectivelyservesasa
Mediator.Insteadofbindingtotheeventsoftheindividualnodes,ahigherlevelobjectisgiventhe
responsibilityofnotifyingsubscribersaboutinteractionevents.

WhenitcomestotheMediatorandEventAggregatorpatterns,therearesometimeswhereitmaylook
likethepatternsareinterchangeableduetoimplementationsimilarities.However,thesemanticsand
intentofthesepatternsareverydifferent.

Andeveniftheimplementationsbothusesomeofthesamecoreconstructs,Ibelievethereisadistinct
differencebetweenthem.Ialsobelievetheyshouldnotbeinterchangedorconfusedincommunication
becauseofthedifferences.

ASimpleMediator

AMediatorisanobjectthatcoordinatesinteractions(logicandbehavior)betweenmultipleobjects.It
makesdecisionsonwhentocallwhichobjects,basedontheactions(orinaction)ofotherobjectsand
input.

Youcanwriteamediatorusingasinglelineofcode:

1 varmediator={};

Yes,ofcoursethisisjustanobjectliteralinJavaScript.Onceagain,weretalkingaboutsemanticshere.
Thepurposeofthemediatoristocontroltheworkflowbetweenobjectsandwereallydontneed
anythingmorethananobjectliteraltodothis.

1 varorgChart={
2
3 addNewEmployee:function(){
4
5 //getEmployeeDetailprovidesaviewthatusersinteractwith
6 varemployeeDetail=this.getEmployeeDetail();
7
8 //whentheemployeedetailiscomplete,themediator(the'orgchart'object)
9 //decideswhatshouldhappennext
10 employeeDetail.on("complete",function(employee){
11
12 //setupadditionalobjectsthathaveadditionalevents,whichareused
13 //bythemediatortodoadditionalthings
14 varmanagerSelector=this.selectManager(employee);
15 managerSelector.on("save",function(employee){
16 employee.save();
17 });
18
19 });
20 },
21
22 //...
23 }

Thisexampleshowsaverybasicimplementationofamediatorobjectwithsomeutilitymethodsthat
cantriggerandsubscribetoevents.
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 50/188
26/04/2015 LearningJavaScriptDesignPatterns

Iveoftenreferredtothistypeofobjectasaworkflowobjectinthepast,butthetruthisthatitisa
mediator.Itisanobjectthathandlestheworkflowbetweenmanyotherobjects,aggregatingthe
responsibilityofthatworkflowknowledgeintoasingleobject.Theresultisworkflowthatiseasierto
understandandmaintain.

SimilaritiesAndDifferences

Thereare,withoutadoubt,similaritiesbetweentheeventaggregatorandmediatorexamplesthatIve
shownhere.Thesimilaritiesboildowntotwoprimaryitems:eventsandthirdpartyobjects.These
differencesaresuperficialatbest,though.Whenwedigintotheintentofthepatternandseethatthe
implementationscanbedramaticallydifferent,thenatureofthepatternsbecomemoreapparent.

Events
Boththeeventaggregatorandmediatoruseevents,intheaboveexamples.Aneventaggregator
obviouslydealswitheventsitsinthenameafterall.Themediatoronlyuseseventsbecauseitmakes
lifeeasywhendealingwithmodernJavaScriptwebappframeworks.Thereisnothingthatsaysa
mediatormustbebuiltwithevents.Youcanbuildamediatorwithcallbackmethods,byhandingthe
mediatorreferencetothechildobject,orbyanyofanumberofothermeans.

Thedifference,then,iswhythesetwopatternsarebothusingevents.Theeventaggregator,asapattern,
isdesignedtodealwithevents.Themediator,though,onlyusesthembecauseitsconvenient.

ThirdPartyObjects
Boththeeventaggregatorandmediator,bydesign,useathirdpartyobjecttofacilitatethings.Theevent
aggregatoritselfisathirdpartytotheeventpublisherandtheeventsubscriber.Itactsasacentralhub
foreventstopassthrough.Themediatorisalsoathirdpartytootherobjects,though.Sowhereisthe
difference?Whydontwecallaneventaggregatoramediator?Theanswerlargelycomesdownto
wheretheapplicationlogicandworkflowiscoded.

Inthecaseofaneventaggregator,thethirdpartyobjectisthereonlytofacilitatethepassthroughof
eventsfromanunknownnumberofsourcestoanunknownnumberofhandlers.Allworkflowand
businesslogicthatneedstobekickedoffisputdirectlyintotheobjectthattriggerstheeventsandthe
objectsthathandletheevents.

Inthecaseofthemediator,though,thebusinesslogicandworkflowisaggregatedintothemediator
itself.Themediatordecideswhenanobjectshouldhaveitsmethodscalledandattributesupdatedbased
onfactorsthatthemediatorknowsabout.Itencapsulatestheworkflowandprocess,coordinating
multipleobjectstoproducethedesiredsystembehaviour.Theindividualobjectsinvolvedinthis
workfloweachknowhowtoperformtheirowntask.Butitsthemediatorthattellstheobjectswhento
performthetasksbymakingdecisionsatahigherlevelthantheindividualobjects.

Aneventaggregatorfacilitatesafireandforgetmodelofcommunication.Theobjecttriggeringthe
eventdoesntcareifthereareanysubscribers.Itjustfirestheeventandmoveson.Amediator,though,
mightuseeventstomakedecisions,butitisdefinitelynotfireandforget.Amediatorpaysattention
toaknownsetofinputoractivitiessothatitcanfacilitateandcoordinateadditionalbehaviorwitha
knownsetofactors(objects).

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 51/188
26/04/2015 LearningJavaScriptDesignPatterns

Relationships:WhenToUseWhich

Understandingthesimilaritiesanddifferencesbetweenaneventaggregatorandmediatorisimportant
forsemanticreasons.Itsequallyasimportanttounderstandwhentousewhichpattern,though.The
basicsemanticsandintentofthepatternsdoesinformthequestionofwhen,butactualexperiencein
usingthepatternswillhelpyouunderstandthemoresubtlepointsandnuanceddecisionsthathaveto
bemade.

EventAggregatorUse
Ingeneral,aneventaggregatorisusedwhenyoueitherhavetoomanyobjectstolistentodirectly,or
youhaveobjectsthatareentirelyunrelated.

Whentwoobjectshaveadirectrelationshipalreadysay,aparentviewandchildviewthenthere
mightbelittlebenefitinusinganeventaggregator.Havethechildviewtriggeraneventandtheparent
viewcanhandletheevent.InJavaScriptframeworkterms,thisismostcommonlyseeninBackbones
CollectionandModel,whereallModeleventsarebubbleduptoandthroughitsparentCollection.A
Collectionoftenusesmodeleventstomodifythestateofitselforothermodels.Handlingselected
itemsinacollectionisagoodexampleofthis.

jQuerysonmethodasaneventaggregatorisagreatexampleoftoomanyobjectstolistento.Ifyou
have10,20or200DOMelementsthatcantriggeraclickevent,itmightbeabadideatosetupa
listeneronallofthemindividually.Thiscouldquicklydeteriorateperformanceoftheapplicationand
userexperience.Instead,usingjQuerysonmethodallowsustoaggregatealloftheeventsandreduce
theoverheadof10,20,or200eventhandlersdownto1.

Indirectrelationshipsarealsoagreattimetouseeventaggregators.Inmodernapplications,itisvery
commontohavemultipleviewobjectsthatneedtocommunicate,buthavenodirectrelationship.For
example,amenusystemmighthaveaviewthathandlesthemenuitemclicks.Butwedontwantthe
menutobedirectlytiedtothecontentviewsthatshowallofthedetailsandinformationwhenamenu
itemisclicked.Havingthecontentandmenucoupledtogetherwouldmakethecodeverydifficultto
maintain,inthelongrun.Instead,wecanuseaneventaggregatortotriggermenu:click:fooevents,
andhaveafooobjecthandletheclickeventtoshowitscontentonthescreen.

MediatorUse
Amediatorisbestappliedwhentwoormoreobjectshaveanindirectworkingrelationship,and
businesslogicorworkflowneedstodictatetheinteractionsandcoordinationoftheseobjects.

Awizardinterfaceisagoodexampleofthis,asshownwiththeorgChartexample,above.Thereare
multipleviewsthatfacilitatetheentireworkflowofthewizard.Ratherthantightlycouplingtheview
togetherbyhavingthemreferenceeachotherdirectly,wecandecouplethemandmoreexplicitlymodel
theworkflowbetweenthembyintroducingamediator.

Themediatorextractstheworkflowfromtheimplementationdetailsandcreatesamorenatural
abstractionatahigherlevel,showingusatamuchfasterglancewhatthatworkflowis.Wenolonger
havetodigintothedetailsofeachviewintheworkflow,toseewhattheworkflowactuallyis.

EventAggregator(Pub/Sub)AndMediatorTogether

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 52/188
26/04/2015 LearningJavaScriptDesignPatterns

Thecruxofthedifferencebetweenaneventaggregatorandamediator,andwhythesepatternnames
shouldnotbeinterchangedwitheachother,isillustratedbestbyshowinghowtheycanbeused
together.Themenuexampleforaneventaggregatoristheperfectplacetointroduceamediatoraswell.

Clickingamenuitemmaytriggeraseriesofchangesthroughoutanapplication.Someofthesechanges
willbeindependentofothers,andusinganeventaggregatorforthismakessense.Someofthese
changesmaybeinternallyrelatedtoeachother,though,andmayuseamediatortoenactthosechanges.

Amediator,then,couldbesetuptolistentotheeventaggregator.Itcouldrunitslogicandprocessto
facilitateandcoordinatemanyobjectsthatarerelatedtoeachother,butunrelatedtotheoriginalevent
source.

1 varMenuItem=MyFrameworkView.extend({
2
3 events:{
4 "click.thatThing":"clickedIt"
5 },
6
7 clickedIt:function(e){
8 e.preventDefault();
9
10 //assumethistriggers"menu:click:foo"
11 MyFramework.trigger("menu:click:"+this.model.get("name"));
12 }
13
14 });
15
16 //...somewhereelseintheapp
17
18 varMyWorkflow=function(){
19 MyFramework.on("menu:click:foo",this.doStuff,this);
20 };
21
22 MyWorkflow.prototype.doStuff=function(){
23 //instantiatemultipleobjectshere.
24 //setupeventhandlersforthoseobjects.
25 //coordinatealloftheobjectsintoameaningfulworkflow.
26 };

Inthisexample,whentheMenuItemwiththerightmodelisclicked,the menu:click:foo eventwillbe


triggered.AninstanceoftheMyWorkflowobject,assumingoneisalreadyinstantiated,willhandle
thisspecificeventandwillcoordinatealloftheobjectsthatitknowsabout,tocreatethedesireduser
experienceandworkflow.

Aneventaggregatorandamediatorhavebeencombinedtocreateamuchmoremeaningfulexperience
inboththecodeandtheapplicationitself.Wenowhaveacleanseparationbetweenthemenuandthe
workflowthroughaneventaggregatorandwearestillkeepingtheworkflowitselfcleanand
maintainablethroughtheuseofamediator.

Advantages&Disadvantages
ThelargestbenefitoftheMediatorpatternisthatitreducesthecommunicationchannelsneeded
betweenobjectsorcomponentsinasystemfrommanytomanytojustmanytoone.Addingnew
publishersandsubscribersisrelativelyeasyduetothelevelofdecouplingpresent.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 53/188
26/04/2015 LearningJavaScriptDesignPatterns

Perhapsthebiggestdownsideofusingthepatternisthatitcanintroduceasinglepointoffailure.
PlacingaMediatorbetweenmodulescanalsocauseaperformancehitastheyarealways
communicatingindirectly.Becauseofthenatureofloosecoupling,itsdifficulttoestablishhowa
systemmightreactbyonlylookingatthebroadcasts.

Thatsaid,itsusefultoremindourselvesthatdecoupledsystemshaveanumberofotherbenefitsifour
modulescommunicatedwitheachotherdirectly,changestomodules(e.ganothermodulethrowingan
exception)couldeasilyhaveadominoeffectontherestofourapplication.Thisproblemislessofa
concernwithdecoupledsystems.

Attheendoftheday,tightcouplingcausesallkindsofheadachesandthisisjustanotheralternative
solution,butonewhichcanworkverywellifimplementedcorrectly.

MediatorVs.Facade
WewillbecoveringtheFacadepatternshortly,butforreferencepurposessomedevelopersmayalso
wonderwhethertherearesimilaritiesbetweentheMediatorandFacadepatterns.Theydobothabstract
thefunctionalityofexistingmodules,buttherearesomesubtledifferences.

TheMediatorcentralizescommunicationbetweenmoduleswhereitsexplicitlyreferencedbythese
modules.Inasensethisismultidirectional.TheFacadehoweverjustdefinesasimplerinterfacetoa
moduleorsystembutdoesntaddanyadditionalfunctionality.Othermodulesinthesystemarent
directlyawareoftheconceptofafacadeandcouldbeconsideredunidirectional.

ThePrototypePattern
TheGoFrefertotheprototypepatternasonewhichcreatesobjectsbasedonatemplateofanexisting
objectthroughcloning.

Wecanthinkoftheprototypepatternasbeingbasedonprototypalinheritancewherewecreateobjects
whichactasprototypesforotherobjects.Theprototypeobjectitselfiseffectivelyusedasablueprintfor
eachobjecttheconstructorcreates.Iftheprototypeoftheconstructorfunctionusedcontainsaproperty
called name forexample(asperthecodesamplelowerdown),theneachobjectcreatedbythatsame
constructorwillalsohavethissameproperty.

Reviewingthedefinitionsforthispatterninexisting(nonJavaScript)literature,wemayfindreferences
toclassesonceagain.Therealityisthatprototypalinheritanceavoidsusingclassesaltogether.There
isntadefinitionobjectnoracoreobjectintheory.Weresimplycreatingcopiesofexistingfunctional
objects.

Oneofthebenefitsofusingtheprototypepatternisthatwereworkingwiththeprototypalstrengths
JavaScripthastooffernativelyratherthanattemptingtoimitatefeaturesofotherlanguages.Withother

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 54/188
26/04/2015 LearningJavaScriptDesignPatterns

designpatterns,thisisntalwaysthecase.

Notonlyisthepatternaneasywaytoimplementinheritance,butitcanalsocomewithaperformance
boostaswell:whendefiningafunctioninanobject,theyreallcreatedbyreference(soallchildobjects
pointtothesamefunction)insteadofcreatingtheirownindividualcopies.

Forthoseinterested,realprototypalinheritance,asdefinedintheECMAScript5standard,requiresthe
useof (whichwepreviouslylookedatearlierinthissection).Toremindourselves,
Object.create
Object.create createsanobjectwhichhasaspecifiedprototypeandoptionallycontainsspecified
propertiesaswell(e.g Object.create(prototype,optionalDescriptorObjects) ).

Wecanseethisdemonstratedintheexamplebelow:

1 varmyCar={
2
3 name:"FordEscort",
4
5 drive:function(){
6 console.log("Weeee.I'mdriving!");
7 },
8
9 panic:function(){
10 console.log("Wait.Howdoyoustopthisthing?");
11 }
12
13 };
14
15 //UseObject.createtoinstantiateanewcar
16 varyourCar=Object.create(myCar);
17
18 //Nowwecanseethatoneisaprototypeoftheother
19 console.log(yourCar.name);

alsoallowsustoeasilyimplementadvancedconceptssuchasdifferentialinheritance
Object.create
whereobjectsareabletodirectlyinheritfromotherobjects.Wesawearlierthat Object.create allowsus
toinitialiseobjectpropertiesusingthesecondsuppliedargument.Forexample:

1 varvehicle={
2 getModel:function(){
3 console.log("Themodelofthisvehicleis.."+this.model);
4 }
5 };
6
7 varcar=Object.create(vehicle,{
8
9 "id":{
10 value:MY_GLOBAL.nextId(),
11 //writable:false,configurable:falsebydefault
12 enumerable:true
13 },
14
15 "model":{
16 value:"Ford",
17 enumerable:true
18 }
19
20 });
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 55/188
26/04/2015 LearningJavaScriptDesignPatterns

Herethepropertiescanbeinitializedonthesecondargumentof Object.create usinganobjectliteral


withasyntaxsimilartothatusedbythe Object.defineProperties and Object.defineProperty methodsthat
welookedatpreviously.

Itisworthnotingthatprototypalrelationshipscancausetroublewhenenumeratingpropertiesof
objectsand(asCrockfordrecommends)wrappingthecontentsoftheloopina hasOwnProperty() check.

Ifwewishtoimplementtheprototypepatternwithoutdirectlyusing Object.create ,wecansimulatethe


patternaspertheaboveexampleasfollows:

1 varvehiclePrototype={
2
3 init:function(carModel){
4 this.model=carModel;
5 },
6
7 getModel:function(){
8 console.log("Themodelofthisvehicleis.."+this.model);
9 }
10 };
11
12
13 functionvehicle(model){
14
15 functionF(){};
16 F.prototype=vehiclePrototype;
17
18 varf=newF();
19
20 f.init(model);
21 returnf;
22
23 }
24
25 varcar=vehicle("FordEscort");
26 car.getModel();

Note:Thisalternativedoesnotallowtheusertodefinereadonlypropertiesinthesamemanner(asthe
vehiclePrototypemaybealteredifnotcareful).

AfinalalternativeimplementationofthePrototypepatterncouldbethefollowing:

1 varbeget=(function(){
2
3 functionF(){}
4
5 returnfunction(proto){
6 F.prototype=proto;
7 returnnewF();
8 };
9 })();

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 56/188
26/04/2015 LearningJavaScriptDesignPatterns

Onecouldreferencethismethodfromthe vehicle function.Note,howeverthat vehicle hereis


emulatingaconstructor,sincetheprototypepatterndoesnotincludeanynotionofinitializationbeyond
linkinganobjecttoaprototype.

TheCommandPattern
TheCommandpatternaimstoencapsulatemethodinvocation,requestsoroperationsintoasingle
objectandgivesustheabilitytobothparameterizeandpassmethodcallsaroundthatcanbeexecuted
atourdiscretion.Inaddition,itenablesustodecoupleobjectsinvokingtheactionfromtheobjects
whichimplementthem,givingusagreaterdegreeofoverallflexibilityinswappingoutconcreteclasses
(objects).

Concreteclassesarebestexplainedintermsofclassbasedprogramminglanguagesandarerelatedtothe
ideaofabstractclasses.Anabstractclassdefinesaninterface,butdoesntnecessarilyprovide
implementationsforallofitsmemberfunctions.Itactsasabaseclassfromwhichothersarederived.A
derivedclasswhichimplementsthemissingfunctionalityiscalledaconcreteclass.

ThegeneralideabehindtheCommandpatternisthatitprovidesusameanstoseparatethe
responsibilitiesofissuingcommandsfromanythingexecutingcommands,delegatingthisresponsibility
todifferentobjectsinstead.

Implementationwise,simplecommandobjectsbindtogetherbothanactionandtheobjectwishingto
invoketheaction.Theyconsistentlyincludeanexecutionoperation(suchas run() or execute() ).All
Commandobjectswiththesameinterfacecaneasilybeswappedasneededandthisisconsideredoneof
thelargerbenefitsofthepattern.

TodemonstratetheCommandpatternweregoingtocreateasimplecarpurchasingservice.

1 (function(){
2
3 varcarManager={
4
5 //requestinformation
6 requestInfo:function(model,id){
7 return"Theinformationfor"+model+"withID"+id+"isfoobar";
8 },
9
10 //purchasethecar
11 buyVehicle:function(model,id){
12 return"YouhavesuccessfullypurchasedItem"+id+",a"+model;
13 },
14
15 //arrangeaviewing
16 arrangeViewing:function(model,id){
17 return"Youhavesuccessfullybookedaviewingof"+model+"("+id+
18 }
19
20 };
21
22 })();

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 57/188
26/04/2015 LearningJavaScriptDesignPatterns

Takingalookattheabovecode,itwouldbetrivialtoinvokeour carManager methodsbydirectly


accessingtheobject.Wewouldallbeforgivenforthinkingthereisnothingwrongwiththis
technically,itscompletelyvalidJavaScript.Therearehoweverscenarioswherethismaybe
disadvantageous.

Forexample,imagineifthecoreAPIbehindthe carManager changed.Thiswouldrequireallobjects


directlyaccessingthesemethodswithinourapplicationtoalsobemodified.Thiscouldbeviewedasa
layerofcouplingwhicheffectivelygoesagainsttheOOPmethodologyoflooselycouplingobjectsas
muchaspossible.Instead,wecouldsolvethisproblembyabstractingtheAPIawayfurther.

Letsnowexpandonour carManager sothatourapplicationoftheCommandpatternresultsinthe


following:acceptanynamedmethodsthatcanbeperformedonthe carManager object,passingalongany
datathatmightbeusedsuchastheCarmodelandID.

Hereiswhatwewouldliketobeabletoachieve:

1 carManager.execute("buyVehicle","FordEscort","453543");

Asperthisstructureweshouldnowaddadefinitionforthe carManager.execute methodasfollows:

1 carManager.execute=function(name){
2 returncarManager[name]&&carManager[name].apply(carManager,[].slice.call(argum
3 };

Ourfinalsamplecallswouldthuslookasfollows:

1 carManager.execute("arrangeViewing","Ferrari","14523");
2 carManager.execute("requestInfo","FordMondeo","54323");
3 carManager.execute("requestInfo","FordEscort","34232");
4 carManager.execute("buyVehicle","FordEscort","34232");

TheFacadePattern
Whenweputupafacade,wepresentanoutwardappearancetotheworldwhichmayconcealavery
differentreality.Thiswastheinspirationforthenamebehindthenextpatternweregoingtoreview
theFacadepattern.Thispatternprovidesaconvenienthigherlevelinterfacetoalargerbodyofcode,
hidingitstrueunderlyingcomplexity.ThinkofitassimplifyingtheAPIbeingpresentedtoother
developers,somethingwhichalmostalwaysimprovesusability.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 58/188
26/04/2015 LearningJavaScriptDesignPatterns

FacadesareastructuralpatternwhichcanoftenbeseeninJavaScriptlibrarieslikejQuerywhere,
althoughanimplementationmaysupportmethodswithawiderangeofbehaviors,onlyafacadeor
limitedabstractionofthesemethodsispresentedtothepublicforuse.

ThisallowsustointeractwiththeFacadedirectlyratherthanthesubsystembehindthescenes.
WheneverweusejQuerys $(el).css() or $(el).animate() methods,wereactuallyusingaFacadethe
simplerpublicinterfacethatavoidsushavingtomanuallycallthemanyinternalmethodsinjQuery
corerequiredtogetsomebehaviorworking.ThisalsoavoidstheneedtomanuallyinteractwithDOM
APIsandmaintainstatevariables.

ThejQuerycoremethodsshouldbeconsideredintermediateabstractions.Themoreimmediateburden
todevelopersistheDOMAPIandfacadesarewhatmakethejQuerylibrarysoeasytouse.

Tobuildonwhatwevelearned,theFacadepatternbothsimplifiestheinterfaceofaclassanditalso
decouplestheclassfromthecodethatutilizesit.Thisgivesustheabilitytoindirectlyinteractwith
subsystemsinawaythatcansometimesbelesspronetoerrorthanaccessingthesubsystemdirectly.A
Facadesadvantagesincludeeaseofuseandoftenasmallsizefootprintinimplementingthepattern.

Letstakealookatthepatterninaction.Thisisanunoptimizedcodeexample,butherewereutilizinga
Facadetosimplifyaninterfaceforlisteningtoeventscrossbrowser.Wedothisbycreatingacommon
methodthatcanbeusedinonescodewhichdoesthetaskofcheckingfortheexistenceoffeaturesso
thatitcanprovideasafeandcrossbrowsercompatiblesolution.

1 varaddMyEvent=function(el,ev,fn){
2
3 if(el.addEventListener){
4 el.addEventListener(ev,fn,false);
5 }elseif(el.attachEvent){
6 el.attachEvent("on"+ev,fn);
7 }else{
8 el["on"+ev]=fn;
9 }
10
11 };

Inasimilarmanner,wereallfamiliarwithjQuerys $(document).ready(..) .Internally,thisisactually


beingpoweredbyamethodcalled bindReady() ,whichisdoingthis:

1 bindReady:function(){
2 ...
3 if(document.addEventListener){
4 //Usethehandyeventcallback
5 document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);
6
7 //Afallbacktowindow.onload,thatwillalwayswork
8 window.addEventListener("load",jQuery.ready,false);
9
10 //IfIEeventmodelisused
11 }elseif(document.attachEvent){
12
13 document.attachEvent("onreadystatechange",DOMContentLoaded);
14
15 //Afallbacktowindow.onload,thatwillalwayswork

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 59/188
26/04/2015 LearningJavaScriptDesignPatterns

16 window.attachEvent("onload",jQuery.ready);
17 ...

ThisisanotherexampleofaFacade,wheretherestoftheworldsimplyusesthelimitedinterface
exposedby $(document).ready(..) andthemorecompleximplementationpoweringitiskepthidden
fromsight.

Facadesdontjusthavetobeusedontheirown,however.Theycanalsobeintegratedwithother
patternssuchastheModulepattern.Aswecanseebelow,ourinstanceofthemodulepatternscontains
anumberofmethodswhichhavebeenprivatelydefined.AFacadeisthenusedtosupplyamuch
simplerAPItoaccessingthesemethods:

1 varmodule=(function(){
2
3 var_private={
4 i:5,
5 get:function(){
6 console.log("currentvalue:"+this.i);
7 },
8 set:function(val){
9 this.i=val;
10 },
11 run:function(){
12 console.log("running");
13 },
14 jump:function(){
15 console.log("jumping");
16 }
17 };
18
19 return{
20
21 facade:function(args){
22 _private.set(args.val);
23 _private.get();
24 if(args.run){
25 _private.run();
26 }
27 }
28 };
29 }());
30
31
32 //Outputs:"currentvalue:10"and"running"
33 module.facade({run:true,val:10});

Inthisexample,calling module.facade() willactuallytriggerasetofprivatebehaviorwithinthemodule,


butagain,theuserisntconcernedwiththis.wevemadeitmucheasierforthemtoconsumeafeature
withoutneedingtoworryaboutimplementationleveldetails.

Notesonabstraction
Facadesgenerallyhavefewdisadvantages,butoneconcernworthnotingisperformance.Namely,one
mustdeterminewhetherthereisanimplicitcosttotheabstractionaFacadeofferstoour
implementationandifso,whetherthiscostisjustifiable.GoingbacktothejQuerylibrary,mostofusare

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 60/188
26/04/2015 LearningJavaScriptDesignPatterns

awarethatboth getElementById("identifier") and $("#identifier") canbeusedtoqueryanelementona


pagebyitsID.

Didyouknowhoweverthat getElementById() onitsownissignificantlyfasterbyahighorderof


magnitude?TakealookatthisjsPerftesttoseeresultsonaperbrowserlevel:
http://jsperf.com/getelementbyidvsjqueryid.Nowofcourse,wehavetokeepinmindthatjQuery(and
Sizzleitsselectorengine)aredoingalotmorebehindthescenestooptimizeourquery(andthata
jQueryobject,notjustaDOMnodeisreturned).

ThechallengewiththisparticularFacadeisthatinordertoprovideanelegantselectorfunctioncapable
ofacceptingandparsingmultipletypesofqueries,thereisanimplicitcostofabstraction.Theuserisnt
requiredtoaccess jQuery.getById("identifier") or jQuery.getByClass("identifier") andsoon.Thatsaid,the
tradeoffinperformancehasbeentestedinpracticeovertheyearsandgiventhesuccessofjQuery,a
simpleFacadeactuallyworkedoutverywellfortheteam.

Whenusingthepattern,trytobeawareofanyperformancecostsinvolvedandmakeacallonwhether
theyareworththelevelofabstractionoffered.

TheFactoryPattern
TheFactorypatternisanothercreationalpatternconcernedwiththenotionofcreatingobjects.Whereit
differsfromtheotherpatternsinitscategoryisthatitdoesntexplicitlyrequireususeaconstructor.
Instead,aFactorycanprovideagenericinterfaceforcreatingobjects,wherewecanspecifythetypeof
factoryobjectwewishtobecreated.

ImaginethatwehaveaUIfactorywhereweareaskedtocreateatypeofUIcomponent.Ratherthan
creatingthiscomponentdirectlyusingthe new operatororviaanothercreationalconstructor,weaska
Factoryobjectforanewcomponentinstead.WeinformtheFactorywhattypeofobjectisrequired(e.g
Button,Panel)anditinstantiatesthis,returningittousforuse.

Thisisparticularlyusefuliftheobjectcreationprocessisrelativelycomplex,e.g.ifitstronglydepends
ondynamicfactorsorapplicationconfiguration.

ExamplesofthispatterncanbefoundinUIlibrariessuchasExtJSwherethemethodsforcreating
objectsorcomponentsmaybefurthersubclassed.

ThefollowingisanexamplethatbuildsuponourprevioussnippetsusingtheConstructorpatternlogic
todefinecars.ItdemonstrateshowaVehicleFactorymaybeimplementedusingtheFactorypattern:

1 //Types.jsConstructorsusedbehindthescenes
2
3 //Aconstructorfordefiningnewcars
4 functionCar(options){
5
6 //somedefaults
7 this.doors=options.doors||4;
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 61/188
26/04/2015 LearningJavaScriptDesignPatterns

8 this.state=options.state||"brandnew";
9 this.color=options.color||"silver";
10
11 }
12
13 //Aconstructorfordefiningnewtrucks
14 functionTruck(options){
15
16 this.state=options.state||"used";
17 this.wheelSize=options.wheelSize||"large";
18 this.color=options.color||"blue";
19 }
20
21
22 //FactoryExample.js
23
24 //Defineaskeletonvehiclefactory
25 functionVehicleFactory(){}
26
27 //Definetheprototypesandutilitiesforthisfactory
28
29 //OurdefaultvehicleClassisCar
30 VehicleFactory.prototype.vehicleClass=Car;
31
32 //OurFactorymethodforcreatingnewVehicleinstances
33 VehicleFactory.prototype.createVehicle=function(options){
34
35 switch(options.vehicleType){
36 case"car":
37 this.vehicleClass=Car;
38 break;
39 case"truck":
40 this.vehicleClass=Truck;
41 break;
42 //defaultstoVehicleFactory.prototype.vehicleClass(Car)
43 }
44
45 returnnewthis.vehicleClass(options);
46
47 };
48
49 //Createaninstanceofourfactorythatmakescars
50 varcarFactory=newVehicleFactory();
51 varcar=carFactory.createVehicle({
52 vehicleType:"car",
53 color:"yellow",
54 doors:6});
55
56 //TesttoconfirmourcarwascreatedusingthevehicleClass/prototypeCar
57
58 //Outputs:true
59 console.log(carinstanceofCar);
60
61 //Outputs:Carobjectofcolor"yellow",doors:6ina"brandnew"state
62 console.log(car);

Approach#1:ModifyaVehicleFactoryinstancetousetheTruckclass

1 varmovingTruck=carFactory.createVehicle({
2 vehicleType:"truck",
3 state:"likenew",
4 color:"red",
5 wheelSize:"small"});
6

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 62/188
26/04/2015 LearningJavaScriptDesignPatterns

7 //TesttoconfirmourtruckwascreatedwiththevehicleClass/prototypeTruck
8
9 //Outputs:true
10 console.log(movingTruckinstanceofTruck);
11
12 //Outputs:Truckobjectofcolor"red",a"likenew"state
13 //anda"small"wheelSize
14 console.log(movingTruck);

Approach#2:SubclassVehicleFactorytocreateafactoryclassthatbuildsTrucks

1 functionTruckFactory(){}
2 TruckFactory.prototype=newVehicleFactory();
3 TruckFactory.prototype.vehicleClass=Truck;
4
5 vartruckFactory=newTruckFactory();
6 varmyBigTruck=truckFactory.createVehicle({
7 state:"omg..sobad.",
8 color:"pink",
9 wheelSize:"sobig"});
10
11 //ConfirmsthatmyBigTruckwascreatedwiththeprototypeTruck
12 //Outputs:true
13 console.log(myBigTruckinstanceofTruck);
14
15 //Outputs:Truckobjectwiththecolor"pink",wheelSize"sobig"
16 //andstate"omg.sobad"
17 console.log(myBigTruck);

WhenToUseTheFactoryPattern
TheFactorypatterncanbeespeciallyusefulwhenappliedtothefollowingsituations:

Whenourobjectorcomponentsetupinvolvesahighlevelofcomplexity
Whenweneedtoeasilygeneratedifferentinstancesofobjectsdependingontheenvironment
wearein
Whenwereworkingwithmanysmallobjectsorcomponentsthatsharethesameproperties
WhencomposingobjectswithinstancesofotherobjectsthatneedonlysatisfyanAPIcontract
(aka,ducktyping)towork.Thisisusefulfordecoupling.

WhenNotToUseTheFactoryPattern
Whenappliedtothewrongtypeofproblem,thispatterncanintroduceanunnecessarilygreatdealof
complexitytoanapplication.Unlessprovidinganinterfaceforobjectcreationisadesigngoalforthe
libraryorframeworkwearewriting,Iwouldsuggeststickingtoexplicitconstructorstoavoidthe
unnecessaryoverhead.

Duetothefactthattheprocessofobjectcreationiseffectivelyabstractedbehindaninterface,thiscan

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 63/188
26/04/2015 LearningJavaScriptDesignPatterns

alsointroduceproblemswithunittestingdependingonjusthowcomplexthisprocessmightbe.

AbstractFactories
ItisalsousefultobeawareoftheAbstractFactorypattern,whichaimstoencapsulateagroupof
individualfactorieswithacommongoal.Itseparatesthedetailsofimplementationofasetofobjects
fromtheirgeneralusage.

AnAbstractFactoryshouldbeusedwhereasystemmustbeindependentfromthewaytheobjectsit
createsaregeneratedoritneedstoworkwithmultipletypesofobjects.

Anexamplewhichisbothsimpleandeasiertounderstandisavehiclefactory,whichdefineswaysto
getorregistervehiclestypes.TheabstractfactorycanbenamedabstractVehicleFactory.TheAbstract
factorywillallowthedefinitionoftypesofvehiclelikecarortruckandconcretefactorieswill
implementonlyclassesthatfulfillthevehiclecontract(e.g Vehicle.prototype.drive and
Vehicle.prototype.breakDown ).

1 varabstractVehicleFactory=(function(){
2
3 //Storageforourvehicletypes
4 vartypes={};
5
6 return{
7 getVehicle:function(type,customizations){
8 varVehicle=types[type];
9
10 return(Vehicle?newVehicle(customizations):null);
11 },
12
13 registerVehicle:function(type,Vehicle){
14 varproto=Vehicle.prototype;
15
16 //onlyregisterclassesthatfulfillthevehiclecontract
17 if(proto.drive&&proto.breakDown){
18 types[type]=Vehicle;
19 }
20
21 returnabstractVehicleFactory;
22 }
23 };
24 })();
25
26
27 //Usage:
28
29 abstractVehicleFactory.registerVehicle("car",Car);
30 abstractVehicleFactory.registerVehicle("truck",Truck);
31
32 //Instantiateanewcarbasedontheabstractvehicletype
33 varcar=abstractVehicleFactory.getVehicle("car",{
34 color:"limegreen",
35 state:"likenew"});
36
37 //Instantiateanewtruckinasimilarmanner
38 vartruck=abstractVehicleFactory.getVehicle("truck",{
39 wheelSize:"medium",
40 color:"neonyellow"});

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 64/188
26/04/2015 LearningJavaScriptDesignPatterns

TheMixinPattern
IntraditionalprogramminglanguagessuchasC++andLisp,Mixinsareclasseswhichofferfunctionality
thatcanbeeasilyinheritedbyasubclassorgroupofsubclassesforthepurposeoffunctionreuse.

Subclassing
Fordevelopersunfamiliarwithsubclassing,wewillgothroughabriefbeginnersprimeronthem
beforedivingintoMixinsandDecoratorsfurther.

Subclassingisatermthatreferstoinheritingpropertiesforanewobjectfromabaseorsuperclassobject.
Intraditionalobjectorientedprogramming,aclass B isabletoextendanotherclass A .Herewe
consider A asuperclassand B asubclassof A .Assuch,allinstancesof B inheritthemethodsfrom A .
B ishoweverstillabletodefineitsownmethods,includingthosethatoverridemethodsoriginally
definedby A .

Should B needtoinvokeamethodin A thathasbeenoverridden,werefertothisasmethodchaining.


Should B needtoinvoketheconstructor A (thesuperclass),wecallthisconstructorchaining.

Inordertodemonstratesubclassing,wefirstneedabaseobjectthatcanhavenewinstancesofitself
created.letsmodelthisaroundtheconceptofaperson.

1 varPerson=function(firstName,lastName){
2
3 this.firstName=firstName;
4 this.lastName=lastName;
5 this.gender="male";
6
7 };

Next,wellwanttospecifyanewclass(object)thatsasubclassoftheexisting Person object.Letus


imaginewewanttoadddistinctpropertiestodistinguisha Person froma Superhero whilstinheriting
thepropertiesofthe Person superclass.Assuperheroessharemanycommontraitswithnormalpeople
(e.g.name,gender),thisshouldhopefullyillustratehowsubclassingworksadequately.

1 //anewinstanceofPersoncantheneasilybecreatedasfollows:
2 varclark=newPerson("Clark","Kent");
3
4 //Defineasubclassconstructorforfor"Superhero":
5 varSuperhero=function(firstName,lastName,powers){
6
7 //Invokethesuperclassconstructoronthenewobject
8 //thenuse.call()toinvoketheconstructorasamethodof
9 //theobjecttobeinitialized.
10
11 Person.call(this,firstName,lastName);
12

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 65/188
26/04/2015 LearningJavaScriptDesignPatterns

13 //Finally,storetheirpowers,anewarrayoftraitsnotfoundinanormal"Pers
14 this.powers=powers;
15 };
16
17 Superhero.prototype=Object.create(Person.prototype);
18 varsuperman=newSuperhero("Clark","Kent",["flight","heatvision"]);
19 console.log(superman);
20
21 //OutputsPersonattributesaswellaspowers

The Superhero constructorcreatesanobjectwhichdescendsfrom Person .Objectsofthistypehave


attributesoftheobjectsthatareaboveitinthechainandifwehadsetdefaultvaluesinthe Person
object, Superhero iscapableofoverridinganyinheritedvalueswithvaluesspecifictoitsobject.

Mixins
InJavaScript,wecanlookatinheritingfromMixinsasameansofcollectingfunctionalitythrough
extension.Eachnewobjectwedefinehasaprototypefromwhichitcaninheritfurtherproperties.
Prototypescaninheritfromotherobjectprototypesbut,evenmoreimportantly,candefineproperties
foranynumberofobjectinstances.Wecanleveragethisfacttopromotefunctionreuse.

Mixinsallowobjectstoborrow(orinherit)functionalityfromthemwithaminimalamountof
complexity.AsthepatternworkswellwithJavaScriptsobjectprototypes,itgivesusafairlyflexibleway
tosharefunctionalityfromnotjustoneMixin,buteffectivelymanythroughmultipleinheritance.

Theycanbeviewedasobjectswithattributesandmethodsthatcanbeeasilysharedacrossanumberof
otherobjectprototypes.ImaginethatwedefineaMixincontainingutilityfunctionsinastandardobject
literalasfollows:

1 varmyMixins={
2
3 moveUp:function(){
4 console.log("moveup");
5 },
6
7 moveDown:function(){
8 console.log("movedown");
9 },
10
11 stop:function(){
12 console.log("stop!inthenameoflove!");
13 }
14
15 };

Wecantheneasilyextendtheprototypeofexistingconstructorfunctionstoincludethisbehaviorusing
ahelpersuchastheUnderscore.js _.extend() method:

1 //AskeletoncarAnimatorconstructor
2 functionCarAnimator(){
3 this.moveLeft=function(){
4 console.log("moveleft");
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 66/188
26/04/2015 LearningJavaScriptDesignPatterns

5 };
6 }
7
8 //AskeletonpersonAnimatorconstructor
9 functionPersonAnimator(){
10 this.moveRandomly=function(){/*..*/};
11 }
12
13 //ExtendbothconstructorswithourMixin
14 _.extend(CarAnimator.prototype,myMixins);
15 _.extend(PersonAnimator.prototype,myMixins);
16
17 //CreateanewinstanceofcarAnimator
18 varmyAnimator=newCarAnimator();
19 myAnimator.moveLeft();
20 myAnimator.moveDown();
21 myAnimator.stop();
22
23 //Outputs:
24 //moveleft
25 //movedown
26 //stop!inthenameoflove!

Aswecansee,thisallowsustoeasilymixincommonbehaviourintoobjectconstructorsfairly
trivially.

Inthenextexample,wehavetwoconstructors:aCarandaMixin.Whatweregoingtodoisaugment
(anotherwayofsayingextend)theCarsothatitcaninheritspecificmethodsdefinedintheMixin,
namely driveForward() and driveBackward() .ThistimewewontbeusingUnderscore.js.

Instead,thisexamplewilldemonstratehowtoaugmentaconstructortoincludefunctionalitywithout
theneedtoduplicatethisprocessforeveryconstructorfunctionwemayhave.

1 //DefineasimpleCarconstructor
2 varCar=function(settings){
3
4 this.model=settings.model||"nomodelprovided";
5 this.color=settings.color||"nocolourprovided";
6
7 };
8
9 //Mixin
10 varMixin=function(){};
11
12 Mixin.prototype={
13
14 driveForward:function(){
15 console.log("driveforward");
16 },
17
18 driveBackward:function(){
19 console.log("drivebackward");
20 },
21
22 driveSideways:function(){
23 console.log("drivesideways");
24 }
25
26 };
27
28
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 67/188
26/04/2015 LearningJavaScriptDesignPatterns

29 //Extendanexistingobjectwithamethodfromanother
30 functionaugment(receivingClass,givingClass){
31
32 //onlyprovidecertainmethods
33 if(arguments[2]){
34 for(vari=2,len=arguments.length;i<len;i++){
35 receivingClass.prototype[arguments[i]]=givingClass.prototype[arguments[
36 }
37 }
38 //provideallmethods
39 else{
40 for(varmethodNameingivingClass.prototype){
41
42 //checktomakesurethereceivingclassdoesn't
43 //haveamethodofthesamenameastheonecurrently
44 //beingprocessed
45 if(!Object.hasOwnProperty.call(receivingClass.prototype,methodName))
46 receivingClass.prototype[methodName]=givingClass.prototype[methodNa
47 }
48
49 //Alternatively(checkprototypechainaswell):
50 //if(!receivingClass.prototype[methodName]){
51 //receivingClass.prototype[methodName]=givingClass.prototype[methodNam
52 //}
53 }
54 }
55 }
56
57
58 //AugmenttheCarconstructortoinclude"driveForward"and"driveBackward"
59 augment(Car,Mixin,"driveForward","driveBackward");
60
61 //CreateanewCar
62 varmyCar=newCar({
63 model:"FordEscort",
64 color:"blue"
65 });
66
67 //Testtomakesurewenowhaveaccesstothemethods
68 myCar.driveForward();
69 myCar.driveBackward();
70
71 //Outputs:
72 //driveforward
73 //drivebackward
74
75 //WecanalsoaugmentCartoincludeallfunctionsfromourmixin
76 //bynotexplicitlylistingaselectionofthem
77 augment(Car,Mixin);
78
79 varmySportsCar=newCar({
80 model:"Porsche",
81 color:"red"
82 });
83
84 mySportsCar.driveSideways();
85
86 //Outputs:
87 //drivesideways

Advantages&Disadvantages
Mixinsassistindecreasingfunctionalrepetitionandincreasingfunctionreuseinasystem.Wherean

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 68/188
26/04/2015 LearningJavaScriptDesignPatterns

applicationislikelytorequiresharedbehaviouracrossobjectinstances,wecaneasilyavoidany
duplicationbymaintainingthissharedfunctionalityinaMixinandthusfocusingonimplementingonly
thefunctionalityinoursystemwhichistrulydistinct.

Thatsaid,thedownsidestoMixinsarealittlemoredebatable.Somedevelopersfeelthatinjecting
functionalityintoanobjectprototypeisabadideaasitleadstobothprototypepollutionandalevelof
uncertaintyregardingtheoriginofourfunctions.Inlargesystemsthismaywellbethecase.

Iwouldarguethatstrongdocumentationcanassistinminimizingtheamountofconfusionregarding
thesourceofmixedinfunctions,butaswitheverypattern,ifcareistakenduringimplementationwe
shouldbeokay.

TheDecoratorPattern
Decoratorsareastructuraldesignpatternthataimtopromotecodereuse.SimilartoMixins,theycan
beconsideredanotherviablealternativetoobjectsubclassing.

Classically,Decoratorsofferedtheabilitytoaddbehaviourtoexistingclassesinasystemdynamically.
Theideawasthatthedecorationitselfwasntessentialtothebasefunctionalityoftheclass,otherwiseit
wouldbebakedintothesuperclassitself.

Theycanbeusedtomodifyexistingsystemswherewewishtoaddadditionalfeaturestoobjects
withouttheneedtoheavilymodifytheunderlyingcodeusingthem.Acommonreasonwhydevelopers
usethemistheirapplicationsmaycontainfeaturesrequiringalargequantityofdistincttypesofobject.
Imaginehavingtodefinehundredsofdifferentobjectconstructorsforsay,aJavaScriptgame.

Theobjectconstructorscouldrepresentdistinctplayertypes,eachwithdifferingcapabilities.ALordof
theRingsgamecouldrequireconstructorsfor Hobbit , Elf , Orc , Wizard , MountainGiant , StoneGiant and
soon,buttherecouldeasilybehundredsofthese.Ifwethenfactoredincapabilities,imaginehavingto
createsubclassesforeachcombinationofcapabilitytypee.g HobbitWithRing , HobbitWithSword ,
HobbitWithRingAndSword andsoon.Thisisntverypracticalandcertainlyisntmanageablewhenwefactor

inagrowingnumberofdifferentabilities.

TheDecoratorpatternisntheavilytiedtohowobjectsarecreatedbutinsteadfocusesontheproblemof
extendingtheirfunctionality.Ratherthanjustrelyingonprototypalinheritance,weworkwithasingle
baseobjectandprogressivelyadddecoratorobjectswhichprovidetheadditionalcapabilities.Theidea
isthatratherthansubclassing,weadd(decorate)propertiesormethodstoabaseobjectsoitsalittle
morestreamlined.

AddingnewattributestoobjectsinJavaScriptisaverystraightforwardprocesssowiththisinmind,a
verysimplisticdecoratormaybeimplementedasfollows:

Example1:DecoratingConstructorsWithNewFunctionality
?

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 69/188
26/04/2015 LearningJavaScriptDesignPatterns

1 //Avehicleconstructor
2 functionVehicle(vehicleType){
3
4 //somesanedefaults
5 this.vehicleType=vehicleType||"car";
6 this.model="default";
7 this.license="00000000";
8
9 }
10
11 //Testinstanceforabasicvehicle
12 vartestInstance=newVehicle("car");
13 console.log(testInstance);
14
15 //Outputs:
16 //vehicle:car,model:default,license:00000000
17
18 //Letscreateanewinstanceofvehicle,tobedecorated
19 vartruck=newVehicle("truck");
20
21 //Newfunctionalitywe'redecoratingvehiclewith
22 truck.setModel=function(modelName){
23 this.model=modelName;
24 };
25
26 truck.setColor=function(color){
27 this.color=color;
28 };
29
30 //Testthevaluesettersandvalueassignmentworkscorrectly
31 truck.setModel("CAT");
32 truck.setColor("blue");
33
34 console.log(truck);
35
36 //Outputs:
37 //vehicle:truck,model:CAT,color:blue
38
39 //Demonstrate"vehicle"isstillunaltered
40 varsecondInstance=newVehicle("car");
41 console.log(secondInstance);
42
43 //Outputs:
44 //vehicle:car,model:default,license:00000000

Thistypeofsimplisticimplementationisfunctional,butitdoesntreallydemonstrateallofthestrengths
Decoratorshavetooffer.Forthis,werefirstgoingtogothroughmyvariationoftheCoffeeexample
fromanexcellentbookcalledHeadFirstDesignPatternsbyFreeman,SierraandBates,whichismodeled
aroundaMacbookpurchase.

Example2:DecoratingObjectsWithMultipleDecorators
?

1 //Theconstructortodecorate
2 functionMacBook(){
3
4 this.cost=function(){return997;};
5 this.screenSize=function(){return11.6;};
6
7 }
8
9 //Decorator1
10 functionmemory(macbook){
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 70/188
26/04/2015 LearningJavaScriptDesignPatterns

11
12 varv=macbook.cost();
13 macbook.cost=function(){
14 returnv+75;
15 };
16
17 }
18
19 //Decorator2
20 functionengraving(macbook){
21
22 varv=macbook.cost();
23 macbook.cost=function(){
24 returnv+200;
25 };
26
27 }
28
29 //Decorator3
30 functioninsurance(macbook){
31
32 varv=macbook.cost();
33 macbook.cost=function(){
34 returnv+250;
35 };
36
37 }
38
39 varmb=newMacBook();
40 memory(mb);
41 engraving(mb);
42 insurance(mb);
43
44 //Outputs:1522
45 console.log(mb.cost());
46
47 //Outputs:11.6
48 console.log(mb.screenSize());

Intheaboveexample,ourDecoratorsareoverridingthe MacBook() superclassobjects .cost() function


toreturnthecurrentpriceofthe Macbook plusthecostoftheupgradebeingspecified.

Itsconsideredadecorationastheoriginal Macbook objectsconstructormethodswhicharenot


overridden(e.g. screenSize() )aswellasanyotherpropertieswhichwemaydefineasapartofthe
Macbook remainunchangedandintact.

Thereisntreallyadefinedinterfaceintheaboveexampleandwereshiftingawaytheresponsibilityof
ensuringanobjectmeetsaninterfacewhenmovingfromthecreatortothereceiver.

PseudoclassicalDecorators
WerenowgoingtoexamineavariationoftheDecoratorfirstpresentedinaJavaScriptforminPro
JavaScriptDesignPatterns(PJDP)byDustinDiazandRossHarmes.

Unlikesomeoftheexamplesfromearlier,DiazandHarmesstickmorecloselytohowdecoratorsare
implementedinotherprogramminglanguages(suchasJavaorC++)usingtheconceptofaninterface,
whichwewilldefineinmoredetailshortly.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 71/188
26/04/2015 LearningJavaScriptDesignPatterns

Note:ThisparticularvariationoftheDecoratorpatternisprovidedforreferencepurposes.Iffindingit
overlycomplex,Irecommendoptingforoneofthesimplerimplementationscoveredearlier.

Interfaces
PJDPdescribestheDecoratorasapatternthatisusedtotransparentlywrapobjectsinsideotherobjects
ofthesameinterface.Aninterfaceisawayofdefiningthemethodsanobjectshouldhave,however,it
doesntactuallydirectlyspecifyhowthosemethodsshouldbeimplemented.

Theycanalsoindicatewhatparametersthemethodstake,butthisisconsideredoptional.

So,whywouldweuseaninterfaceinJavaScript?Theideaisthattheyreselfdocumentingandpromote
reusability.Intheory,interfacesalsomakecodemorestablebyensuringchangestothemmustalsobe
madetotheobjectsimplementingthem.

BelowisanexampleofanimplementationofinterfacesinJavaScriptusingducktypinganapproach
thathelpsdeterminewhetheranobjectisaninstanceofconstructor/objectbasedonthemethodsit
implements.

1 //CreateinterfacesusingapredefinedInterface
2 //constructorthatacceptsaninterfacenameand
3 //skeletonmethodstoexpose.
4
5 //Inourreminderexamplesummary()andplaceOrder()
6 //representfunctionalitytheinterfaceshould
7 //support
8 varreminder=newInterface("List",["summary","placeOrder"]);
9
10 varproperties={
11 name:"Remembertobuythemilk",
12 date:"05/06/2016",
13 actions:{
14 summary:function(){
15 return"Remembertobuythemilk,wearealmostout!";
16 },
17 placeOrder:function(){
18 return"Orderingmilkfromyourlocalgrocerystore";
19 }
20 }
21 };
22
23 //Nowcreateaconstructorimplementingtheaboveproperties
24 //andmethods
25
26 functionTodo(config){
27
28 //Statethemethodsweexpecttobesupported
29 //aswellastheInterfaceinstancebeingchecked
30 //against
31
32 Interface.ensureImplements(config.actions,reminder);
33
34 this.name=config.name;
35 this.methods=config.actions;
36
37 }
38
39 //CreateanewinstanceofourTodoconstructor

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 72/188
26/04/2015 LearningJavaScriptDesignPatterns

40
41 vartodoItem=Todo(properties);
42
43 //Finallytesttomakesurethesefunctioncorrectly
44
45 console.log(todoItem.methods.summary());
46 console.log(todoItem.methods.placeOrder());
47
48 //Outputs:
49 //Remembertobuythemilk,wearealmostout!
50 //Orderingmilkfromyourlocalgrocerystore

Intheabove, Interface.ensureImplements providesstrictfunctionalitycheckingandcodeforboththisand


the Interface constructorcanbefoundhere.

Thebiggestproblemwithinterfacesisthat,asthereisntbuiltinsupportfortheminJavaScript,thereis
adangerofusattemptingtoemulateafeatureofanotherlanguagethatmaynotbeanidealfit.
Lightweightinterfacescanbeusedwithoutagreatperformancecosthoweverandwewillnextlookat
AbstractDecoratorsusingthissameconcept.

AbstractDecorators
TodemonstratethestructureofthisversionoftheDecoratorpattern,weregoingtoimaginewehavea
superclassthatmodelsa Macbook onceagainandastorethatallowsustodecorateourMacbookwitha
numberofenhancementsforanadditionalfee.

Enhancementscanincludeupgradesto4GBor8GBRam,engraving,Parallelsoracase.Nowifwewere
tomodelthisusinganindividualsubclassforeachcombinationofenhancementoptions,itmightlook
somethinglikethis:

1 varMacbook=function(){
2 //...
3 };
4
5 varMacbookWith4GBRam=function(){},
6 MacbookWith8GBRam=function(){},
7 MacbookWith4GBRamAndEngraving=function(){},
8 MacbookWith8GBRamAndEngraving=function(){},
9 MacbookWith8GBRamAndParallels=function(){},
10 MacbookWith4GBRamAndParallels=function(){},
11 MacbookWith8GBRamAndParallelsAndCase=function(){},
12 MacbookWith4GBRamAndParallelsAndCase=function(){},
13 MacbookWith8GBRamAndParallelsAndCaseAndInsurance=function(){},
14 MacbookWith4GBRamAndParallelsAndCaseAndInsurance=function(){};

andsoon.

Thiswouldbeanimpracticalsolutionasanewsubclasswouldberequiredforeverypossible
combinationofenhancementsthatareavailable.Aswewouldprefertokeepthingssimplewithout
maintainingalargesetofsubclasses,letslookathowdecoratorsmaybeusedtosolvethisproblem
better.

Ratherthanrequiringallofthecombinationswesawearlier,weshouldsimplyhavetocreatefivenew

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 73/188
26/04/2015 LearningJavaScriptDesignPatterns

decoratorclasses.Methodsthatarecalledontheseenhancementclasseswouldbepassedontoour
Macbook class.

Inournextexample,decoratorstransparentlywraparoundtheircomponentsandcaninterestinglybe
interchangedastheyusethesameinterface.

HerestheinterfaceweregoingtodefinefortheMacbook:

1 varMacbook=newInterface("Macbook",
2 ["addEngraving",
3 "addParallels",
4 "add4GBRam",
5 "add8GBRam",
6 "addCase"]);
7
8 //AMacbookPromightthusberepresentedasfollows:
9 varMacbookPro=function(){
10 //implementsMacbook
11 };
12
13 MacbookPro.prototype={
14 addEngraving:function(){
15 },
16 addParallels:function(){
17 },
18 add4GBRam:function(){
19 },
20 add8GBRam:function(){
21 },
22 addCase:function(){
23 },
24 getPrice:function(){
25 //Baseprice
26 return900.00;
27 }
28 };

Tomakeiteasierforustoaddasmanymoreoptionsasneededlateron,anAbstractDecoratorclassis
definedwithdefaultmethodsrequiredtoimplementthe Macbook interface,whichtherestoftheoptions
willsubclass.AbstractDecoratorsensurethatwecandecorateabaseclassindependentlywithasmany
decoratorsasneededindifferentcombinations(remembertheexampleearlier?)withoutneedingto
deriveaclassforeverypossiblecombination.

1 //Macbookdecoratorabstractdecoratorclass
2
3 varMacbookDecorator=function(macbook){
4
5 Interface.ensureImplements(macbook,Macbook);
6 this.macbook=macbook;
7
8 };
9
10 MacbookDecorator.prototype={
11 addEngraving:function(){
12 returnthis.macbook.addEngraving();
13 },
14 addParallels:function(){
15 returnthis.macbook.addParallels();

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 74/188
26/04/2015 LearningJavaScriptDesignPatterns

16 },
17 add4GBRam:function(){
18 returnthis.macbook.add4GBRam();
19 },
20 add8GBRam:function(){
21 returnthis.macbook.add8GBRam();
22 },
23 addCase:function(){
24 returnthis.macbook.addCase();
25 },
26 getPrice:function(){
27 returnthis.macbook.getPrice();
28 }
29 };

Whatshappeningintheabovesampleisthatthe Macbook Decoratoracceptsanobject(aMacbook)to


useasourbasecomponent.Itsusingthe Macbook interfacewedefinedearlierandforeachmethodis
justcallingthesamemethodonthecomponent.Wecannowcreateouroptionclassesforwhatcanbe
added,justbyusingthe Macbook Decorator.

?
1 //First,defineawaytoextendanobjecta
2 //withthepropertiesinobjectb.We'lluse
3 //thisshortly!
4 functionextend(a,b){
5 for(varkeyinb)
6 if(b.hasOwnProperty(key))
7 a[key]=b[key];
8 returna;
9 }
10
11 varCaseDecorator=function(macbook){
12 this.macbook=macbook;
13 };
14
15 //Let'snowextend(decorate)theCaseDecorator
16 //withaMacbookDecorator
17 extend(CaseDecorator,MacbookDecorator);
18
19 CaseDecorator.prototype.addCase=function(){
20 returnthis.macbook.addCase()+"Addingcasetomacbook";
21 };
22
23 CaseDecorator.prototype.getPrice=function(){
24 returnthis.macbook.getPrice()+45.00;
25 };

Whatweredoinghereisoverridingthe addCase() and getPrice() methodsthatneedtobedecorated


andwereachievingthisbyfirstcallingthesemethodsontheoriginal macbook andthensimply
appendingastringornumericvalue(e.g45.00)tothemaccordingly.

Astheresbeenquitealotofinformationpresentedinthissectionsofar,letstrytobringitalltogether
inasingleexamplethatwillhopefullyhighlightwhatwehavelearned.

1 //Instantiationofthemacbook
2 varmyMacbookPro=newMacbookPro();
3
4 //Outputs:900.00
5 console.log(myMacbookPro.getPrice());

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 75/188
26/04/2015 LearningJavaScriptDesignPatterns

6
7 //Decoratethemacbook
8 vardecoratedMacbookPro=newCaseDecorator(myMacbookPro);
9
10 //Thiswillreturn945.00
11 console.log(decoratedMacbookPro.getPrice());

Asdecoratorsareabletomodifyobjectsdynamically,theyreaperfectpatternforchangingexisting
systems.Occasionally,itsjustsimplertocreatedecoratorsaroundanobjectversusthetroubleof
maintainingindividualsubclassesforeachobjecttype.Thismakesmaintainingapplicationsthatmay
requirealargenumberofsubclassedobjectssignificantlymorestraightforward.

AfunctionalversionofthisexamplecanbefoundonJSBin.

DecoratorsWithjQuery
Aswithotherpatternswevecovered,therearealsoexamplesoftheDecoratorpatternthatcanbe
implementedwithjQuery. jQuery.extend() allowsustoextend(ormerge)twoormoreobjects(andtheir
properties)togetherintoasingleobjecteitheratruntimeordynamicallyatalaterpoint.

Inthisscenario,atargetobjectcanbedecoratedwithnewfunctionalitywithoutnecessarilybreakingor
overridingexistingmethodsinthesource/superclassobject(althoughthiscanbedone).

Inthefollowingexample,wedefinethreeobjects:defaults,optionsandsettings.Theaimofthetaskisto
decoratethe defaults objectwithadditionalfunctionalityfoundin optionssettings .Wemust:

(a)Leavedefaultsinanuntouchedstatewherewedontlosetheabilitytoaccessthepropertiesor
functionsfoundinitalaterpoint(b)Gaintheabilitytousethedecoratedpropertiesandfunctions
foundinoptions

1 vardecoratorApp=decoratorApp||{};
2
3 //definetheobjectswe'regoingtouse
4 decoratorApp={
5
6 defaults:{
7 validate:false,
8 limit:5,
9 name:"foo",
10 welcome:function(){
11 console.log("welcome!");
12 }
13 },
14
15 options:{
16 validate:true,
17 name:"bar",
18 helloWorld:function(){
19 console.log("helloworld");
20 }
21 },
22
23 settings:{},
24

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 76/188
26/04/2015 LearningJavaScriptDesignPatterns
25 printObj:function(obj){
26 vararr=[],
27 next;
28 $.each(obj,function(key,val){
29 next=key+":";
30 next+=$.isPlainObject(val)?printObj(val):val;
31 arr.push(next);
32 });
33
34 return"{"+arr.join(",")+"}";
35 }
36
37 };
38
39 //mergedefaultsandoptions,withoutmodifyingdefaultsexplicitly
40 decoratorApp.settings=$.extend({},decoratorApp.defaults,decoratorApp.options);
41
42 //whatwehavedonehereisdecorateddefaultsinawaythatprovides
43 //accesstothepropertiesandfunctionalityithastooffer(aswellas
44 //thatofthedecorator"options").defaultsitselfisleftunchanged
45
46 $("#log")
47 .append(decoratorApp.printObj(decoratorApp.settings)+
48 +decoratorApp.printObj(decoratorApp.options)+
49 +decoratorApp.printObj(decoratorApp.defaults));
50
51 //settings{validate:true,limit:5,name:bar,welcome:function(){console.l
52 //helloWorld:function(){console.log("helloworld");}}
53 //options{validate:true,name:bar,helloWorld:function(){console.log("hel
54 //defaults{validate:false,limit:5,name:foo,welcome:function(){console.

Advantages&Disadvantages
Developersenjoyusingthispatternasitcanbeusedtransparentlyandisalsofairlyflexibleasweve
seen,objectscanbewrappedordecoratedwithnewbehaviorandthencontinuetobeusedwithout
needingtoworryaboutthebaseobjectbeingmodified.Inabroadercontext,thispatternalsoavoidsus
needingtorelyonlargenumbersofsubclassestogetthesamebenefits.

Therearehoweverdrawbacksthatweshouldbeawareofwhenimplementingthepattern.Ifpoorly
managed,itcansignificantlycomplicateourapplicationarchitectureasitintroducesmanysmall,but
similarobjectsintoournamespace.Theconcernhereisthatinadditiontobecominghardtomanage,
otherdevelopersunfamiliarwiththepatternmayhaveahardtimegraspingwhyitsbeingused.

Sufficientcommentingorpatternresearchshouldassistwiththelatter,howeveraslongaswekeepa
handleonhowwidespreadweusethedecoratorinourapplicationsweshouldbefineonbothcounts.

Flyweight

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 77/188
26/04/2015 LearningJavaScriptDesignPatterns

TheFlyweightpatternisaclassicalstructuralsolutionforoptimizingcodethatisrepetitive,slowand
inefficientlysharesdata.Itaimstominimizetheuseofmemoryinanapplicationbysharingasmuch
dataaspossiblewithrelatedobjects(e.gapplicationconfiguration,stateandsoon).

ThepatternwasfirstconceivedbyPaulCalderandMarkLintonin1990andwasnamedafterthe
boxingweightclassthatincludesfightersweighinglessthan112lb.ThenameFlyweightitselfisderived
fromthisweightclassificationasitreferstothesmallweight(memoryfootprint)thepatternaimsto
helpusachieve.

Inpractice,Flyweightdatasharingcaninvolvetakingseveralsimilarobjectsordataconstructsusedby
anumberofobjectsandplacingthisdataintoasingleexternalobject.Wecanpassthroughthisobject
throughtothosedependingonthisdata,ratherthanstoringidenticaldataacrosseachone.

UsingFlyweights
TherearetwowaysinwhichtheFlyweightpatterncanbeapplied.Thefirstisatthedatalayer,where
wedealwiththeconceptofsharingdatabetweenlargequantitiesofsimilarobjectsstoredinmemory.

ThesecondisattheDOMlayerwheretheFlyweightcanbeusedasacentraleventmanagertoavoid
attachingeventhandlerstoeverychildelementinaparentcontainerwewishtohavesomesimilar
behavior.

Asthedatalayeriswheretheflyweightpatternismostusedtraditionally,welltakealookatthisfirst.

Flyweightsandsharingdata
Forthisapplication,thereareafewmoreconceptsaroundtheclassicalFlyweightpatternthatweneed
tobeawareof.IntheFlyweightpatterntheresaconceptoftwostatesintrinsicandextrinsic.Intrinsic
informationmayberequiredbyinternalmethodsinourobjectswhichtheyabsolutelycannotfunction
without.Extrinsicinformationcanhoweverberemovedandstoredexternally.

Objectswiththesameintrinsicdatacanbereplacedwithasinglesharedobject,createdbyafactory
method.Thisallowsustoreducetheoverallquantityofimplicitdatabeingstoredquitesignificantly.

Thebenefitofthisisthatwereabletokeepaneyeonobjectsthathavealreadybeeninstantiatedsothat
newcopiesareonlyevercreatedshouldtheintrinsicstatedifferfromtheobjectwealreadyhave.

Weuseamanagertohandletheextrinsicstates.Howthisisimplementedcanvary,butoneapproachto
thistohavethemanagerobjectcontainacentraldatabaseoftheextrinsicstatesandtheflyweightobjects
whichtheybelongto.

ImplementingClassicalFlyweights
AstheFlyweightpatternhasntbeenheavilyusedinJavaScriptinrecentyears,manyofthe

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 78/188
26/04/2015 LearningJavaScriptDesignPatterns

implementationswemightuseforinspirationcomefromtheJavaandC++worlds.

OurfirstlookatFlyweightsincodeismyJavaScriptimplementationoftheJavasampleoftheFlyweight
patternfromWikipedia(http://en.wikipedia.org/wiki/Flyweight_pattern).

WewillbemakinguseofthreetypesofFlyweightcomponentsinthisimplementation,whicharelisted
below:

Flyweightcorrespondstoaninterfacethroughwhichflyweightsareabletoreceiveandact
onextrinsicstates
ConcreteFlyweightactuallyimplementstheFlyweightinterfaceandstoresintrinsicstate.
ConcreteFlyweightsneedtobesharableandcapableofmanipulatingstatethatisextrinsic
FlyweightFactorymanagesflyweightobjectsandcreatesthemtoo.Itmakessurethatour
flyweightsaresharedandmanagesthemasagroupofobjectswhichcanbequeriedifwe
requireindividualinstances.Ifanobjecthasbeenalreadycreatedinthegroupitreturnsit,
otherwiseitaddsanewobjecttothepoolandreturnsit.

Thesecorrespondtothefollowingdefinitionsinourimplementation:

CoffeeOrder:Flyweight
CoffeeFlavor:ConcreteFlyweight
CoffeeOrderContext:Helper
CoffeeFlavorFactory:FlyweightFactory
testFlyweight:UtilizationofourFlyweights

Duckpunchingimplements
Duckpunchingallowsustoextendthecapabilitiesofalanguageorsolutionwithoutnecessarily
needingtomodifytheruntimesource.AsthisnextsolutionrequirestheuseofaJavakeyword
( implements )forimplementinginterfacesandisntfoundinJavaScriptnatively,letsfirstduckpunchit.

Function.prototype.implementsFor worksonanobjectconstructorandwillacceptaparentclass(function)
orobjectandeitherinheritfromthisusingnormalinheritance(forfunctions)orvirtualinheritance(for
objects).

1 //Simulatepurevirtualinheritance/"implement"keywordforJS
2 Function.prototype.implementsFor=function(parentClassOrObject){
3 if(parentClassOrObject.constructor===Function)
4 {
5 //NormalInheritance
6 this.prototype=newparentClassOrObject();
7 this.prototype.constructor=this;
8 this.prototype.parent=parentClassOrObject.prototype;
9 }
10 else
11 {
12 //PureVirtualInheritance
13 this.prototype=parentClassOrObject;
14 this.prototype.constructor=this;
15 this.prototype.parent=parentClassOrObject;
16 }
17 returnthis;
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 79/188
26/04/2015 LearningJavaScriptDesignPatterns

18 };

Wecanusethistopatchthelackofan implements keywordbyhavingafunctioninheritaninterface


explicitly.Below, CoffeeFlavor implementsthe CoffeeOrder interfaceandmustcontainitsinterface
methodsinorderforustoassignthefunctionalitypoweringtheseimplementationstoanobject.

1 //Flyweightobject
2 varCoffeeOrder={
3
4 //Interfaces
5 serveCoffee:function(context){},
6 getFlavor:function(){}
7
8 };
9
10
11 //ConcreteFlyweightobjectthatcreatesConcreteFlyweight
12 //ImplementsCoffeeOrder
13 functionCoffeeFlavor(newFlavor){
14
15 varflavor=newFlavor;
16
17 //Ifaninterfacehasbeendefinedforafeature
18 //implementthefeature
19 if(typeofthis.getFlavor==="function"){
20 this.getFlavor=function(){
21 returnflavor;
22 };
23 }
24
25 if(typeofthis.serveCoffee==="function"){
26 this.serveCoffee=function(context){
27 console.log("ServingCoffeeflavor"
28 +flavor
29 +"totablenumber"
30 +context.getTable());
31 };
32 }
33
34 }
35
36
37 //ImplementinterfaceforCoffeeOrder
38 CoffeeFlavor.implementsFor(CoffeeOrder);
39
40
41 //Handletablenumbersforacoffeeorder
42 functionCoffeeOrderContext(tableNumber){
43 return{
44 getTable:function(){
45 returntableNumber;
46 }
47 };
48 }
49
50
51 functionCoffeeFlavorFactory(){
52 varflavors={},
53 length=0;
54
55 return{
56 getCoffeeFlavor:function(flavorName){
57

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 80/188
26/04/2015 LearningJavaScriptDesignPatterns

58 varflavor=flavors[flavorName];
59 if(typeofflavor==="undefined"){
60 flavor=newCoffeeFlavor(flavorName);
61 flavors[flavorName]=flavor;
62 length++;
63 }
64 returnflavor;
65 },
66
67 getTotalCoffeeFlavorsMade:function(){
68 returnlength;
69 }
70 };
71 }
72
73 //Sampleusage:
74 //testFlyweight()
75
76 functiontestFlyweight(){
77
78
79 //Theflavorsordered.
80 varflavors=newCoffeeFlavor(),
81
82 //Thetablesfortheorders.
83 tables=newCoffeeOrderContext(),
84
85 //Numberofordersmade
86 ordersMade=0,
87
88 //TheCoffeeFlavorFactoryinstance
89 flavorFactory;
90
91 functiontakeOrders(flavorIn,table){
92 flavors[ordersMade]=flavorFactory.getCoffeeFlavor(flavorIn);
93 tables[ordersMade++]=newCoffeeOrderContext(table);
94 }
95
96 flavorFactory=newCoffeeFlavorFactory();
97
98 takeOrders("Cappuccino",2);
99 takeOrders("Cappuccino",2);
100 takeOrders("Frappe",1);
101 takeOrders("Frappe",1);
102 takeOrders("Xpresso",1);
103 takeOrders("Frappe",897);
104 takeOrders("Cappuccino",97);
105 takeOrders("Cappuccino",97);
106 takeOrders("Frappe",3);
107 takeOrders("Xpresso",3);
108 takeOrders("Cappuccino",3);
109 takeOrders("Xpresso",96);
110 takeOrders("Frappe",552);
111 takeOrders("Cappuccino",121);
112 takeOrders("Xpresso",121);
113
114 for(vari=0;i<ordersMade;++i){
115 flavors[i].serveCoffee(tables[i]);
116 }
117 console.log("");
118 console.log("totalCoffeeFlavorobjectsmade:"+flavorFactory.getTotalCoffeeFla
119 }

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 81/188
26/04/2015 LearningJavaScriptDesignPatterns

ConvertingcodetousetheFlyweightpattern
Next,letscontinueourlookatFlyweightsbyimplementingasystemtomanageallofthebooksina
library.Theimportantmetadataforeachbookcouldprobablybebrokendownasfollows:

ID
Title
Author
Genre
Pagecount
PublisherID
ISBN

Wellalsorequirethefollowingpropertiestokeeptrackofwhichmemberhascheckedoutaparticular
book,thedatetheyvecheckeditoutonaswellastheexpecteddateofreturn.

checkoutDate
checkoutMember
dueReturnDate
availability

Eachbookwouldthusberepresentedasfollows,priortoanyoptimizationusingtheFlyweightpattern:

1 varBook=function(id,title,author,genre,pageCount,publisherID,ISBN,checkoutD
2
3 this.id=id;
4 this.title=title;
5 this.author=author;
6 this.genre=genre;
7 this.pageCount=pageCount;
8 this.publisherID=publisherID;
9 this.ISBN=ISBN;
10 this.checkoutDate=checkoutDate;
11 this.checkoutMember=checkoutMember;
12 this.dueReturnDate=dueReturnDate;
13 this.availability=availability;
14
15 };
16
17 Book.prototype={
18
19 getTitle:function(){
20 returnthis.title;
21 },
22
23 getAuthor:function(){
24 returnthis.author;
25 },
26
27 getISBN:function(){
28 returnthis.ISBN;
29 },
30
31 //Forbrevity,othergettersarenotshown
32 updateCheckoutStatus:function(bookID,newStatus,checkoutDate,checkoutMember,ne

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 82/188
26/04/2015 LearningJavaScriptDesignPatterns

33
34 this.id=bookID;
35 this.availability=newStatus;
36 this.checkoutDate=checkoutDate;
37 this.checkoutMember=checkoutMember;
38 this.dueReturnDate=newReturnDate;
39
40 },
41
42 extendCheckoutPeriod:function(bookID,newReturnDate){
43
44 this.id=bookID;
45 this.dueReturnDate=newReturnDate;
46
47 },
48
49 isPastDue:function(bookID){
50
51 varcurrentDate=newDate();
52 returncurrentDate.getTime()>Date.parse(this.dueReturnDate);
53
54 }
55 };

Thisprobablyworksfineinitiallyforsmallcollectionsofbooks,howeverasthelibraryexpandsto
includealargerinventorywithmultipleversionsandcopiesofeachbookavailable,wemayfindthe
managementsystemrunningslowerandslowerovertime.Usingthousandsofbookobjectsmay
overwhelmtheavailablememory,butwecanoptimizeoursystemusingtheFlyweightpatternto
improvethis.

Wecannowseparateourdataintointrinsicandextrinsicstatesasfollows:datarelevanttothebook
object( title , author etc)isintrinsicwhilstthecheckoutdata( checkoutMember , dueReturnDate etc)is
consideredextrinsic.EffectivelythismeansthatonlyoneBookobjectisrequiredforeachcombinationof
bookproperties.itsstillaconsiderablequantityofobjects,butsignificantlyfewerthanwehad
previously.

Thefollowingsingleinstanceofourbookmetadatacombinationswillbesharedamongallofthecopies
ofabookwithaparticulartitle.

1 //Flyweightoptimizedversion
2 varBook=function(title,author,genre,pageCount,publisherID,ISBN){
3
4 this.title=title;
5 this.author=author;
6 this.genre=genre;
7 this.pageCount=pageCount;
8 this.publisherID=publisherID;
9 this.ISBN=ISBN;
10
11 };

Aswecansee,theextrinsicstateshavebeenremoved.Everythingtodowithlibrarycheckoutswillbe
movedtoamanagerandastheobjectdataisnowsegmented,afactorycanbeusedforinstantiation.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 83/188
26/04/2015 LearningJavaScriptDesignPatterns

ABasicFactory
Letsnowdefineaverybasicfactory.Whatweregoingtohaveitdoisperformachecktoseeifabook
withaparticulartitlehasbeenpreviouslycreatedinsidethesystem;ifithas,wellreturnitifnot,a
newbookwillbecreatedandstoredsothatitcanbeaccessedlater.Thismakessurethatweonlycreate
asinglecopyofeachuniqueintrinsicpieceofdata:

1 //BookFactorysingleton
2 varBookFactory=(function(){
3 varexistingBooks={},existingBook;
4
5 return{
6 createBook:function(title,author,genre,pageCount,publisherID,ISBN){
7
8 //Findoutifaparticularbookmetadatacombinationhasbeencreatedbefore
9 //!!or(bangbang)forcesabooleantobereturned
10 existingBook=existingBooks[ISBN];
11 if(!!existingBook){
12 returnexistingBook;
13 }else{
14
15 //ifnot,let'screateanewinstanceofthebookandstoreit
16 varbook=newBook(title,author,genre,pageCount,publisherID,ISBN);
17 existingBooks[ISBN]=book;
18 returnbook;
19
20 }
21 }
22 };
23
24 });

Managingtheextrinsicstates
Next,weneedtostorethestatesthatwereremovedfromtheBookobjectssomewhereluckilya
manager(whichwellbedefiningasaSingleton)canbeusedtoencapsulatethem.Combinationsofa
BookobjectandthelibrarymemberthatscheckedthemoutwillbecalledBookrecords.Ourmanager
willbestoringbothandwillalsoincludecheckoutrelatedlogicwestrippedoutduringourflyweight
optimizationoftheBookclass.

1 //BookRecordManagersingleton
2 varBookRecordManager=(function(){
3
4 varbookRecordDatabase={};
5
6 return{
7 //addanewbookintothelibrarysystem
8 addBookRecord:function(id,title,author,genre,pageCount,publisherID,ISBN,
9
10 varbook=bookFactory.createBook(title,author,genre,pageCount,publisherID
11
12 bookRecordDatabase[id]={
13 checkoutMember:checkoutMember,
14 checkoutDate:checkoutDate,

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 84/188
26/04/2015 LearningJavaScriptDesignPatterns

15 dueReturnDate:dueReturnDate,
16 availability:availability,
17 book:book
18 };
19 },
20 updateCheckoutStatus:function(bookID,newStatus,checkoutDate,checkoutMember,
21
22 varrecord=bookRecordDatabase[bookID];
23 record.availability=newStatus;
24 record.checkoutDate=checkoutDate;
25 record.checkoutMember=checkoutMember;
26 record.dueReturnDate=newReturnDate;
27 },
28
29 extendCheckoutPeriod:function(bookID,newReturnDate){
30 bookRecordDatabase[bookID].dueReturnDate=newReturnDate;
31 },
32
33 isPastDue:function(bookID){
34 varcurrentDate=newDate();
35 returncurrentDate.getTime()>Date.parse(bookRecordDatabase[bookID].dueReturn
36 }
37 };
38
39 })();

TheresultofthesechangesisthatallofthedatathatsbeenextractedfromtheBookclassisnowbeing
storedinanattributeoftheBookManagersingleton(BookDatabase)somethingconsiderablymore
efficientthanthelargenumberofobjectswewerepreviouslyusing.Methodsrelatedtobookcheckouts
arealsonowbasedhereastheydealwithdatathatsextrinsicratherthanintrinsic.

Thisprocessdoesaddalittlecomplexitytoourfinalsolution,howeveritsasmallconcernwhen
comparedtotheperformanceissuesthathavebeentackled.Datawise,ifwehave30copiesofthesame
book,wearenowonlystoringitonce.Also,everyfunctiontakesupmemory.Withtheflyweight
patternthesefunctionsexistinoneplace(onthemanager)andnotoneveryobject,thussavingon
memoryuse.Fortheabovementionedflyweightunoptimizedversionwestorejustlinktothefunction
objectasweusedBookconstructorsprototypebutifitwasimplementedinotherway,functionswould
becreatedforeverybookinstance.

TheFlyweightpatternandtheDOM
TheDOM(DocumentObjectModel)supportstwoapproachesthatallowobjectstodetecteventseither
topdown(eventcapture)orbottomup(eventbubbling).

Ineventcapture,theeventisfirstcapturedbytheoutermostelementandpropagatedtotheinnermost
element.Ineventbubbling,theeventiscapturedandgiventotheinnermostelementandthen
propagatedtotheouterelements.

OneofthebestmetaphorsfordescribingFlyweightsinthiscontextwaswrittenbyGaryChisholmand
itgoesalittlelikethis:

Trytothinkoftheflyweightintermsofapond.Afishopensitsmouth(theevent),bubblesrise
tothesurface(thebubbling)aflysittingonthetopfliesawaywhenthebubblereachesthe
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 85/188
26/04/2015 LearningJavaScriptDesignPatterns

surface(theaction).Inthisexamplewecaneasilytransposethefishopeningitsmouthtoa
buttonbeingclicked,thebubblesasthebubblingeffectandtheflyflyingawaytosomefunction
beingrun

Bubblingwasintroducedtohandlesituationswhereasingleevent(e.gaclick)maybehandledby
multipleeventhandlersdefinedatdifferentlevelsoftheDOMhierarchy.Wherethishappens,event
bubblingexecuteseventhandlersdefinedforspecificelementsatthelowestlevelpossible.Fromthere
on,theeventbubblesuptocontainingelementsbeforegoingtothoseevenhigherup.

Flyweightscanbeusedtotweaktheeventbubblingprocessfurther,aswewillseeshortly.

Example1:Centralizedeventhandling
Forourfirstpracticalexample,imaginewehaveanumberofsimilarelementsinadocumentwith
similarbehaviorexecutedwhenauseraction(e.gclick,mouseover)isperformedagainstthem.

Normallywhatwedowhenconstructingourownaccordioncomponent,menuorotherlistbased
widgetisbindaclickeventtoeachlinkelementintheparentcontainer(e.g $('ullia').on(..) .Instead
ofbindingtheclicktomultipleelements,wecaneasilyattachaFlyweighttothetopofourcontainer
whichcanlistenforeventscomingfrombelow.Thesecanthenbehandledusinglogicthatisassimple
orcomplexasrequired.

Asthetypesofcomponentsmentionedoftenhavethesamerepeatingmarkupforeachsection(e.g.each
sectionofanaccordion),theresagoodchancethebehaviorofeachelementthatmaybeclickedisgoing
tobequitesimilarandrelativetosimilarclassesnearby.Wellusethisinformationtoconstructavery
basicaccordionusingtheFlyweightbelow.

AstateManagernamespaceisusedheretoencapsulateourflyweightlogicwhilstjQueryisusedtobind
theinitialclicktoacontainerdiv.Inordertoensurethatnootherlogiconthepageisattachingsimilar
handlestothecontainer,anunbindeventisfirstapplied.

Nowtoestablishexactlywhatchildelementinthecontainerisclicked,wemakeuseofa target check


whichprovidesareferencetotheelementthatwasclicked,regardlessofitsparent.Wethenusethis
informationtohandletheclickeventwithoutactuallyneedingtobindtheeventtospecificchildren
whenourpageloads.

HTML

?
1 <divid="container">
2 <divclass="toggle"href="#">MoreInfo(Address)
3 <spanclass="info">
4 Thisismoreinformation
5 </span></div>
6 <divclass="toggle"href="#">EvenMoreInfo(Map)
7 <spanclass="info">
8 <iframesrc="http://www.mapgenerator.net/extmap.php?name=London&amp;addres
9 </span>
10 </div>
11 </div>

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 86/188
26/04/2015 LearningJavaScriptDesignPatterns

JavaScript

?
1 varstateManager={
2
3 fly:function(){
4
5 varself=this;
6
7 $("#container")
8 .unbind()
9 .on("click","div.toggle",function(e){
10 self.handleClick(e.target);
11 });
12 },
13
14 handleClick:function(elem){
15 elem.find("span").toggle("slow");
16 }
17 };

Thebenefithereisthatwereconvertingmanyindependentactionsintoasharedones(potentially
savingonmemory).

Example2:UsingtheFlyweightforperformanceoptimization
Inoursecondexample,wellreferencesomefurtherperformancegainsthatcanbeachievedusing
FlyweightswithjQuery.

JamesPadolseypreviouslywroteanarticlecalled76bytesforfasterjQuerywhereheremindedusthat
eachtimejQueryfiresoffacallback,regardlessoftype(filter,each,eventhandler),wereabletoaccess
thefunctionscontext(theDOMelementrelatedtoit)viathe this keyword.

Unfortunately,manyofushavebecomeusedtotheideaofwrapping this in $() or jQuery() ,which


meansthatanewinstanceofjQueryisunnecessarilyconstructedeverytime,ratherthansimplydoing
this:

?
1 $("div").on("click",function(){
2 console.log("Youclicked:"+$(this).attr("id"));
3 });
4
5 //weshouldavoidusingtheDOMelementtocreatea
6 //jQueryobject(withtheoverheadthatcomeswithit)
7 //andjustusetheDOMelementitselflikethis:
8
9 $("div").on("click",function(){
10 console.log("Youclicked:"+this.id);
11 });

JameshadwantedtousejQuerys jQuery.text inthefollowingcontext,howeverhedisagreedwiththe


notionthatanewjQueryobjecthadtobecreatedoneachiteration:

?
1 $("a").map(function(){
2 return$(this).text();
3 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 87/188
26/04/2015 LearningJavaScriptDesignPatterns

Nowwithrespecttoredundantwrapping,wherepossiblewithjQuerysutilitymethods,itsbetterto
use jQuery.methodName (e.g jQuery.text )asopposedto jQuery.fn.methodName (e.g jQuery.fn.text )where
methodNamerepresentsautilitysuchas each() or text .Thisavoidstheneedtocallafurtherlevelof
abstractionorconstructanewjQueryobjecteachtimeourfunctioniscalledasas jQuery.methodName is
whatthelibraryitselfusesatalowerleveltopower jQuery.fn.methodName .

BecausehowevernotallofjQuerysmethodshavecorrespondingsinglenodefunctions,Padolsey
devisedtheideaofajQuery.singleutility.

TheideahereisthatasinglejQueryobjectiscreatedandusedforeachcalltojQuery.single(effectively
meaningonlyonejQueryobjectisevercreated).Theimplementationforthiscanbefoundbelowandas
wereconsolidatingdataformultiplepossibleobjectsintoamorecentralsingularstructure,itis
technicallyalsoaFlyweight.

1 jQuery.single=(function(o){
2
3 varcollection=jQuery([1]);
4 returnfunction(element){
5
6 //Givecollectiontheelement:
7 collection[0]=element;
8
9 //Returnthecollection:
10 returncollection;
11
12 };
13 })();

Anexampleofthisinactionwithchainingis:

?
1 $("div").on("click",function(){
2
3 varhtml=jQuery.single(this).next().html();
4 console.log(html);
5
6 });

Note:AlthoughwemaybelievethatsimplycachingourjQuerycodemayofferjustasequivalent
performancegains,Padolseyclaimsthat$.single()isstillworthusingandcanperformbetter.Thatsnot
tosaydontapplyanycachingatall,justbemindfulthatthisapproachcanassist.Forfurtherdetails
about$.single,IrecommendreadingPadolseysfullpost.

JavaScriptMV*Patterns
Inthissection,weregoingtoreviewthreeveryimportantarchitecturalpatternsMVC(ModelView
Controller),MVP(ModelViewPresenter)andMVVM(ModelViewViewModel).Inthepast,these
patternshavebeenheavilyusedforstructuringdesktopandserversideapplicationsbutitsonlybeen

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 88/188
26/04/2015 LearningJavaScriptDesignPatterns

inrecentyearsthatcometobeingappliedtoJavaScript.

AsthemajorityofJavaScriptdeveloperscurrentlyusingthesepatternsopttoutilizelibrariessuchas
Backbone.jsforimplementinganMVC/MV*likestructure,wewillcomparehowmodernsolutionssuch
asitdifferintheirinterpretationofMVCcomparedtoclassicaltakesonthesepatterns.

Letusfirstnowcoverthebasics.

MVC
MVCisanarchitecturaldesignpatternthatencouragesimprovedapplicationorganizationthrougha
separationofconcerns.Itenforcestheisolationofbusinessdata(Models)fromuserinterfaces(Views),
withathirdcomponent(Controllers)traditionallymanaginglogicanduserinput.Thepatternwas
originallydesignedbyTrygveReenskaugduringhistimeworkingonSmalltalk80(1979)whereitwas
initiallycalledModelViewControllerEditor.MVCwentontobedescribedindepthin1995sDesign
Patterns:ElementsofReusableObjectOrientedSoftware(TheGoFbook),whichplayedarolein
popularizingitsuse.

Smalltalk80MVC
ItsimportanttounderstandwhattheoriginalMVCpatternwasaimingtosolveasitsmutatedquite
heavilysincethedaysofitsorigin.Backinthe70s,graphicaluserinterfaceswerefewandfarbetween
andaconceptknownasSeparatedPresentationbegantobeusedasameanstomakeacleardivision
betweendomainobjectswhichmodeledconceptsintherealworld(e.gaphoto,aperson)andthe
presentationobjectswhichwererenderedtotheusersscreen.

TheSmalltalk80implementationofMVCtookthisconceptfurtherandhadanobjectiveofseparating
outtheapplicationlogicfromtheuserinterface.Theideawasthatdecouplingthesepartsofthe
applicationwouldalsoallowthereuseofmodelsforotherinterfacesintheapplication.Therearesome
interestingpointsworthnotingaboutSmalltalk80sMVCarchitecture:

AModelrepresenteddomainspecificdataandwasignorantoftheuserinterface(Viewsand
Controllers).Whenamodelchanged,itwouldinformitsobservers.
AViewrepresentedthecurrentstateofaModel.TheObserverpatternwasusedforletting
theViewknowwhenevertheModelwasupdatedormodified.
PresentationwastakencareofbytheView,buttherewasntjustasingleViewandController
aViewControllerpairwasrequiredforeachsectionorelementbeingdisplayedonthe
screen.
TheControllersroleinthispairwashandlinguserinteraction(suchaskeypressesand
actionse.g.clicks),makingdecisionsfortheView.

DevelopersaresometimessurprisedwhentheylearnthattheObserverpattern(nowadayscommonly
implementedasthePublish/Subscribevariation)wasincludedasapartofMVCsarchitecturemany
decadesago.InSmalltalk80sMVC,theViewobservestheModel.Asmentionedinthebulletpoint
above,anytimetheModelchanges,theViewsreact.Asimpleexampleofthisisanapplicationbacked
bystockmarketdatainorderfortheapplicationtobeuseful,anychangetothedatainourModels

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 89/188
26/04/2015 LearningJavaScriptDesignPatterns

shouldresultintheViewbeingrefreshedinstantly.

MartinFowlerhasdoneanexcellentjobofwritingabouttheoriginsofMVCovertheyearsandif
interestedinsomefurtherhistoricalinformationaboutSmalltalk80sMVC,Irecommendreadinghis
work.

MVCForJavaScriptDevelopers
Wevereviewedthe70s,butletusnowreturntothehereandnow.Inmoderntimes,theMVCpattern
hasbeenappliedtoadiverserangeofprogramminglanguagesincludingofmostrelevancetous:
JavaScript.JavaScriptnowhasanumberofframeworksboastingsupportforMVC(orvariationsonit,
whichwerefertoastheMV*family),allowingdeveloperstoeasilyaddstructuretotheirapplications
withoutgreateffort.

TheseframeworksincludethelikesofBackbone,Ember.jsandAngularJS.Giventheimportanceof
avoidingspaghetticode,atermwhichdescribescodethatisverydifficulttoreadormaintaindueto
itslackofstructure,itsimperativethatthemodernJavaScriptdeveloperunderstandwhatthispattern
provides.Thisallowsustoeffectivelyappreciatewhattheseframeworksenableustododifferently.

WeknowthatMVCiscomposedofthreecorecomponents:

Models
Modelsmanagethedataforanapplication.Theyareconcernedwithneithertheuserinterfacenor
presentationlayersbutinsteadrepresentuniqueformsofdatathatanapplicationmayrequire.Whena
modelchanges(e.gwhenitisupdated),itwilltypicallynotifyitsobservers(e.gviews,aconceptwewill
covershortly)thatachangehasoccurredsothattheymayreactaccordingly.

Tounderstandmodelsfurther,letusimaginewehaveaJavaScriptphotogalleryapplication.Inaphoto
gallery,theconceptofaphotowouldmerititsownmodelasitrepresentsauniquekindofdomain
specificdata.Suchamodelmaycontainrelatedattributessuchasacaption,imagesourceand
additionalmetadata.Aspecificphotowouldbestoredinaninstanceofamodelandamodelmayalso
bereusable.BelowwecanseeanexampleofaverysimplisticmodelimplementedusingBackbone.

1 varPhoto=Backbone.Model.extend({
2
3 //Defaultattributesforthephoto
4 defaults:{
5 src:"placeholder.jpg",
6 caption:"Adefaultimage",
7 viewed:false
8 },
9
10 //Ensurethateachphotocreatedhasan`src`.
11 initialize:function(){
12 this.set({"src":this.defaults.src});
13 }
14
15 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 90/188
26/04/2015 LearningJavaScriptDesignPatterns

Thebuiltincapabilitiesofmodelsvaryacrossframeworks,howeveritisquitecommonforthemto
supportvalidationofattributes,whereattributesrepresentthepropertiesofthemodel,suchasamodel
identifier.Whenusingmodelsinrealworldapplicationswegenerallyalsodesiremodelpersistence.
Persistenceallowsustoeditandupdatemodelswiththeknowledgethatitsmostrecentstatewillbe
savedineither:memory,inauserslocalStoragedatastoreorsynchronizedwithadatabase.

Inaddition,amodelmayalsohavemultipleviewsobservingit.Ifsay,ourphotomodelcontainedmeta
datasuchasitslocation(longitudeandlatitude),friendsthatwerepresentinthephoto(alistof
identifiers)andalistoftags,adevelopermaydecidetoprovideasingleviewtodisplayeachofthese
threefacets.

ItisnotuncommonformodernMVC/MV*frameworkstoprovideameanstogroupmodelstogether
(e.g.inBackbone,thesegroupsarereferredtoascollections).Managingmodelsingroupsallowsusto
writeapplicationlogicbasedonnotificationsfromthegroupshouldanymodelitcontainsbechanged.
Thisavoidstheneedtomanuallyobserveindividualmodelinstances.

AsamplegroupingofmodelsintoasimplifiedBackbonecollectioncanbeseenbelow.

1 varPhotoGallery=Backbone.Collection.extend({
2
3 //Referencetothiscollection'smodel.
4 model:Photo,
5
6 //Filterdownthelistofallphotos
7 //thathavebeenviewed
8 viewed:function(){
9 returnthis.filter(function(photo){
10 returnphoto.get("viewed");
11 });
12 },
13
14 //Filterdownthelisttoonlyphotosthat
15 //havenotyetbeenviewed
16 unviewed:function(){
17 returnthis.without.apply(this,this.viewed());
18 }
19 });

OldertextsonMVCmayalsocontainreferencetoanotionofmodelsmanagingapplicationstate.In
JavaScriptapplicationsstatehasadifferentconnotation,typicallyreferringtothecurrentstatei.eview
orsubview(withspecificdata)onausersscreenatafixedpoint.Stateisatopicwhichisregularly
discussedwhenlookingatSinglepageapplications,wheretheconceptofstateneedstobesimulated.

Sotosummarize,modelsareprimarilyconcernedwithbusinessdata.

Views
Viewsareavisualrepresentationofmodelsthatpresentafilteredviewoftheircurrentstate.Whilst
Smalltalkviewsareaboutpaintingandmaintainingabitmap,JavaScriptviewsareaboutbuildingand
maintainingaDOMelement.

Aviewtypicallyobservesamodelandisnotifiedwhenthemodelchanges,allowingtheviewtoupdate

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 91/188
26/04/2015 LearningJavaScriptDesignPatterns

itselfaccordingly.Designpatternliteraturecommonlyreferstoviewsasdumbgiventhattheir
knowledgeofmodelsandcontrollersinanapplicationislimited.

Usersareabletointeractwithviewsandthisincludestheabilitytoreadandedit(i.egetorsetthe
attributevaluesin)models.Astheviewisthepresentationlayer,wegenerallypresenttheabilitytoedit
andupdateinauserfriendlyfashion.Forexample,intheformerphotogalleryapplicationwe
discussedearlier,modeleditingcouldbefacilitatedthroughaneditviewwhereauserwhohas
selectedaspecificphotocouldedititsmetadata.

Theactualtaskofupdatingthemodelfallstocontrollers(whichwewillbecoveringshortly).

LetsexploreviewsalittlefurtherusingavanillaJavaScriptsampleimplementation.Belowwecanseea
functionthatcreatesasinglePhotoview,consumingbothamodelinstanceandacontrollerinstance.

Wedefinea render() utilitywithinourviewwhichisresponsibleforrenderingthecontentsofthe


photoModel usingaJavaScripttemplatingengine(Underscoretemplating)andupdatingthecontentsof
ourview,referencedby photoEl .

The photoModel thenaddsour render() callbackasoneofitssubscriberssothatthroughtheObserver


patternwecantriggertheviewtoupdatewhenthemodelchanges.

Onemaywonderwhereuserinteractioncomesintoplayhere.Whenusersclickonanyelementswithin
theview,itsnottheviewsresponsibilitytoknowwhattodonext.Itreliesonacontrollertomakethis
decisionforit.Inoursampleimplementation,thisisachievedbyaddinganeventlistenerto photoEl
whichwilldelegatehandlingtheclickbehaviorbacktothecontroller,passingthemodelinformation
alongwithitincaseitsneeded.

Thebenefitofthisarchitectureisthateachcomponentplaysitsownseparateroleinmakingthe
applicationfunctionasneeded.

?
1 varbuildPhotoView=function(photoModel,photoController){
2
3 varbase=document.createElement("div"),
4 photoEl=document.createElement("div");
5
6 base.appendChild(photoEl);
7
8 varrender=function(){
9 //WeuseatemplatinglibrarysuchasUnderscore
10 //templatingwhichgeneratestheHTMLforour
11 //photoentry
12 photoEl.innerHTML=_.template("#photoTemplate",{
13 src:photoModel.getSrc()
14 });
15 };
16
17 photoModel.addSubscriber(render);
18
19 photoEl.addEventListener("click",function(){
20 photoController.handleEvent("click",photoModel);
21 });
22
23 varshow=function(){
24 photoEl.style.display="";
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 92/188
26/04/2015 LearningJavaScriptDesignPatterns

25 };
26
27 varhide=function(){
28 photoEl.style.display="none";
29 };
30
31 return{
32 showView:show,
33 hideView:hide
34 };
35
36 };

Templating

InthecontextofJavaScriptframeworksthatsupportMVC/MV*,itisworthbrieflydiscussingJavaScript
templatinganditsrelationshiptoviewsaswebrieflytoucheduponitinthelastsection.

Ithaslongbeenconsidered(andproven)aperformancebadpracticetomanuallycreatelargeblocksof
HTMLmarkupinmemorythroughstringconcatenation.Developersdoingsohavefallenpreyto
inperformantlyiteratingthroughtheirdata,wrappingitinnesteddivsandusingoutdatedtechniques
suchas document.write toinjectthetemplateintotheDOM.Asthistypicallymeanskeepingscripted
markupinlinewithourstandardmarkup,itcanquicklybecomebothdifficulttoreadandmore
importantly,maintainsuchdisasters,especiallywhenbuildingnontriviallysizedapplications.

JavaScripttemplatingsolutions(suchasHandlebars.jsandMustache)areoftenusedtodefinetemplates
forviewsasmarkup(eitherstoredexternallyorwithinscripttagswithacustomtypee.g
text/template)containingtemplatevariables.Variablesmaybedelimitatedusingavariablesyntax(e.g
{{name}})andframeworksaretypicallysmartenoughtoacceptdatainaJSONform(whichmodel
instancescanbeconvertedto)suchthatweonlyneedbeconcernedwithmaintainingcleanmodelsand
cleantemplates.Mostofthegruntworktodowithpopulationistakencareofbytheframeworkitself.
Thishasalargenumberofbenefits,particularlywhenoptingtostoretemplatesexternallyasthiscan
givewaytotemplatesbeingdynamicallyloadedonanasneededbasiswhenitcomestobuildinglarger
applications.

BelowwecanseetwoexamplesofHTMLtemplates.OneimplementedusingthepopularHandlebars.js
frameworkandanotherusingUnderscorestemplates.

Handlebars.js:

?
1 <liclass="photo">
2 <h2>{{caption}}</h2>
3 <imgclass="source"src="{{src}}"/>
4 <divclass="metadata">
5 {{metadata}}
6 </div>
7 </li>

Underscore.jsMicrotemplates:

?
1 <liclass="photo">

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 93/188
26/04/2015 LearningJavaScriptDesignPatterns

2 <h2><%=caption%></h2>
3 <imgclass="source"src="<%=src%>"/>
4 <divclass="metadata">
5 <%=metadata%>
6 </div>
7 </li>

Notethattemplatesarenotthemselvesviews.DeveloperscomingfromaStrutsModel2architecture
mayfeellikeatemplate*is*aview,butitisnt.Aviewisanobjectwhichobservesamodelandkeeps
thevisualrepresentationuptodate.Atemplate*might*beadeclarativewaytospecifypartorevenall
ofaviewobjectsothatitcanbegeneratedfromthetemplatespecification.

Itisalsoworthnotingthatinclassicalwebdevelopment,navigatingbetweenindependentviews
requiredtheuseofapagerefresh.InSinglepageJavaScriptapplicationshowever,oncedataisfetched
fromaserverviaAjax,itcansimplybedynamicallyrenderedinanewviewwithinthesamepage
withoutanysuchrefreshbeingnecessary.

Theroleofnavigationthusfallstoarouter,whichassistsinmanagingapplicationstate(e.gallowing
userstobookmarkaparticularviewtheyhavenavigatedto).Asroutersare,however,neitherapartof
MVCnorpresentineveryMVClikeframework,Iwillnotbegoingintothemingreaterdetailinthis
section.

Tosummarize,viewsareavisualrepresentationofourapplicationdata.

Controllers
Controllersareanintermediarybetweenmodelsandviewswhichareclassicallyresponsiblefor
updatingthemodelwhentheusermanipulatestheview.

Inourphotogalleryapplication,acontrollerwouldberesponsibleforhandlingchangestheusermade
totheeditviewforaparticularphoto,updatingaspecificphotomodelwhenauserhasfinished
editing.

RememberthatthecontrollersfulfilloneroleinMVC:thefacilitationoftheStrategypatternforthe
view.IntheStrategypatternregard,theviewdelegatestothecontrollerattheviewsdiscretion.So,
thatshowthestrategypatternworks.Theviewcoulddelegatehandlingusereventstothecontroller
whentheviewseesfit.Theview*could*delegatehandlingmodelchangeeventstothecontrollerifthe
viewseesfit,butthisisnotthetraditionalroleofthecontroller.

IntermsofwheremostJavaScriptMVCframeworksdetractfromwhatisconventionallyconsidered
MVChowever,itiswithcontrollers.Thereasonsforthisvary,butinmyhonestopinion,itisthat
frameworkauthorsinitiallylookattheserversideinterpretationofMVC,realizethatitdoesnttranslate
1:1ontheclientsideandreinterprettheCinMVCtomeansomethingtheyfeelmakesmoresense.The
issuewiththishoweveristhatitissubjective,increasesthecomplexityinbothunderstandingthe
classicalMVCpatternandofcoursetheroleofcontrollersinmodernframeworks.

Asanexample,letsbrieflyreviewthearchitectureofthepopulararchitecturalframeworkBackbone.js.
Backbonecontainsmodelsandviews(somewhatsimilartowhatwereviewedearlier),howeverit
doesntactuallyhavetruecontrollers.Itsviewsandroutersactalittlesimilartoacontroller,butneither
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 94/188
26/04/2015 LearningJavaScriptDesignPatterns

areactuallycontrollersontheirown.

Inthisrespect,contrarytowhatmightbementionedintheofficialdocumentationorinblogposts,
BackboneisneitheratrulyMVC/MVPnorMVVMframework.Itsinfactbettertoconsideritamember
oftheMV*familywhichapproachesarchitectureinitsownway.Thereisofcoursenothingwrongwith
this,butitisimportanttodistinguishbetweenclassicalMVCandMV*shouldwebeginrelyingon
advicefromclassicalliteratureontheformertohelpwiththelatter.

Controllersinanotherlibrary(Spine.js)vsBackbone.js
Spine.js

Wenowknowthatcontrollersaretraditionallyresponsibleforupdatingthemodelwhentheuser
updatestheview.ItsinterestingtonotethatthemostpopularJavaScriptMVC/MV*frameworkatthe
timeofwriting(Backbone)doesnothaveitsownexplicitconceptofcontrollers.

ItcanthusbeusefulforustoreviewthecontrollerfromanotherMVCframeworktoappreciatethe
differenceinimplementationsandfurtherdemonstratehownontraditionallyframeworksapproachthe
roleofthecontroller.Forthis,letstakealookatasamplecontrollerfromSpine.js:

Inthisexample,weregoingtohaveacontrollercalled PhotosController whichwillbeinchargeof


individualphotosintheapplication.Itwillensurethatwhentheviewupdates(e.gausereditedthe
photometadata)thecorrespondingmodeldoestoo.

Note:WewontbedelvingheavilyintoSpine.jsatall,butwilljusttakeatenfootviewofwhatits
controllerscando:

1 //ControllersinSpinearecreatedbyinheritingfromSpine.Controller
2
3 varPhotosController=Spine.Controller.sub({
4
5 init:function(){
6 this.item.bind("update",this.proxy(this.render));
7 this.item.bind("destroy",this.proxy(this.remove));
8 },
9
10 render:function(){
11 //Handletemplating
12 this.replace($("#photoTemplate").tmpl(this.item));
13 returnthis;
14 },
15
16 remove:function(){
17 this.el.remove();
18 this.release();
19 }
20 });

InSpine,controllersareconsideredtheglueforanapplication,addingandrespondingtoDOMevents,
renderingtemplatesandensuringthatviewsandmodelsarekeptinsync(whichmakessenseinthe
contextofwhatweknowtobeacontroller).

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 95/188
26/04/2015 LearningJavaScriptDesignPatterns

Whatweredoingintheaboveexampleissettinguplistenersinthe update and destroy eventsusing


render() and remove() .Whenaphotoentrygetsupdated,wererendertheviewtoreflectthechanges
tothemetadata.Similarly,ifthephotogetsdeletedfromthegallery,weremoveitfromtheview.Inthe
render()function,wereusingUnderscoremicrotemplating(via _.template() )torenderaJavaScript
templatewiththeID#photoTemplate.ThissimplyreturnsacompiledHTMLstringusedtopopulate
thecontentsof photoEl .

Whatthisprovidesuswithisaverylightweight,simplewaytomanagechangesbetweenthemodeland
theview.

Backbone.js

LateroninthissectionweregoingtorevisitthedifferencesbetweenBackboneandtraditionalMVC,
butfornowletsfocusoncontrollers.

InBackbone,onesharestheresponsibilityofacontrollerwithboththe Backbone.View and


Backbone.Router .SometimeagoBackbonedidoncecomewithitsown Backbone.Controller ,butasthe
namingforthiscomponentdidntmakesenseforthecontextinwhichitwasbeingused,itwaslater
renamedtoRouter.

Routershandlealittlemoreofthecontrollerresponsibilityasitspossibletobindtheeventstherefor
modelsandhaveourviewrespondtoDOMeventsandrendering.AsTimBranyen(anotherBocoup
basedBackbonecontributor)hasalsopreviouslypointedout,itspossibletogetawaywithnotneeding
Backbone.Router atallforthis,soawaytothinkaboutitusingtheRouterparadigmisprobably:

1 varPhotoRouter=Backbone.Router.extend({
2 routes:{"photos/:id":"route"},
3
4 route:function(id){
5 varitem=photoCollection.get(id);
6 varview=newPhotoView({model:item});
7
8 $('.content').html(view.render().el);
9 }
10 });

Tosummarize,thetakeawayfromthissectionisthatcontrollersmanagethelogicandcoordination
betweenmodelsandviewsinanapplication.

WhatdoesMVCgiveus?
ThisseparationofconcernsinMVCfacilitatessimplermodularizationofanapplicationsfunctionality
andenables:

Easieroverallmaintenance.Whenupdatesneedtobemadetotheapplicationitisveryclear
whetherthechangesaredatacentric,meaningchangestomodelsandpossiblycontrollers,or
merelyvisual,meaningchangestoviews.
Decouplingmodelsandviewsmeansthatitissignificantlymorestraightforwardtowrite

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 96/188
26/04/2015 LearningJavaScriptDesignPatterns

unittestsforbusinesslogic
Duplicationoflowlevelmodelandcontrollercode(i.ewhatwemayhavebeenusing
instead)iseliminatedacrosstheapplication
Dependingonthesizeoftheapplicationandseparationofroles,thismodularityallows
developersresponsibleforcorelogicanddevelopersworkingontheuserinterfacestowork
simultaneously

Smalltalk80MVCInJavaScript
AlthoughthemajorityofmoderndayJavaScriptframeworksattempttoevolvetheMVCparadigmto
betterfitthedifferingneedsofwebapplicationdevelopment,thereisoneframeworkwhichattemptsto
adheretothepureformofthepatternfoundinSmalltalk80.Maria.js
(https://github.com/petermichaux/maria)byPeterMichauxoffersanimplementationwhichisfaithfulto
MVCsoriginsModelsaremodels,ViewsareviewsandControllersarenothingbutcontrollers.Whilst
somedevelopersmightfeelanMV*frameworkshouldaddressmoreconcerns,thisisausefulreference
tobeawareofincaseyouwouldlikeaJavaScriptimplementationoftheoriginalMVC.

Delvingdeeper
Atthispointinthebook,weshouldhaveabasicunderstandingofwhattheMVCpatternprovides,but
theresstillsomefascinatinginformationaboutitworthnoting.

TheGoFdonotrefertoMVCasadesignpattern,butratherconsideritasetofclassestobuildauser
interface.Intheirview,itsactuallyavariationofthreeclassicaldesignpatterns:theObserver,Strategy
andCompositepatterns.DependingonhowMVChasbeenimplementedinaframework,itmayalso
usetheFactoryandTemplatepatterns.TheGoFbookmentionsthesepatternsasusefulextraswhen
workingwithMVC.

Aswehavediscussed,modelsrepresentapplicationdatawhilstviewsarewhattheuserispresentedon
screen.Assuch,MVCreliesontheObserverpatternforsomeofitscorecommunication(somethingthat
surprisinglyisntcoveredinmanyarticlesabouttheMVCpattern).Whenamodelischangeditnotifies
itsobservers(Views)thatsomethinghasbeenupdatedthisisperhapsthemostimportantrelationship
inMVC.Theobservernatureofthisrelationshipisalsowhatfacilitatesmultipleviewsbeingattachedto
thesamemodel.

FordevelopersinterestedinknowingmoreaboutthedecouplednatureofMVC(onceagain,depending
ontheimplementation),oneofthegoalsofthepatternistohelpdefineonetomanyrelationships
betweenatopic(dataobject)anditsobservers.Whenatopicchanges,itsobserversareupdated.Views
andcontrollershaveaslightlydifferentrelationship.Controllersfacilitateviewstorespondtodifferent
userinputandareanexampleoftheStrategypattern.

Summary
HavingreviewedtheclassicalMVCpattern,weshouldnowunderstandhowitallowsustocleanly
separateconcernsinanapplication.WeshouldalsonowappreciatehowJavaScriptMVCframeworks
maydifferintheirinterpretationoftheMVCpattern,whichalthoughquiteopentovariation,still

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 97/188
26/04/2015 LearningJavaScriptDesignPatterns

sharessomeofthefundamentalconceptstheoriginalpatternhastooffer.

WhenreviewinganewJavaScriptMVC/MV*framework,rememberitcanbeusefultostepbackand
reviewhowitsoptedtoapproacharchitecture(specifically,howitsupportsimplementingmodels,
views,controllersorotheralternatives)asthiscanbetterhelpusgrokhowtheframeworkexpectstobe
used.

MVP
Modelviewpresenter(MVP)isaderivativeoftheMVCdesignpatternwhichfocusesonimproving
presentationlogic.ItoriginatedatacompanynamedTaligentintheearly1990swhiletheywere
workingonamodelforaC++CommonPointenvironment.WhilstbothMVCandMVPtargetthe
separationofconcernsacrossmultiplecomponents,therearesomefundamentaldifferencesbetween
them.

ForthepurposesofthissummarywewillfocusontheversionofMVPmostsuitableforwebbased
architectures.

Models,Views&Presenters
ThePinMVPstandsforpresenter.Itsacomponentwhichcontainstheuserinterfacebusinesslogicfor
theview.UnlikeMVC,invocationsfromtheviewaredelegatedtothepresenter,whicharedecoupled
fromtheviewandinsteadtalktoitthroughaninterface.Thisallowsforallkindsofusefulthingssuch
asbeingabletomockviewsinunittests.

ThemostcommonimplementationofMVPisonewhichusesaPassiveView(aviewwhichisforall
intentsandpurposesdumb),containinglittletonologic.IfMVCandMVParedifferentitisbecause
theCandPdodifferentthings.InMVP,thePobservesmodelsandupdatesviewswhenmodels
change.ThePeffectivelybindsmodelstoviews,aresponsibilitywhichwaspreviouslyheldby
controllersinMVC.

Solicitedbyaview,presentersperformanyworktodowithuserrequestsandpassdatabacktothem.
Inthisrespect,theyretrievedata,manipulateitanddeterminehowthedatashouldbedisplayedinthe
view.Insomeimplementations,thepresenteralsointeractswithaservicelayertopersistdata(models).
Modelsmaytriggereventsbutitsthepresentersroletosubscribetothemsothatitcanupdatetheview.
Inthispassivearchitecture,wehavenoconceptofdirectdatabinding.Viewsexposesetterswhich
presenterscanusetosetdata.

ThebenefitofthischangefromMVCisthatitincreasesthetestabilityofourapplicationandprovidesa
morecleanseparationbetweentheviewandthemodel.Thisisnthoweverwithoutitscostsasthelack
ofdatabindingsupportinthepatterncanoftenmeanhavingtotakecareofthistaskseparately.

AlthoughacommonimplementationofaPassiveViewisfortheviewtoimplementaninterface,there
arevariationsonit,includingtheuseofeventswhichcandecoupletheViewfromthePresenteralittle
more.AswedonthavetheinterfaceconstructinJavaScript,wereusingmoreaprotocolthanan
explicitinterfacehere.ItstechnicallystillanAPIanditsprobablyfairforustorefertoitasaninterface

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 98/188
26/04/2015 LearningJavaScriptDesignPatterns

fromthatperspective.

ThereisalsoaSupervisingControllervariationofMVP,whichisclosertotheMVCandMVVM
patternsasitprovidesdatabindingfromtheModeldirectlyfromtheView.Keyvalueobserving(KVO)
plugins(suchasDerickBaileysBackbone.ModelBindingplugin)tendtobringBackboneoutofthe
PassiveViewandmoreintotheSupervisingControllerorMVVMvariations.

MVPorMVC?
MVPisgenerallyusedmostofteninenterpriselevelapplicationswhereitsnecessarytoreuseasmuch
presentationlogicaspossible.Applicationswithverycomplexviewsandagreatdealofuserinteraction
mayfindthatMVCdoesntquitefitthebillhereassolvingthisproblemmaymeanheavilyrelyingon
multiplecontrollers.InMVP,allofthiscomplexlogiccanbeencapsulatedinapresenter,whichcan
simplifymaintenancegreatly.

AsMVPviewsaredefinedthroughaninterfaceandtheinterfaceistechnicallytheonlypointofcontact
betweenthesystemandtheview(otherthanapresenter),thispatternalsoallowsdeveloperstowrite
presentationlogicwithoutneedingtowaitfordesignerstoproducelayoutsandgraphicsforthe
application.

Dependingontheimplementation,MVPmaybeeasiertoautomaticallyunittestthanMVC.Thereason
oftencitedforthisisthatthepresentercanbeusedasacompletemockoftheuserinterfaceandsoit
canbeunittestedindependentofothercomponents.Inmyexperiencethisreallydependsonthe
languagesweareimplementingMVPin(theresquiteadifferencebetweenoptingforMVPfora
JavaScriptprojectoveroneforsay,ASP.net).

Attheendoftheday,theunderlyingconcernswemayhavewithMVCwilllikelyholdtrueforMVP
giventhatthedifferencesbetweenthemaremainlysemantic.Aslongaswearecleanlyseparating
concernsintomodels,viewsandcontrollers(orpresenters)weshouldbeachievingmostofthesame
benefitsregardlessofthevariationweoptfor.

MVC,MVPandBackbone.js
Thereareveryfew,ifanyarchitecturalJavaScriptframeworksthatclaimtoimplementtheMVCor
MVPpatternsintheirclassicalformasmanyJavaScriptdevelopersdontviewMVCandMVPasbeing
mutuallyexclusive(weareactuallymorelikelytoseeMVPstrictlyimplementedwhenlookingatweb
frameworkssuchasASP.netorGWT).Thisisbecauseitspossibletohaveadditionalpresenter/view
logicinourapplicationandyetstillconsideritaflavorofMVC.

BackbonecontributorIreneRos(ofBostonbasedBocoup)subscribestothiswayofthinkingaswhen
sheseparatesviewsoutintotheirowndistinctcomponents,sheneedssomethingtoactuallyassemble
themforher.Thiscouldeitherbeacontrollerroute(suchasa Backbone.Router ,coveredlaterinthebook)
oracallbackinresponsetodatabeingfetched.

Thatsaid,somedevelopersdohoweverfeelthatBackbone.jsbetterfitsthedescriptionofMVPthanit
doesMVC.Theirviewisthat:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 99/188
26/04/2015 LearningJavaScriptDesignPatterns

ThepresenterinMVPbetterdescribesthe Backbone.View (thelayerbetweenViewtemplates


andthedataboundtoit)thanacontrollerdoes
Themodelfits Backbone.Model (itisntgreatlydifferenttothemodelsinMVCatall)
Theviewsbestrepresenttemplates(e.gHandlebars/Mustachemarkuptemplates)

AresponsetothiscouldbethattheviewcanalsojustbeaView(asperMVC)becauseBackboneis
flexibleenoughtoletitbeusedformultiplepurposes.TheVinMVCandthePinMVPcanbothbe
accomplishedby Backbone.View becausetheyreabletoachievetwopurposes:bothrenderingatomic
componentsandassemblingthosecomponentsrenderedbyotherviews.

WevealsoseenthatinBackbonetheresponsibilityofacontrollerissharedwithboththe
Backbone.ViewandBackbone.Routerandinthefollowingexamplewecanactuallyseethataspectsof
thatarecertainlytrue.

OurBackbone PhotoView usestheObserverpatterntosubscribetochangestoaViewsmodelinthe


line this.model.bind("change",...) .Italsohandlestemplatinginthe render() method,butunlikesome
otherimplementations,userinteractionisalsohandledintheView(see events ).

1 varPhotoView=Backbone.View.extend({
2
3 //...isalisttag.
4 tagName:"li",
5
6 //Passthecontentsofthephototemplatethroughatemplating
7 //function,cacheitforasinglephoto
8 template:_.template($("#phototemplate").html()),
9
10 //TheDOMeventsspecifictoanitem.
11 events:{
12 "clickimg":"toggleViewed"
13 },
14
15 //ThePhotoViewlistensforchangesto
16 //itsmodel,rerendering.Sincethere's
17 //aonetoonecorrespondencebetweena
18 //**Photo**anda**PhotoView**inthis
19 //app,wesetadirectreferenceonthemodelforconvenience.
20
21 initialize:function(){
22 this.model.on("change",this.render,this);
23 this.model.on("destroy",this.remove,this);
24 },
25
26 //Rerenderthephotoentry
27 render:function(){
28 $(this.el).html(this.template(this.model.toJSON()));
29 returnthis;
30 },
31
32 //Togglethe`"viewed"`stateofthemodel.
33 toggleViewed:function(){
34 this.model.viewed();
35 }
36
37 });

Another(quitedifferent)opinionisthatBackbonemorecloselyresemblesSmalltalk80MVC,whichwe

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 100/188
26/04/2015 LearningJavaScriptDesignPatterns

wentthroughearlier.

AsregularBackbonebloggerDerickBaileyhaspreviouslyputit,itsultimatelybestnottoforce
Backbonetofitanyspecificdesignpatterns.Designpatternsshouldbeconsideredflexibleguidesto
howapplicationsmaybestructuredandinthisrespect,BackbonefitsneitherMVCnorMVP.Instead,it
borrowssomeofthebestconceptsfrommultiplearchitecturalpatternsandcreatesaflexibleframework
thatjustworkswell.

Itishoweverworthunderstandingwhereandwhytheseconceptsoriginated,soIhopethatmy
explanationsofMVCandMVPhavebeenofhelp.CallittheBackboneway,MV*orwhateverhelps
referenceitsflavorofapplicationarchitecture.MoststructuralJavaScriptframeworkswilladopttheir
owntakeonclassicalpatterns,eitherintentionallyorbyaccident,buttheimportantthingisthatthey
helpusdevelopapplicationswhichareorganized,cleanandcanbeeasilymaintained.

MVVM
MVVM(ModelViewViewModel)isanarchitecturalpatternbasedonMVCandMVP,whichattempts
tomoreclearlyseparatethedevelopmentofuserinterfaces(UI)fromthatofthebusinesslogicand
behaviorinanapplication.Tothisend,manyimplementationsofthispatternmakeuseofdeclarative
databindingstoallowaseparationofworkonViewsfromotherlayers.

ThisfacilitatesUIanddevelopmentworkoccurringalmostsimultaneouslywithinthesamecodebase.
UIdeveloperswritebindingstotheViewModelwithintheirdocumentmarkup(HTML),wherethe
ModelandViewModelaremaintainedbydevelopersworkingonthelogicfortheapplication.

History
MVVM(byname)wasoriginallydefinedbyMicrosoftforusewithWindowsPresentationFoundation
(WPF)andSilverlight,havingbeenofficiallyannouncedin2005byJohnGrossmaninablogpostabout
Avalon(thecodenameforWPF).ItalsofoundsomepopularityintheAdobeFlexcommunityasan
alternativetosimplyusingMVC.

PriortoMicrosoftadoptingtheMVVMname,therewashoweveramovementinthecommunitytogo
fromMVPtoMVPM:ModelViewPresentationModel.MartinFowlerwroteanarticleon
PresentationModelsbackin2004forthoseinterestedinreadingmoreaboutit.Theideaofa
PresentationModelhadbeenaroundmuchlongerthanthisarticle,howeveritwasconsideredthebig
breakintheideaandgreatlyhelpedpopularizeit.

Therewasquitealotofuproarinthealt.netcirclesafterMicrosoftannouncedMVVMasanalternative
toMVPM.ManyclaimedthecompanysdominanceintheGUIworldwasgivingthemtheopportunity
totakeoverthecommunityasawhole,renamingexistingconceptsastheypleasedformarketing
purposes.AprogressivecrowdrecognizedthatwhilstMVVMandMVPMwereeffectivelythesame
idea,theycameinslightlydifferentpackages.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 101/188
26/04/2015 LearningJavaScriptDesignPatterns

Inrecentyears,MVVMhasbeenimplementedinJavaScriptintheformofstructuralframeworkssuch
asKnockoutJS,KendoMVVMandKnockback.js,withanoverallpositiveresponsefromthecommunity.

LetsnowreviewthethreecomponentsthatcomposeMVVM.

Model
AswithothermembersoftheMV*family,theModelinMVVMrepresentsdomainspecificdataor
informationthatourapplicationwillbeworkingwith.Atypicalexampleofdomainspecificdatamight
beauseraccount(e.gname,avatar,email)oramusictrack(e.gtitle,year,album).

Modelsholdinformation,buttypicallydonthandlebehavior.Theydontformatinformationor
influencehowdataappearsinthebrowserasthisisnttheirresponsibility.Instead,formattingofdatais
handledbytheView,whilstbehaviorisconsideredbusinesslogicthatshouldbeencapsulatedin
anotherlayerthatinteractswiththeModeltheViewModel.

TheonlyexceptiontothisruletendstobevalidationanditsconsideredacceptableforModelsto
validatedatabeingusedtodefineorupdateexistingmodels(e.gdoesanemailaddressbeinginput
meettherequirementsofaparticularregularexpression?).

InKnockoutJS,Modelsfallundertheabovedefinition,butoftenmakeAjaxcallstoaserversideservice
tobothreadandwriteModeldata.

IfwewereconstructingasimpleTodoapplication,aKnockoutJSModelrepresentingasingleTodoitem
couldlookasfollows:

?
1 varTodo=function(content,done){
2 this.content=ko.observable(content);
3 this.done=ko.observable(done);
4 this.editing=ko.observable(false);
5 };

Note:Onemaynoticeintheabovesnippetthatwearecallingthemethod observable() onthe


KnockoutJSnamespace ko .InKnockoutJS,observablesarespecialJavaScriptobjectsthatcannotify
subscribersaboutchangesandautomaticallydetectdependencies.ThisallowsustosynchronizeModels
andViewModelswhenthevalueofaModelattributeismodified.

View
AswithMVC,theViewistheonlypartoftheapplicationthatusersactuallyinteractwith.Theyarean
interactiveUIthatrepresentthestateofaViewModel.Inthissense,theviewisconsideredactiverather
thanpassive,butthisisalsotrueforviewsinMVCandMVP.InMVC,MVPandMVVMaviewcan
alsobepassive,butwhatdoesthismean?

ApassiveViewonlyoutputsadisplayanddoesnotacceptanyuserinput.

Suchaviewmayalsohavenorealknowledgeofthemodelsinourapplicationandcouldbe
manipulatedbyapresenter.MVVMsactiveViewcontainsthedatabindings,eventsandbehaviors
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 102/188
26/04/2015 LearningJavaScriptDesignPatterns

whichrequiresanunderstandingoftheViewModel.Althoughthesebehaviorscanbemappedto
properties,theViewisstillresponsibleforhandlingeventsfromtheViewModel.

ItsimportanttoremembertheViewisntresponsiblehereforhandlingstateitkeepsthisinsyncwith
theViewModel.

AKnockoutJSViewissimplyaHTMLdocumentwithdeclarativebindingstolinkittotheViewModel.
KnockoutJSViewsdisplayinformationfromtheViewModel,passcommandstoit(e.gauserclickingon
anelement)andupdateasthestateoftheViewModelchanges.Templatesgeneratingmarkupusing
datafromtheViewModelcanhoweveralsobeusedforthispurpose.

Togiveabriefinitialexample,wecanlooktotheJavaScriptMVVMframeworkKnockoutJSforhowit
allowsthedefinitionofaViewModelanditsrelatedbindingsinmarkup:

ViewModel:

?
1 varaViewModel={
2 contactName:ko.observable("John")
3 };
4 ko.applyBindings(aViewModel);

View:

1 <p><inputid="source"databind="value:contactName,valueUpdate:'keyup'"/></p>
2 <divdatabind="visible:contactName().length>10">
3 Youhaveareallylongname!
4 </div>
5 <p>Contactname:<strongdatabind="text:contactName"></strong></p>

Ourinputtextbox(source)obtainsitsinitialvaluefrom contactName ,automaticallyupdatingthisvalue


whenevercontactNamechanges.Asthedatabindingistwoway,typingintothetextboxwillupdate
contactName accordinglysothevaluesarealwaysinsync.

AlthoughimplementationspecifictoKnockoutJS,the <div> containingtheYouhaveareallylong


name!textalsocontainssimplevalidation(onceagainintheformofdatabindings).Iftheinput
exceeds10characters,itwilldisplay,otherwiseitwillremainhidden.

Movingontoamoreadvancedexample,wecanreturntoourTodoapplication.Atrimmeddown
KnockoutJSViewforthis,includingallthenecessarydatabindingsmaylookasfollows.

?
1 <divid="todoapp">
2 <header>
3 <h1>Todos</h1>
4 <inputid="newtodo"type="text"databind="value:current,valueUpdate:'aft
5 placeholder="Whatneedstobedone?"/>
6 </header>
7 <sectionid="main"databind="block:todos().length">
8
9 <inputid="toggleall"type="checkbox"databind="checked:allCompleted"

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 103/188
26/04/2015 LearningJavaScriptDesignPatterns
10 <labelfor="toggleall">Markallascomplete</label>
11
12 <ulid="todolist"databind="foreach:todos">
13
14 <!item>
15 <lidatabind="css:{done:done,editing:editing}">
16 <divclass="view"databind="event:{dblclick:$root.editItem}"
17 <inputclass="toggle"type="checkbox"databind="checked:done"
18 <labeldatabind="text:content"></label>
19 <aclass="destroy"href="#"databind="click:$root.remove"
20 </div>
21 <inputclass="edit'type="text"
22 databind="value:content,valueUpdate:'afterkeydown',enterK
23 </li>
24
25 </ul>
26
27 </section>
28 </div>

Notethatthebasiclayoutofthemarkupisrelativelystraightforward,containinganinputtextbox
( newtodo )foraddingnewitems,togglersformarkingitemsascompleteandalist( todolist )witha
templateforaTodoitemintheformofan li .

Thedatabindingsintheabovemarkupcanbebrokendownasfollows:

Theinputtextbox newtodo hasadatabindingforthe current property,whichiswherethe


valueofthecurrentitembeingaddedisstored.OurViewModel(shownshortly)observesthe
current propertyandalsohasabindingagainstthe add event.Whentheenterkeyis
pressed,the add eventistriggeredandourViewModelcanthentrimthevalueof current
andaddittotheTodolistasneeded
Theinputcheckbox toggleall canmarkallofthecurrentitemsascompletedifclicked.If
checked,ittriggersthe allCompleted event,whichcanbeseeninourViewModel
Theitem li hastheclass done .Whenataskismarkedasdone,theCSSclass editing is
markedaccordingly.Ifdoubleclickingontheitem,the $root.editItem callbackwillbe
executed
Thecheckboxwiththeclass toggle showsthestateofthe done property
AlabelcontainsthetextvalueoftheTodoitem( content )
Thereisalsoaremovebuttonthatwillcallthe $root.remove callbackwhenclicked.
AninputtextboxusedforeditingmodealsoholdsthevalueoftheTodoitem content .The
enterKey eventwillsetthe editing propertytotrueorfalse

ViewModel
TheViewModelcanbeconsideredaspecializedControllerthatactsasadataconverter.Itchanges
ModelinformationintoViewinformation,passingcommandsfromtheViewtotheModel.

Forexample,letusimaginethatwehaveamodelcontainingadateattributeinunixformat(e.g
1333832407).Ratherthanourmodelsbeingawareofausersviewofthedate(e.g04/07/2012@5:00pm),
whereitwouldbenecessarytoconverttheattributetoitsdisplayformat,ourmodelsimplyholdsthe
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 104/188
26/04/2015 LearningJavaScriptDesignPatterns

rawformatofthedata.OurViewcontainstheformatteddateandourViewModelactsasamiddleman
betweenthetwo.

Inthissense,theViewModelmightbelookeduponasmoreofaModelthanaViewbutitdoeshandle
mostoftheViewsdisplaylogic.TheViewModelmayalsoexposemethodsforhelpingtomaintainthe
Viewsstate,updatethemodelbasedontheactionsonaViewandtriggereventsontheView.

Insummary,theViewModelsitsbehindourUIlayer.ItexposesdataneededbyaView(fromaModel)
andcanbeviewedasthesourceourViewsgotoforbothdataandactions.

KnockoutJSinterpretstheViewModelastherepresentationofdataandoperationsthatcanbe
performedonaUI.ThisisnttheUIitselfnorthedatamodelthatpersists,butratheralayerthatcan
alsoholdtheyettobesaveddataauserisworkingwith.KnockoutsViewModelsareimplemented
JavaScriptobjectswithnoknowledgeofHTMLmarkup.Thisabstractapproachtotheirimplementation
allowsthemtostaysimple,meaningmorecomplexbehaviorcanbemoreeasilymanagedontopas
needed.

ApartialKnockoutJSViewModelforourTodoapplicationcouldthuslookasfollows:

1 //ourmainViewModel
2 varViewModel=function(todos){
3 varself=this;
4
5 //maparrayofpassedintodostoanobservableArrayofTodoobjects
6 self.todos=ko.observableArray(
7 ko.utils.arrayMap(todos,function(todo){
8 returnnewTodo(todo.content,todo.done);
9 }));
10
11 //storethenewtodovaluebeingentered
12 self.current=ko.observable();
13
14 //addanewtodo,whenenterkeyispressed
15 self.add=function(data,event){
16 varnewTodo,current=self.current().trim();
17 if(current){
18 newTodo=newTodo(current);
19 self.todos.push(newTodo);
20 self.current("");
21 }
22 };
23
24 //removeasingletodo
25 self.remove=function(todo){
26 self.todos.remove(todo);
27 };
28
29 //removeallcompletedtodos
30 self.removeCompleted=function(){
31 self.todos.remove(function(todo){
32 returntodo.done();
33 });
34 };
35
36 //writeablecomputedobservabletohandlemarkingallcomplete/incomplete
37 self.allCompleted=ko.computed({
38
39 //alwaysreturntrue/falsebasedonthedoneflagofalltodos

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 105/188
26/04/2015 LearningJavaScriptDesignPatterns
40 read:function(){
41 return!self.remainingCount();
42 },
43
44 //setalltodostothewrittenvalue(true/false)
45 write:function(newValue){
46 ko.utils.arrayForEach(self.todos(),function(todo){
47 //setevenifvalueisthesame,assubscribersarenotnotifiedint
48 todo.done(newValue);
49 });
50 }
51 });
52
53 //editanitem
54 self.editItem=function(item){
55 item.editing(true);
56 };
57 ..

Abovewearebasicallyprovidingthemethodsneededtoadd,editorremoveitemsaswellasthelogic
tomarkallremainingitemsashavingbeencompletedNote:Theonlyrealdifferenceworthnotingfrom
previousexamplesinourViewModelareobservablearrays.InKnockoutJS,ifwewishtodetectand
respondtochangesonasingleobject,wewoulduse observables .Ifhoweverwewishtodetectand
respondtochangesofacollectionofthings,wecanusean observableArray instead.Asimplerexample
ofhowtouseobservablesarraysmaylookasfollows:

1 //Defineaninitiallyanemptyarray
2 varmyObservableArray=ko.observableArray();
3
4 //Addavaluetothearrayandnotifyourobservers
5 myObservableArray.push('Anewtodoitem');

Note:ThecompleteKnockout.jsTodoapplicationwereviewedabovecanbegrabbedfromTodoMVCif
interested.

Recap:TheViewandtheViewModel
ViewsandViewModelscommunicateusingdatabindingsandevents.Aswesawinourinitial
ViewModelexample,theViewModeldoesntjustexposeModelattributesbutalsoaccesstoother
methodsandfeaturessuchasvalidation.

OurViewshandletheirownuserinterfaceevents,mappingthemtotheViewModelasnecessary.
ModelsandattributesontheViewModelaresynchronizedandupdatedviatwowaydatabinding.

Triggers(datatriggers)alsoallowustofurtherreacttochangesinthestateofourModelattributes.

Recap:TheViewModelandtheModel
WhilstitmayappeartheViewModeliscompletelyresponsiblefortheModelinMVVM,therearesome
subtletieswiththisrelationshipworthnoting.TheViewModelcanexposeaModelorModelattributes
forthepurposesofdatabindingandcanalsocontaininterfacesforfetchingandmanipulating
propertiesexposedintheview.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 106/188
26/04/2015 LearningJavaScriptDesignPatterns

ProsandCons
WenowhopefullyhaveabetterappreciationforwhatMVVMisandhowitworks.Letsnowreview
theadvantagesanddisadvantagesofemployingthepattern:

Advantages
MVVMFacilitateseasierparalleldevelopmentofaUIandthebuildingblocksthatpowerit
AbstractstheViewandthusreducesthequantityofbusinesslogic(orglue)requiredinthe
codebehindit
TheViewModelcanbeeasiertounittestthaneventdrivencode
TheViewModel(beingmoreModelthanView)canbetestedwithoutconcernsofUI
automationandinteraction

Disadvantages
ForsimplerUIs,MVVMcanbeoverkill
Whilstdatabindingscanbedeclarativeandnicetoworkwith,theycanbehardertodebug
thanimperativecodewherewesimplysetbreakpoints
Databindingsinnontrivialapplicationscancreatealotofbookkeeping.Wealsodontwant
toendupinasituationwherebindingsareheavierthantheobjectsbeingboundto
Inlargerapplications,itcanbemoredifficulttodesigntheViewModelupfronttogetthe
necessaryamountofgeneralization

MVVMWithLooserDataBindings
ItsnotuncommonforJavaScriptdevelopersfromanMVCorMVPbackgroundtoreviewMVVMand
complainaboutitstrueseparationofconcerns.Namely,thequantityofinlinedatabindingsmaintained
intheHTMLmarkupofaView.

ImustadmitthatwhenIfirstreviewedimplementationsofMVVM(e.gKnockoutJS,Knockback),Iwas
surprisedthatanydeveloperwouldwanttoreturntothedaysofoldwherewemixedlogic(JavaScript)
withourmarkupandfounditquicklyunmaintainable.TherealityhoweveristhatMVVMdoesthisfor
anumberofgoodreasons(whichwevecovered),includingfacilitatingdesignerstomoreeasilybindto
logicfromtheirmarkup.

Forthepuristsamongus,youllbehappytoknowthatwecannowalsogreatlyreducehowreliantwe
areondatabindingsthankstoafeatureknownascustombindingproviders,introducedinKnockoutJS
1.3andavailableinallversionssince.

KnockoutJSbydefaulthasadatabindingproviderwhichsearchesforanyelementswith databind
attributesonthemsuchasinthebelowexample.

1 <inputid="newtodo"type="text"databind="value:current,valueUpdate:'afterkeydown

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 107/188
26/04/2015 LearningJavaScriptDesignPatterns

Whentheproviderlocatesanelementwiththisattribute,itparsesitandturnsitintoabindingobject
usingthecurrentdatacontext.ThisisthewayKnockoutJShasalwaysworked,allowingusto
declarativelyaddbindingstoelementswhichKnockoutJSbindstothedataatthatlayer.

OncewestartbuildingViewsthatarenolongertrivial,wemayendupwithalargenumberofelements
andattributeswhosebindingsinmarkupcanbecomedifficulttomanage.Withcustombinding
providershowever,thisisnolongeraproblem.

Abindingproviderisprimarilyinterestedintwothings:

WhengivenaDOMnode,doesitcontainanydatabindings?
Ifthenodepassedthisfirstquestion,whatdoesthebindingobjectlooklikeinthecurrent
datacontext?

Bindingprovidersimplementtwofunctions:

nodeHasBindings :thistakesinaDOMnodewhichdoesntnecessarilyhavetobeanelement
getBindings :returnsanobjectrepresentingthebindingsasappliedtothecurrentdatacontext

Askeletonbindingprovidermightthuslookasfollows:

?
1 varourBindingProvider={
2 nodeHasBindings:function(node){
3 //returnstrue/false
4 },
5
6 getBindings:function(node,bindingContext){
7 //returnsabindingobject
8 }
9 };

Beforewegettofleshingoutthisprovider,letsbrieflydiscusslogicindatabindattributes.

IfwhenusingKnockoutsMVVMwefindyourselfdissatisfiedwiththeideaofapplicationlogicbeing
overlytiedintoyourView,wecanchangethis.WecouldimplementsomethingalittlelikeCSSclasses
toassignbindingsbynametoelements.RyanNiemeyer(ofknockmeout.net)haspreviouslysuggested
using dataclass forthistoavoidconfusingpresentationclasseswithdataclasses,soletsgetour
nodeHasBindings functionsupportingthis:

1 //doesanelementhaveanybindings?
2 functionnodeHasBindings(node){
3 returnnode.getAttribute?node.getAttribute("dataclass"):false;
4 };

Next,weneedasensible getBindings() function.AswerestickingwiththeideaofCSSclasses,whynot


alsoconsidersupportingspaceseparatedclassestoallowustosharebindingspecsbetweendifferent
elements?

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 108/188
26/04/2015 LearningJavaScriptDesignPatterns

Letsfirstreviewwhatourbindingswilllooklike.Wecreateanobjecttoholdthemwhereourproperty
namesneedtomatchthekeyswewishtouseinourdataclasses.

Note:ThereisntagreatdealofworkrequiredtoconvertaKnockoutJSapplicationfromusing
traditionaldatabindingsovertounobtrusivebindingswithcustombindingproviders.Wesimplypull
ourallofourdatabindattributes,replacethemwithdataclassattributesandplaceourbindingsina
bindingobjectasperbelow:

1 varviewModel=newViewModel(todos||[]),
2 bindings={
3
4 newTodo:{
5 value:viewModel.current,
6 valueUpdate:"afterkeydown",
7 enterKey:viewModel.add
8 },
9
10 taskTooltip:{
11 visible:viewModel.showTooltip
12 },
13 checkAllContainer:{
14 visible:viewModel.todos().length
15 },
16 checkAll:{
17 checked:viewModel.allCompleted
18 },
19
20 todos:{
21 foreach:viewModel.todos
22 },
23 todoListItem:function(){
24 return{
25 css:{
26 editing:this.editing
27 }
28 };
29 },
30 todoListItemWrapper:function(){
31 return{
32 css:{
33 done:this.done
34 }
35 };
36 },
37 todoCheckBox:function(){
38 return{
39 checked:this.done
40 };
41 },
42 todoContent:function(){
43 return{
44 text:this.content,
45 event:{
46 dblclick:this.edit
47 }
48 };
49 },
50 todoDestroy:function(){
51 return{
52 click:viewModel.remove
53 };
54 },
55
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 109/188
26/04/2015 LearningJavaScriptDesignPatterns
56 todoEdit:function(){
57 return{
58 value:this.content,
59 valueUpdate:"afterkeydown",
60 enterKey:this.stopEditing,
61 event:{
62 blur:this.stopEditing
63 }
64 };
65 },
66
67 todoCount:{
68 visible:viewModel.remainingCount
69 },
70 remainingCount:{
71 text:viewModel.remainingCount
72 },
73 remainingCountWord:function(){
74 return{
75 text:viewModel.getLabel(viewModel.remainingCount)
76 };
77 },
78 todoClear:{
79 visible:viewModel.completedCount
80 },
81 todoClearAll:{
82 click:viewModel.removeCompleted
83 },
84 completedCount:{
85 text:viewModel.completedCount
86 },
87 completedCountWord:function(){
88 return{
89 text:viewModel.getLabel(viewModel.completedCount)
90 };
91 },
92 todoInstructions:{
93 visible:viewModel.todos().length
94 }
95 };
96
97 ....

Therearehowevertwolinesmissingfromtheabovesnippetwestillneedour getBindings function,


whichwillloopthrougheachofthekeysinourdataclassattributesandbuilduptheresultingobject
fromeachofthem.Ifwedetectthatthebindingobjectisafunction,wecallitwithourcurrentdata
usingthecontext this .Ourcompletecustombindingproviderwouldlookasfollows:

?
1 //WecannowcreateabindingProviderthatuses
2 //somethingdifferentthandatabindattributes
3 ko.customBindingProvider=function(bindingObject){
4 this.bindingObject=bindingObject;
5
6 //determineifanelementhasanybindings
7 this.nodeHasBindings=function(node){
8 returnnode.getAttribute?node.getAttribute("dataclass"):false
9 };
10 };
11
12 //returnthebindingsgivenanodeandthebindingContext
13 this.getBindings=function(node,bindingContext){
14
15 varresult={},

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 110/188
26/04/2015 LearningJavaScriptDesignPatterns
16 classes=node.getAttribute("dataclass");
17
18 if(classes){
19 classes=classes.split("");
20
21 //evaluateeachclass,buildasingleobjecttoreturn
22 for(vari=0,j=classes.length;i<j;i++){
23
24 varbindingAccessor=this.bindingObject[classes[i]];
25 if(bindingAccessor){
26 varbinding=typeofbindingAccessor==="function"?bindingAcces
27 ko.utils.extend(result,binding);
28 }
29
30 }
31 }
32
33 returnresult;
34 };
35 };

Thus,thefinalfewlinesofour bindings objectcanbedefinedasfollows:

1 //setko'scurrentbindingProviderequaltoournewbindingprovider
2 ko.bindingProvider.instance=newko.customBindingProvider(bindings);
3
4 //bindanewinstanceofourViewModeltothepage
5 ko.applyBindings(viewModel);
6
7 })();

Whatweredoinghereiseffectivelydefiningconstructorforourbindinghandlerwhichacceptsan
object(bindings)whichweusetolookupourbindings.Wecouldthenrewritethemarkupforour
applicationViewusingdataclassesasfollows:

?
1 <divid="createtodo">
2 <inputid="newtodo"dataclass="newTodo"placeholder="Whatneedsto
3 <spanclass="uitooltiptop"dataclass="taskTooltip"style="display:
4 </div>
5 <divid="todos">
6 <divdataclass="checkAllContainer">
7 <inputid="checkall"class="check"type="checkbox"dataclass
8 <labelfor="checkall">Markallascomplete</label>
9 </div>
10 <ulid="todolist"dataclass="todos">
11 <lidataclass="todoListItem">
12 <divclass="todo"dataclass="todoListItemWrapper">
13 <divclass="display">
14 <inputclass="check"type="checkbox"dataclass
15 <divclass="todocontent"dataclass="todoContent"
16 <spanclass="tododestroy"dataclass="todoDestroy"
17 </div>
18 <divclass="edit'>
19 <inputclass="todoinput"dataclass="todoEdit'/>
20 </div>
21 </div>
22 </li>
23 </ul>
24 </div>

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 111/188
26/04/2015 LearningJavaScriptDesignPatterns

NeilKerkinhasputtogetheracompleteTodoMVCdemoappusingtheabove,whichcanbeaccessed
andplayedaroundwithhere.

Whilstitmaylooklikequitealotofworkintheexplanationabove,nowthatwehaveageneric
getBindings methodwritten,itsalotmoretrivialtosimplyreuseitandusedataclassesratherthan
strictdatabindingsforwritingourKnockoutJSapplicationsinstead.Thenetresultishopefullycleaner
markupwithourdatabindingsbeingshiftedfromtheViewtoabindingsobjectinstead.

MVCVs.MVPVs.MVVM
BothMVPandMVVMarederivativesofMVC.Thekeydifferencebetweenitanditsderivativesisthe
dependencyeachlayerhasonotherlayersaswellashowtightlyboundtheyaretoeachother.

InMVC,theViewsitsontopofourarchitecturewiththecontrollerbesideit.Modelssitbelowthe
controllerandsoourViewsknowaboutourcontrollersandcontrollersknowaboutModels.Here,our
ViewshavedirectaccesstoModels.ExposingthecompleteModeltotheViewhowevermayhave
securityandperformancecosts,dependingonthecomplexityofourapplication.MVVMattemptsto
avoidtheseissues.

InMVP,theroleofthecontrollerisreplacedwithaPresenter.Presenterssitatthesamelevelasviews,
listeningtoeventsfromboththeViewandmodelandmediatingtheactionsbetweenthem.Unlike
MVVM,thereisntamechanismforbindingViewstoViewModels,soweinsteadrelyoneachView
implementinganinterfaceallowingthePresentertointeractwiththeView.

MVVMconsequentlyallowsustocreateViewspecificsubsetsofaModelwhichcancontainstateand
logicinformation,avoidingtheneedtoexposetheentireModeltoaView.UnlikeMVPsPresenter,a
ViewModelisnotrequiredtoreferenceaView.TheViewcanbindtopropertiesontheViewModel
whichinturnexposedatacontainedinModelstotheView.Aswevementioned,theabstractionofthe
Viewmeansthereislesslogicrequiredinthecodebehindit.

OneofthedownsidestothishoweveristhatalevelofinterpretationisneededbetweentheViewModel
andtheViewandthiscanhaveperformancecosts.Thecomplexityofthisinterpretationcanalsovary
itcanbeassimpleascopyingdataorascomplexasmanipulatingthemtoaformwewouldlikethe
Viewtosee.MVCdoesnthavethisproblemasthewholeModelisreadilyavailableandsuch
manipulationcanbeavoided.

Backbone.jsVs.KnockoutJS
UnderstandingthesubtledifferencesbetweenMVC,MVPandMVVMareimportantbutdevelopers
ultimatelywillaskwhethertheyshouldconsiderusingKnockoutJSoverBackbonebasedinwhatweve
learned.Thefollowingnotesmaybeofhelphere:

Bothlibrariesaredesignedwithdifferentgoalsinmindanditsoftennotassimpleasjust
choosingMVCorMVVM

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 112/188
26/04/2015 LearningJavaScriptDesignPatterns

Ifdatabindingandtwowaycommunicationareyourmainconcerns,KnockoutJSis
definitelythewaytogo.PracticallyanyattributeorvaluestoredinDOMnodescanbe
mappedtoJavaScriptobjectswiththisapproach.

BackboneexcelswithitseaseofintegrationwithRESTfulservices,whilstKnockoutJSModels
aresimplyJavaScriptobjectsandcodeneededforupdatingtheModelmustbewrittenbythe
developer.

KnockoutJShasafocusonautomatingUIbindings,whichrequiressignificantlymore
verbosecustomcodeifattemptingtodothiswithBackbone.Thisisntaproblemwith
BackboneitselfperseasitpurposefullyattemptstostayoutoftheUI.Knockbackdoes
howeverattempttoassistwiththisproblem.

WithKnockoutJS,wecanbindourownfunctionstoViewModelobservables,whichare
executedanytimetheobservablechanges.Thisallowsusthesamelevelofflexibilityascan
befoundinBackbone

Backbonehasasolidroutingsolutionbuiltin,whilstKnockoutJSoffersnoroutingoptions
outofthebox.OnecanhowevereasilyfillthisbehaviorinifneededusingBenAlmansBBQ
pluginorastandaloneroutingsystemlikeMillerMedeirossexcellentCrossroads.

Toconclude,IpersonallyfindKnockoutJSmoresuitableforsmallerapplicationswhilstBackbones
featuresetreallyshineswhenbuildinganythingnontrivial.Thatsaid,manydevelopershaveusedboth
frameworkstowriteapplicationsofvaryingcomplexityandIrecommendtryingoutbothatasmaller
scalebeforemakingadecisiononwhichmightworkbestforyourproject.

ForfurtherreadingaboutMVVMorKnockout,Irecommendthefollowingarticles:
TheAdvantagesOfMVVM
SO:WhataretheproblemswithMVVM?
MVVMExplained
HowdoesMVVMcomparetoMVC?
CustombindingsinKnockoutJS
ExploringKnockoutwithTodoMVC

ModernModularJavaScript
DesignPatterns
TheImportanceOfDecouplingApplications
IntheworldofscalableJavaScript,whenwesayanapplicationismodular,weoftenmeanits
composedofasetofhighlydecoupled,distinctpiecesoffunctionalitystoredinmodules.Loose
couplingfacilitateseasiermaintainabilityofappsbyremovingdependencieswherepossible.Whenthisis
implementedefficiently,itsquiteeasytoseehowchangestoonepartofasystemmayaffectanother.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 113/188
26/04/2015 LearningJavaScriptDesignPatterns

Unlikesomemoretraditionalprogramminglanguageshowever,thecurrentiterationofJavaScript
(ECMA262)doesntprovidedeveloperswiththemeanstoimportsuchmodulesofcodeinaclean,
organizedmanner.Itsoneoftheconcernswithspecificationsthathaventrequiredgreatthoughtuntil
morerecentyearswheretheneedformoreorganizedJavaScriptapplicationsbecameapparent.

Instead,developersatpresentarelefttofallbackonvariationsofthemoduleorobjectliteralpatterns,
whichwecoveredearlierinthebook.Withmanyofthese,modulescriptsarestrungtogetherinthe
DOMwithnamespacesbeingdescribedbyasingleglobalobjectwhereitsstillpossibletoincurnaming
collisionsinourarchitecture.Theresalsonocleanwaytohandledependencymanagementwithout
somemanualeffortorthirdpartytools.

WhilstnativesolutionstotheseproblemswillbearrivinginESHarmony(likelytobethenextversion
ofJavaScript),thegoodnewsisthatwritingmodularJavaScripthasneverbeeneasierandwecanstart
doingittoday.

Inthissection,weregoingtolookatthreeformatsforwritingmodularJavaScript:AMD,CommonJS
andproposalsforthenextversionofJavaScript,Harmony.

ANoteOnScriptLoaders

ItsdifficulttodiscussAMDandCommonJSmoduleswithouttalkingabouttheelephantintheroom
scriptloaders.Atthetimeofwritingthisbook,scriptloadingisameanstoagoal,thatgoalbeing
modularJavaScriptthatcanbeusedinapplicationstodayforthis,useofacompatiblescriptloaderis
unfortunatelynecessary.Inordertogetthemostoutofthissection,Irecommendgainingabasic
understandingofhowpopularscriptloadingtoolsworksotheexplanationsofmoduleformatsmake
senseincontext.

ThereareanumberofgreatloadersforhandlingmoduleloadingintheAMDandCommonJSformats,
butmypersonalpreferencesareRequireJSandcurl.js.Completetutorialsonthesetoolsareoutsidethe
scopeofthisbook,butIcanrecommendreadingJohnHannsarticleaboutcurl.jsandJamesBurkes
RequireJSAPIdocumentationformore.

Fromaproductionperspective,theuseofoptimizationtools(liketheRequireJSoptimizer)to
concatenatescriptsisrecommendedfordeploymentwhenworkingwithsuchmodules.Interestingly,
withtheAlmondAMDshim,RequireJSdoesntneedtoberolledinthedeployedsiteandwhatone
mightconsiderascriptloadercanbeeasilyshiftedoutsideofdevelopment.

Thatsaid,JamesBurkewouldprobablysaythatbeingabletodynamicallyloadscriptsafterpageload
stillhasitsusecasesandRequireJScanassistwiththistoo.Withthesenotesinmind,letsgetstarted.

AMD
AFormatForWritingModularJavaScriptInTheBrowser
TheoverallgoalfortheAMD(AsynchronousModuleDefinition)formatistoprovideasolutionfor

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 114/188
26/04/2015 LearningJavaScriptDesignPatterns

modularJavaScriptthatdeveloperscanusetoday.ItwasbornoutofDojosrealworldexperienceusing
XHR+evalandproponentsofthisformatwantedtoavoidanyfuturesolutionssufferingfromthe
weaknessesofthoseinthepast.

TheAMDmoduleformatitselfisaproposalfordefiningmoduleswhereboththemoduleand
dependenciescanbeasynchronouslyloaded.Ithasanumberofdistinctadvantagesincludingbeing
bothasynchronousandhighlyflexiblebynaturewhichremovesthetightcouplingonemight
commonlyfindbetweencodeandmoduleidentity.Manydevelopersenjoyusingitandonecould
consideritareliablesteppingstonetowardsthemodulesystemproposedforESHarmony.

AMDbeganasadraftspecificationforamoduleformatontheCommonJSlistbutasitwasntableto
reachfullconsensus,furtherdevelopmentoftheformatmovedtotheamdjsgroup.

TodayitsembracedbyprojectsincludingDojo,MooTools,FirebugandevenjQuery.Althoughtheterm
CommonJSAMDformathasbeenseeninthewildonoccasion,itsbesttorefertoitasjustAMDorAsync
ModulesupportasnotallparticipantsontheCommonJSlistwishedtopursueit.

Note:TherewasatimewhentheproposalwasreferredtoasModulesTransport/C,howeverasthespec
wasntgearedtowardstransportingexistingCommonJSmodules,butratherfordefiningmodulesit
mademoresensetooptfortheAMDnamingconvention.

GettingStartedWithModules
ThefirsttwoconceptsworthnotingaboutAMDaretheideaofa define methodforfacilitatingmodule
definitionanda require methodforhandlingdependencyloading.defineisusedtodefinenamedor
unnamedmodulesbasedusingthefollowingsignature:

1 define(
2 module_id/*optional*/,
3 [dependencies]/*optional*/,
4 definitionfunction/*functionforinstantiatingthemoduleorobject*/
5 );

Aswecantellbytheinlinecomments,the module_id isanoptionalargumentwhichistypicallyonly


requiredwhennonAMDconcatenationtoolsarebeingused(theremaybesomeotheredgecaseswhere
itsusefultoo).Whenthisargumentisleftout,werefertothemoduleasanonymous.

Whenworkingwithanonymousmodules,theideaofamodulesidentityisDRY,makingittrivialto
avoidduplicationoffilenamesandcode.Becausethecodeismoreportable,itcanbeeasilymovedto
otherlocations(oraroundthefilesystem)withoutneedingtoalterthecodeitselforchangeitsmodule
ID.Considerthe module_id similartotheconceptoffolderpaths.

Note:DeveloperscanrunthissamecodeonmultipleenvironmentsjustbyusinganAMDoptimizer
thatworkswithaCommonJSenvironmentsuchasr.js.

Backtothe define signature,thedependenciesargumentrepresentsanarrayofdependencieswhichare


requiredbythemodulewearedefiningandthethirdargument(definitionfunctionorfactory
function)isafunctionthatsexecutedtoinstantiateourmodule.Abarebonemodulecouldbedefined
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 115/188
26/04/2015 LearningJavaScriptDesignPatterns

asfollows:

UnderstandingAMD:define()

?
1 //Amodule_id(myModule)isusedherefordemonstrationpurposesonly
2 define("myModule",
3
4 ["foo","bar"],
5
6 //moduledefinitionfunction
7 //dependencies(fooandbar)aremappedtofunctionparameters
8 function(foo,bar){
9 //returnavaluethatdefinesthemoduleexport
10 //(i.ethefunctionalitywewanttoexposeforconsumption)
11
12 //createyourmodulehere
13 varmyModule={
14 doStuff:function(){
15 console.log("Yay!Stuff");
16 }
17 };
18
19 returnmyModule;
20 });
21
22 //Analternativeversioncouldbe..
23 define("myModule",
24
25 ["math","graph"],
26
27 function(math,graph){
28
29 //Notethatthisisaslightlydifferentpattern
30 //WithAMD,it'spossibletodefinemodulesinafew
31 //differentwaysduetoit'sflexibilitywith
32 //certainaspectsofthesyntax
33 return{
34 plot:function(x,y){
35 returngraph.drawPie(math.randomGrid(x,y));
36 }
37 };
38 });

requireontheotherhandistypicallyusedtoloadcodeinatoplevelJavaScriptfileorwithinamodule
shouldwewishtodynamicallyfetchdependencies.Anexampleofitsusageis:

UnderstandingAMD:require()

1 //Consider"foo"and"bar"aretwoexternalmodules
2 //Inthisexample,the"exports"fromthetwomodules
3 //loadedarepassedasfunctionargumentstothe
4 //callback(fooandbar)sothattheycansimilarlybeaccessed
5
6 require(["foo","bar"],function(foo,bar){
7 //restofyourcodehere
8 foo.doSomething();
9 });

DynamicallyloadedDependencies

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 116/188
26/04/2015 LearningJavaScriptDesignPatterns
?
1 define(function(require){
2 varisReady=false,foobar;
3
4 //notetheinlinerequirewithinourmoduledefinition
5 require(["foo","bar"],function(foo,bar){
6 isReady=true;
7 foobar=foo()+bar();
8 });
9
10 //wecanstillreturnamodule
11 return{
12 isReady:isReady,
13 foobar:foobar
14 };
15 });

UnderstandingAMD:plugins

ThefollowingisanexampleofdefininganAMDcompatibleplugin:

?
1 //WithAMD,it'spossibletoloadinassetsofalmostanykind
2 //includingtextfilesandHTML.Thisenablesustohavetemplate
3 //dependencieswhichcanbeusedtoskincomponentseitheron
4 //pageloadordynamically.
5
6 define(["./templates","text!./template.md","css!./template.css"],
7
8 function(templates,template){
9 console.log(templates);
10 //dosomethingwithourtemplateshere
11 }
12
13 });

Note:Althoughcss!isincludedforloadingCSSdependenciesintheaboveexample,itsimportantto
rememberthatthisapproachhassomecaveatssuchasitnotbeingfullypossibletoestablishwhenthe
CSSisfullyloaded.Dependingonhowweapproachourbuildprocess,itmayalsoresultinCSSbeing
includedasadependencyintheoptimizedfile,souseCSSasaloadeddependencyinsuchcaseswith
caution.Ifinterestedindoingtheabove,wecanalsoexplore@VIISONsRequireJSCSSpluginfurther
here:https://github.com/VIISON/RequireCSS

LoadingAMDModulesUsingRequireJS

1 require(["app/myModule"],
2
3 function(myModule){
4 //startthemainmodulewhichinturn
5 //loadsothermodules
6 varmodule=newmyModule();
7 module.doStuff();
8 });

Thisexamplecouldsimplybelookedatas requirejs(["app/myModule"],function(){}) whichindicatesthe


loaderstoplevelglobalsarebeingused.Thisishowtokickofftoplevelloadingofmoduleswith
differentAMDloadershoweverwitha define() function,ifitspassedalocalrequireall require([])
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 117/188
26/04/2015 LearningJavaScriptDesignPatterns

examplesapplytobothtypesofloader(curl.jsandRequireJS).

LoadingAMDModulesUsingcurl.js

1 curl(["app/myModule.js"],
2
3 function(myModule){
4 //startthemainmodulewhichinturn
5 //loadsothermodules
6 varmodule=newmyModule();
7 module.doStuff();
8
9 });

ModulesWithDeferredDependencies

?
1 //ThiscouldbecompatiblewithjQuery'sDeferredimplementation,
2 //futures.js(slightlydifferentsyntax)oranyoneofanumber
3 //ofotherimplementations
4
5 define(["lib/Deferred"],function(Deferred){
6 vardefer=newDeferred();
7
8 require(["lib/templates/?index.html","lib/data/?stats"],
9 function(template,data){
10 defer.resolve({template:template,data:data});
11 }
12 );
13 returndefer.promise();
14 });

AMDModulesWithDojo
DefiningAMDcompatiblemodulesusingDojoisfairlystraightforward.Asperabove,defineany
moduledependenciesinanarrayasthefirstargumentandprovideacallback(factory)whichwill
executethemoduleoncethedependencieshavebeenloaded.e.g:

?
1 define(["dijit/Tooltip"],function(Tooltip){
2
3 //Ourdijittooltipisnowavailableforlocaluse
4 newTooltip(...);
5
6 });

Notetheanonymousnatureofthemodule,whichcannowbebothconsumedbyaDojoasynchronous
loader,RequireJSorthestandarddojo.require()moduleloader.

Therearesomeinterestinggotchaswithmodulereferencingthatareusefultoknowhere.Althoughthe
AMDadvocatedwayofreferencingmodulesdeclarestheminthedependencylistwithasetof
matchingarguments,thisisntsupportedbytheolderDojo1.6buildsystemitreallyonlyworksfor
AMDcompliantloaders.e.g:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 118/188
26/04/2015 LearningJavaScriptDesignPatterns
?

1 define(["dojo/cookie","dijit/Tooltip"],function(cookie,Tooltip){
2
3 varcookieValue=cookie("cookieName");
4 newTooltip(...);
5
6 });

Thishasmanyadvantagesovernestednamespacingasmodulesnolongerneedtodirectlyreference
completenamespaceseverytimeallwerequireisthedojo/cookiepathindependencies,whichonce
aliasedtoanargument,canbereferencedbythatvariable.Thisremovestheneedtorepeatedlytypeout
dojo.inourapplications.

ThefinalgotchatobeawareofisthatifwewishtocontinueusingtheolderDojobuildsystemorwish
tomigrateoldermodulestothisnewerAMDstyle,thefollowingmoreverboseversionenableseasier
migration.Noticethatdojoanddijitandreferencedasdependenciestoo:

?
1 define(["dojo","dijit',"dojo/cookie","dijit/Tooltip"],function(dojo,dijit){
2 varcookieValue=dojo.cookie("cookieName");
3 newdijit.Tooltip(...);
4 });

AMDModuleDesignPatterns(Dojo)
Asweveseeninprevioussections,designpatternscanbehighlyeffectiveinimprovinghowwe
approachstructuringsolutionstocommondevelopmentproblems.JohnHannhasgivensomeexcellent
presentationsaboutAMDmoduledesignpatternscoveringtheSingleton,Decorator,Mediatorand
othersandIhighlyrecommendcheckingouthisslidesifwegetachance.

AselectionofAMDdesignpatternscanbefoundbelow.

Decoratorpattern:

1 //mylib/UpdatableObservable:aDecoratorfordojo/store/Observable
2 define(["dojo","dojo/store/Observable"],function(dojo,Observable){
3 returnfunctionUpdatableObservable(store){
4
5 varobservable=dojo.isFunction(store.notify)?store:
6 newObservable(store);
7
8 observable.updated=function(object){
9 dojo.when(object,function(itemOrArray){
10 dojo.forEach([].concat(itemOrArray),this.notify,this);
11 });
12 };
13
14 returnobservable;
15 };
16 });
17
18
19 //Decoratorconsumer
20 //aconsumerformylib/UpdatableObservable
21

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 119/188
26/04/2015 LearningJavaScriptDesignPatterns
22 define(["mylib/UpdatableObservable"],function(makeUpdatable){
23 varobservable,
24 updatable,
25 someItem;
26
27 //maketheobservablestoreupdatable
28 updatable=makeUpdatable(observable);//`new`isoptional!
29
30 //wecanthencall.updated()lateronifwewishtopass
31 //ondatathathaschanged
32 //updatable.updated(updatedItem);
33 });

Adapterpattern

?
1 //"mylib/Array"adapts`each`functiontomimicjQuerys:
2 define(["dojo/_base/lang","dojo/_base/array"],function(lang,array){
3 returnlang.delegate(array,{
4 each:function(arr,lambda){
5 array.forEach(arr,function(item,i){
6 lambda.call(item,i,item);//likejQuery'seach
7 });
8 }
9 });
10 });
11
12 //Adapterconsumer
13 //"myapp/mymodule":
14 define(["mylib/Array"],function(array){
15 array.each(["uno","dos","tres"],function(i,esp){
16 //here,`this`==item
17 });
18 });

AMDModulesWithjQuery
UnlikeDojo,jQueryreallyonlycomeswithonefile,howevergiventhepluginbasednatureofthe
library,wecandemonstratehowstraightforwarditistodefineanAMDmodulethatusesitbelow.

1 define(["js/jquery.js","js/jquery.color.js","js/underscore.js"],
2
3 function($,colorPlugin,_){
4 //Herewe'vepassedinjQuery,thecolorpluginandUnderscore
5 //Noneofthesewillbeaccessibleintheglobalscope,butwe
6 //caneasilyreferencethembelow.
7
8 //Pseudorandomizeanarrayofcolors,selectingthefirst
9 //itemintheshuffledarray
10 varshuffleColor=_.first(_.shuffle("#666","#333","#111"]));
11
12 //Animatethebackgroundcolorofanyelementswiththeclass
13 //"item"onthepageusingtheshuffledcolor
14 $(".item").animate({"backgroundColor":shuffleColor});
15
16 //Whatwereturncanbeusedbyothermodules
17 return{};
18 });

Thereishoweversomethingmissingfromthisexampleanditstheconceptofregistration.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 120/188
26/04/2015 LearningJavaScriptDesignPatterns

RegisteringjQueryAsAnAsynccompatibleModule

OneofthekeyfeaturesthatlandedinjQuery1.7wassupportforregisteringjQueryasanasynchronous
module.Thereareanumberofcompatiblescriptloaders(includingRequireJSandcurl)whichare
capableofloadingmodulesusinganasynchronousmoduleformatandthismeansfewerhacksare
requiredtogetthingsworking.

IfadeveloperwantstouseAMDanddoesnotwanttheirjQueryversionleakingintotheglobalspace,
theyshouldcall noConflict intheirtoplevelmodulethatusesjQuery.Inaddition,sincemultiple
versionsofjQuerycanbeonapagetherearespecialconsiderationsthatanAMDloadermustaccount
for,andsojQueryonlyregisterswithAMDloadersthathaverecognizedtheseconcerns,whichare
indicatedbytheloaderspecifying define.amd.jQuery .RequireJSandcurlaretwoloadersthatdoso

ThenamedAMDprovidesasafetyblanketofbeingbothrobustandsafeformostusecases.

1 //Accountfortheexistenceofmorethanoneglobal
2 //instancesofjQueryinthedocument,caterfortesting
3 //.noConflict()
4
5 varjQuery=this.jQuery||"jQuery",
6 $=this.$||"$",
7 originaljQuery=jQuery,
8 original$=$;
9
10 define(["jquery"],function($){
11 $(".items").css("background","green");
12 returnfunction(){};
13 });

WhyIsAMDABetterChoiceForWritingModularJavaScript?

Providesaclearproposalforhowtoapproachdefiningflexiblemodules.
Significantlycleanerthanthepresentglobalnamespaceand <script> tagsolutionsmanyof
usrelyon.Theresacleanwaytodeclarestandalonemodulesanddependenciestheymay
have.
Moduledefinitionsareencapsulated,helpingustoavoidpollutionoftheglobalnamespace.
Arguablyworksbetterthansomealternativesolutions(e.g.CommonJS,whichwellbe
lookingatshortly).Itdoesnthaveissueswithcrossdomain,localordebugginganddoesnt
havearelianceonserversidetoolstobeused.MostAMDloaderssupportloadingmodules
inthebrowserwithoutabuildprocess.
Providesatransportapproachforincludingmultiplemodulesinasinglefile.Other
approacheslikeCommonJShaveyettoagreeonatransportformat.
Itspossibletolazyloadscriptsifthisisneeded.

Note:ManyoftheabovecouldbesaidaboutYUIsmoduleloadingstrategyaswell.

RelatedReading

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 121/188
26/04/2015 LearningJavaScriptDesignPatterns

TheRequireJSGuideToAMD

WhatsthefastestwaytoloadAMDmodules?

AMDvs.CommonJS,whatsthebetterformat?

AMDIsBetterForTheWebThanCommonJSModules

TheFutureIsModulesNotFrameworks

AMDNoLongerACommonJSSpecification

OnInventingJavaScriptModuleFormatsAndScriptLoaders

TheAMDMailingList

WhatScriptLoaders&FrameworksSupportAMD?

Inbrowser:

RequireJShttp://requirejs.org
curl.jshttp://github.com/unscriptable/curl
bdLoadhttp://bdframework.com/bdLoad
Yabblehttp://github.com/jbrantly/yabble
PINFhttp://github.com/pinf/loaderjs
(andmore)

Serverside:

RequireJShttp://requirejs.org
PINFhttp://github.com/pinf/loaderjs

AMDConclusions
HavingusedAMDforanumberofprojects,myconclusionsarethatitticksalotofthecheckboxes
developerscreatingseriousapplicationsmightdesirefromabettermoduleformat.Itavoidstheneedto
worryaboutglobals,supportsnamedmodules,doesntrequireservertransformationtofunctionandis
apleasuretousefordependencymanagement.

ItsalsoanexcellentadditionformodulardevelopmentusingBackbone.js,ember.jsoranynumberof
otherstructuralframeworksforkeepingapplicationsorganized.

AsAMDhasbeenheavilydiscussedforalmosttwoyearswithintheDojoandCommonJSworlds,we
knowitshadtimetomatureandevolve.Wealsoknowitsbeenbattletestedinthewildbyanumberof
largecompaniestobuildnontrivialapplications(IBM,BBCiPlayer)andso,ifitdidntwork,chances

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 122/188
26/04/2015 LearningJavaScriptDesignPatterns

aretheywouldhaveabandoneditbynow,buthavent.

Thatsaid,therearestillareaswhereAMDcouldbeimproved.Developerswhohaveusedtheformatfor
sometimemayfeeltheAMDboilerplate/wrappercodeisanannoyingoverhead.WhilstIsharethis
concern,therearetoolssuchasVolothatcanhelpworkaroundtheseissuesandIwouldarguethaton
thewhole,theproswithusingAMDfaroutweighthecons.

CommonJS
AModuleFormatOptimizedForTheServer
TheCommonJSmoduleproposalspecifiesasimpleAPIfordeclaringmodulesserversideandunlike
AMDattemptstocoverabroadersetofconcernssuchasio,filesystem,promisesandmore.

TheformatwasproposedbyCommonJSavolunteerworkinggroupwhichaimtodesign,prototype
andstandardizeJavaScriptAPIs.Todatetheyveattemptedtoratifystandardsforbothmodulesand
packages.

GettingStarted
Fromastructureperspective,aCommonJSmoduleisareusablepieceofJavaScriptwhichexports
specificobjectsmadeavailabletoanydependentcode.UnlikeAMD,therearetypicallynofunction
wrappersaroundsuchmodules(sowewontsee define hereforexample).

CommonJSmodulesbasicallycontaintwoprimaryparts:afreevariablenamed exports whichcontains


theobjectsamodulewishestomakeavailabletoothermodulesanda require functionthatmodules
canusetoimporttheexportsofothermodules.

UnderstandingCommonJS:require()andexports

1 //package/libisadependencywerequire
2 varlib=require("package/lib");
3
4 //behaviourforourmodule
5 functionfoo(){
6 lib.log("helloworld!");
7 }
8
9 //export(expose)footoothermodules
10 exports.foo=foo;

Basicconsumptionofexports

?
1 //definemorebehaviourwewouldliketoexpose
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 123/188
26/04/2015 LearningJavaScriptDesignPatterns
2 functionfoobar(){
3 this.foo=function(){
4 console.log("Hellofoo");
5 }
6
7 this.bar=function(){
8 console.log("Hellobar");
9 }
10 }
11
12 //exposefoobartoothermodules
13 exports.foobar=foobar;
14
15 //anapplicationconsuming"foobar"
16
17 //accessthemodulerelativetothepath
18 //wherebothusageandmodulefilesexist
19 //inthesamedirectory
20
21 varfoobar=require("./foobar").foobar,
22 test=newfoobar();
23
24 //Outputs:"Hellobar"
25 test.bar();

AMDequivalentOfTheFirstCommonJSExample

1 define(function(require){
2 varlib=require("package/lib");
3
4 //somebehaviourforourmodule
5 functionfoo(){
6 lib.log("helloworld!");
7 }
8
9 //export(expose)fooforothermodules
10 return{
11 foobar:foo
12 };
13 });

ThiscanbedoneasAMDsupportsasimplifiedCommonJSwrappingfeature.

ConsumingMultipleDependencies

app.js

?
1 varmodA=require("./foo");
2 varmodB=require("./bar");
3
4 exports.app=function(){
5 console.log("Imanapplication!");
6 }
7
8 exports.foo=function(){
9 returnmodA.helloWorld();
10 }

bar.js
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 124/188
26/04/2015 LearningJavaScriptDesignPatterns
?
1 exports.name="bar";

foo.js

1 require("./bar");
2 exports.helloWorld=function(){
3 return"HelloWorld!!"
4 }

WhatLoaders&FrameworksSupportCommonJS?

Inbrowser:

curl.jshttp://github.com/unscriptable/curl
SproutCore1.1http://sproutcore.com
PINFhttp://github.com/pinf/loaderjs

Serverside:

Nodehttp://nodejs.org
Narwhalhttps://github.com/tlrobinson/narwhal
Perseverehttp://www.persvr.org/
Wakandahttp://www.wakandasoft.com/

IsCommonJSSuitableForTheBrowser?

TherearedevelopersthatfeelCommonJSisbettersuitedtoserversidedevelopmentwhichisone
reasontherescurrentlyalevelofdisagreementoverwhichformatshouldandwillbeusedasthede
factostandardinthepreHarmonyagemovingforward.SomeoftheargumentsagainstCommonJS
includeanotethatmanyCommonJSAPIsaddressserverorientedfeatureswhichonewouldsimplynot
beabletoimplementatabrowserlevelinJavaScriptforexample,io,systemandjscouldbeconsidered
unimplementablebythenatureoftheirfunctionality.

Thatsaid,itsusefultoknowhowtostructureCommonJSmodulesregardlesssothatwecanbetter
appreciatehowtheyfitinwhendefiningmoduleswhichmaybeusedeverywhere.Moduleswhichhave
applicationsonboththeclientandserverincludevalidation,conversionandtemplatingengines.The
waysomedevelopersareapproachingchoosingwhichformattouseisoptingforCommonJSwhena
modulecanbeusedinaserversideenvironmentandusingAMDifthisisnotthecase.

AsAMDmodulesarecapableofusingpluginsandcandefinemoregranularthingslikeconstructors
andfunctionsthismakessense.CommonJSmodulesareonlyabletodefineobjectswhichcanbetedious
toworkwithifweretryingtoobtainconstructorsoutofthem.

Althoughitsbeyondthescopeofthissection,onemayhavealsonoticedthatthereweredifferenttypes
ofrequiremethodsmentionedwhendiscussingAMDandCommonJS.Theconcernwithasimilar

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 125/188
26/04/2015 LearningJavaScriptDesignPatterns

namingconventionisofcourseconfusionandthecommunityarecurrentlysplitonthemeritsofa
globalrequirefunction.JohnHannssuggestionhereisthatratherthancallingitrequire,whichwould
probablyfailtoachievethegoalofinformingusersaboutthedifferentbetweenaglobalandinner
require,itmaymakemoresensetorenamethegloballoadermethodsomethingelse(e.g.thenameof
thelibrary).Itsforthisreasonthataloaderlikecurl.jsuses curl() asopposedto require .

RelatedReading

DemystifyingCommonJSModules

JavaScriptGrowingUp

TheRequireJSNotesOnCommonJS

TakingBabyStepsWithNode.jsAndCommonJSCreatingCustomModules

AsynchronousCommonJSModulesfortheBrowser

TheCommonJSMailingList

AMD&&CommonJSCompeting,ButEquallyValid
Standards

BothAMDandCommonJSarevalidmoduleformatswithdifferentendgoals.

AMDadoptsabrowserfirstapproachtodevelopment,optingforasynchronousbehaviorand
simplifiedbackwardscompatibilitybutitdoesnthaveanyconceptofFileI/O.Itsupportsobjects,
functions,constructors,strings,JSONandmanyothertypesofmodules,runningnativelyinthe
browser.Itsincrediblyflexible.

CommonJSontheotherhandtakesaserverfirstapproach,assumingsynchronousbehavior,noglobal
baggageandattemptstocaterforthefuture(ontheserver).Whatwemeanbythisisthatbecause
CommonJSsupportsunwrappedmodules,itcanfeelalittlemoreclosetotheES.next/Harmony
specifications,freeingusofthe define() wrapperthatAMDenforces.CommonJSmoduleshowever
onlysupportobjectsasmodules.

UMD:AMDAndCommonJSCompatibleModulesForPlugins
Fordeveloperswishingtocreatemodulesthatcanworkinbothbrowserandserversideenvironments,
existingsolutionscouldbeconsideredlittlelacking.Tohelpalleviatethis,JamesBurke,Iandanumber
ofotherdeveloperscreatedUMD(UniversalModuleDefinition)https://github.com/umdjs/umd.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 126/188
26/04/2015 LearningJavaScriptDesignPatterns

UMDisanexperimentalmoduleformatthatallowsthedefinitionofmodulesthatworkinbothclient
andserverenvironmentswithallormostofthepopularscriptloadingtechniquesavailableatthetime
ofwriting.Althoughtheideaof(yet)anothermoduleformatmaybedaunting,wewillcoverUMD
brieflyforthesakeofthoroughness.

WeoriginallybegandefiningUMDbytakingalookatthesimplifiedCommonJSwrappersupportedin
theAMDspecification.FordeveloperswishingtowritemodulesasiftheywereCommonJSmodules,
thefollowingCommonJScompatibleformatcouldbeused:

BasicAMDHybridFormat

?
1 define(function(require,exports,module){
2
3 varshuffler=require("lib/shuffle");
4
5 exports.randomize=function(input){
6 returnshuffler.shuffle(input);
7 }
8 });

ItsimportanthowevertonotethatamoduleisreallyonlytreatedasaCommonJSmoduleifitdoesnt
containadependencyarrayandthedefinitionfunctioncontainsoneparameteratminimum.Thisalso
wontworkcorrectlyonsomedevices(e.gthePS3).Forfurtherinformationabouttheabovewrapper,
seehttp://requirejs.org/docs/api.html#cjsmodule.

Takingthisfurther,wewantedtoprovideanumberofdifferentpatternsthatnotjustworkedwith
AMDandCommonJS,butalsosolvedcommoncompatibilityproblemsdeveloperswishingtodevelop
suchmoduleshadwithotherenvironments.

OnesuchvariationwecanseebelowallowsustouseCommonJS,AMDorbrowserglobalstocreatea
module.

UsingCommonJS,AMDorbrowserglobalstocreateamodule

Defineamodule commonJsStrict ,whichdependsonanothermodulecalled b .Thenameofthemodule


isimpliedbythefilenameanditsbestpracticeforthefilenameandtheexportedglobaltohavethe
samename.

Ifthemodule b alsousesthesametypeofboilerplateinthebrowser,itwillcreateaglobal .b thatis


used.Ifwedontwishtosupportthebrowserglobalpatch,wecanremovethe root andthepassing
this asthefirstargumenttothetopfunction.

1 (function(root,factory){
2 if(typeofexports==='object'){
3 //CommonJS
4 factory(exports,require('b'));
5 }elseif(typeofdefine==='function'&&define.amd){
6 //AMD.Registerasananonymousmodule.
7 define(['exports','b'],factory);
8 }else{
9 //Browserglobals
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 127/188
26/04/2015 LearningJavaScriptDesignPatterns
10 factory((root.commonJsStrict={}),root.b);
11 }
12 }(this,function(exports,b){
13 //usebinsomefashion.
14
15 //attachpropertiestotheexportsobjecttodefine
16 //theexportedmoduleproperties.
17 exports.action=function(){};
18 }));

TheUMDrepositorycontainsvariationscoveringmodulesthatworkoptimallyinthebrowser,those
bestforprovidingexports,thoseoptimalforCommonJSruntimesandeventhosethatworkbestfor
definingjQueryplugins,whichwewilllookatnext.

jQuerypluginsthatfunctioninallenvironments

UMDprovidestwopatternsforworkingwithjQuerypluginsonewhichdefinespluginsthatwork
wellwithAMDandbrowserglobalsandanotherwhichcanalsoworkinCommonJSenvironments.
jQueryisnotlikelytobeusedinmostCommonJSenvironmentssokeepthisinmindunlesswere
workingwithanenvironmentwhichdoesplaywellwithit.

Wewillnowdefineaplugincomposedofacoreandanextensiontothatcore.Thecorepluginisloaded
intoa $.core namespace,whichcanthenbeeasilyextendedusingpluginextensionsviathe
namespacingpattern.Pluginsloadedviascripttagsautomaticallypopulatea plugin namespaceunder
core (i.e. $.core.plugin.methodName() ).

Thepatterncanbequitenicetoworkwithbecausepluginextensionscanaccesspropertiesandmethods
definedinthebaseor,withalittletweaking,overridedefaultbehaviorsothatitcanbeextendedtodo
more.Aloaderisalsonotrequiredtomakeanyofthisfullyfunctional.

Formoredetailsofwhatisbeingdone,pleaseseetheinlinecommentsinthecodesamplesbelow.

usage.html

1 <scripttype="text/javascript"src="jquery1.7.2.min.js"></script>
2 <scripttype="text/javascript"src="pluginCore.js"></script>
3 <scripttype="text/javascript"src="pluginExtension.js"></script>
4
5 <scripttype="text/javascript">
6
7 $(function(){
8
9 //Ourplugin"core"isexposedunderacorenamespacein
10 //thisexample,whichwefirstcache
11 varcore=$.core;
12
13 //Thenuseusesomeofthebuiltincorefunctionalityto
14 //highlightalldivsinthepageyellow
15 core.highlightAll();
16
17 //Accesstheplugins(extensions)loadedintothe"plugin"
18 //namespaceofourcoremodule:
19
20 //Setthefirstdivinthepagetohaveagreenbackground.
21 core.plugin.setGreen("div:first");

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 128/188
26/04/2015 LearningJavaScriptDesignPatterns
22 //Herewe'remakinguseofthecore's"highlight"method
23 //underthehoodfromapluginloadedinafterit
24
25 //Setthelastdivtothe"errorColor"propertydefinedin
26 //ourcoremodule/plugin.Ifwereviewthecodefurtherdown,
27 //wecanseehoweasyitistoconsumepropertiesandmethods
28 //betweenthecoreandotherplugins
29 core.plugin.setRed("div:last");
30 });
31
32 </script>

pluginCore.js

?
1 //Module/Plugincore
2 //Note:thewrappercodeweseearoundthemoduleiswhatenables
3 //ustosupportmultiplemoduleformatsandspecificationsby
4 //mappingtheargumentsdefinedtowhataspecificformatexpects
5 //tobepresent.Ouractualmodulefunctionalityisdefinedlower
6 //down,whereanamedmoduleandexportsaredemonstrated.
7 //
8 //Notethatdependenciescanjustaseasilybedeclaredifrequired
9 //andshouldworkasdemonstratedearlierwiththeAMDmoduleexamples.
10
11 (function(name,definition){
12 vartheModule=definition(),
13 //thisisconsidered"safe":
14 hasDefine=typeofdefine==="function"&&define.amd,
15 //hasDefine=typeofdefine==="function",
16 hasExports=typeofmodule!=="undefined"&&module.exports;
17
18 if(hasDefine){//AMDModule
19 define(theModule);
20 }elseif(hasExports){//Node.jsModule
21 module.exports=theModule;
22 }else{//Assigntocommonnamespacesorsimplytheglobalobject(window)
23 (this.jQuery||this.ender||this.$||this)[name]=theModule;
24 }
25 })("core",function(){
26 varmodule=this;
27 module.plugins=[];
28 module.highlightColor="yellow";
29 module.errorColor="red";
30
31 //definethecoremodulehereandreturnthepublicAPI
32
33 //ThisisthehighlightmethodusedbythecorehighlightAll()
34 //methodandallofthepluginshighlightingelementsdifferent
35 //colors
36 module.highlight=function(el,strColor){
37 if(this.jQuery){
38 jQuery(el).css("background",strColor);
39 }
40 }
41 return{
42 highlightAll:function(){
43 module.highlight("div",module.highlightColor);
44 }
45 };
46
47 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 129/188
26/04/2015 LearningJavaScriptDesignPatterns

pluginExtension.js

?
1 //Extensiontomodulecore
2
3 (function(name,definition){
4 vartheModule=definition(),
5 hasDefine=typeofdefine==="function",
6 hasExports=typeofmodule!=="undefined"&&module.exports;
7
8 if(hasDefine){//AMDModule
9 define(theModule);
10 }elseif(hasExports){//Node.jsModule
11 module.exports=theModule;
12 }else{
13
14 //Assigntocommonnamespacesorsimplytheglobalobject(window)
15 //accountforforflatfile/globalmoduleextensions
16 varobj=null,
17 namespaces,
18 scope;
19
20 obj=null;
21 namespaces=name.split(".");
22 scope=(this.jQuery||this.ender||this.$||this);
23
24 for(vari=0;i<namespaces.length;i++){
25 varpackageName=namespaces[i];
26 if(obj&&i==namespaces.length1){
27 obj[packageName]=theModule;
28 }elseif(typeofscope[packageName]==="undefined"){
29 scope[packageName]={};
30 }
31 obj=scope[packageName];
32 }
33
34 }
35 })("core.plugin",function(){
36
37 //DefineourmodulehereandreturnthepublicAPI.
38 //Thiscodecouldbeeasilyadaptedwiththecoreto
39 //allowformethodsthatoverwriteandextendcorefunctionality
40 //inordertoexpandthehighlightmethodtodomoreifwewish.
41 return{
42 setGreen:function(el){
43 highlight(el,"green");
44 },
45 setRed:function(el){
46 highlight(el,errorColor);
47 }
48 };
49
50 });

UMDdoesntaimtoreplaceAMDnorCommonJSbutmerelyofferssomesupplementalassistancefor
developerswishingtogettheircodeworkinginmoreenvironmentstoday.Forfurtherinformationorto
contributesuggestionstowardsthisexperimentalformat,seehttps://github.com/umdjs/umd.

FurtherReading

UsingAMDLoaderstoWriteandManageModularJavaScript,JohnHann
DemystifyingCommonJSModules,AlexYoung

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 130/188
26/04/2015 LearningJavaScriptDesignPatterns

AMDModulePatterns:Singleton,JohnHann
RunAnywhereJavaScriptModulesBoilerplateCode,KrisZyp
StandardsAndProposalsforJavaScriptModulesAndjQuery,JamesBurke

ESHarmony
ModulesOfTheFuture
TC39,thestandardsbodychargedwithdefiningthesyntaxandsemanticsofECMAScriptanditsfuture
iterationsiscomposedofanumberofveryintelligentdevelopers.Someofthesedevelopers(suchas
AlexRussell)havebeenkeepingacloseeyeontheevolutionofJavaScriptusageforlargescale
developmentoverthepastfewyearsandareacutelyawareoftheneedforbetterlanguagefeaturesfor
writingmoremodularJS.

Forthisreason,therearecurrentlyproposalsforanumberofexcitingadditionstothelanguage
includingflexiblemodulesthatcanworkonboththeclientandserver,amoduleloaderandmore.In
thissection,wellexplorecodesamplesusingthesyntaxproposedformodulesinES.nextsowecanget
atasteofwhatstocome.

Note:AlthoughHarmonyisstillintheproposalphases,wecanalreadytryout(partial)featuresof
ES.nextthataddressnativesupportforwritingmodularJavaScriptthankstoGooglesTraceurcompiler.
TogetupandrunningwithTraceurinunderaminute,readthisgettingstartedguide.Theresalsoa
JSConfpresentationaboutitthatsworthlookingatifinterestedinlearningmoreabouttheproject.

ModulesWithImportsAndExports
HavingreadthroughthesectionsonAMDandCommonJSmodulesyoumaybefamiliarwiththe
conceptofmoduledependencies(imports)andmoduleexports(or,thepublicAPI/variablesweallow
othermodulestoconsume).InES.next,theseconceptshavebeenproposedinaslightlymoresuccinct
mannerwithdependenciesbeingspecifiedusingan import keyword. export isntgreatlydifferentto
whatwemightexpectandmanydeveloperswilllookatthecodesampleslowerdownandinstantly
grabthem.

importdeclarationsbindamodulesexportsaslocalvariablesandmayberenamedtoavoid
namecollisions/conflicts.
exportdeclarationsdeclarethatalocalbindingofamoduleisexternallyvisiblesuchthat
othermodulesmayreadtheexportsbutcantmodifythem.Interestingly,modulesmay
exportchildmodulesbutcantexportmodulesthathavebeendefinedelsewhere.Wecan
alsorenameexportssotheirexternalnamediffersfromtheirlocalnames.

?
1 modulestaff{
2 //specify(public)exportsthatcanbeconsumedby
3 //othermodules
4 exportvarbaker={
5 bake:function(item){

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 131/188
26/04/2015 LearningJavaScriptDesignPatterns

6 console.log("Woo!Ijustbaked"+item);
7 }
8 }
9 }
10
11 moduleskills{
12 exportvarspecialty="baking";
13 exportvarexperience="5years";
14 }
15
16 modulecakeFactory{
17
18 //specifydependencies
19 importbakerfromstaff;
20
21 //importeverythingwithwildcards
22 import*fromskills;
23
24 exportvaroven={
25 makeCupcake:function(toppings){
26 baker.bake("cupcake",toppings);
27 },
28 makeMuffin:function(mSize){
29 baker.bake("muffin",size);
30 }
31 }
32 }

ModulesLoadedFromRemoteSources
Themoduleproposalsalsocaterformoduleswhichareremotelybased(e.g.athirdpartylibraries)
makingitsimplistictoloadmodulesinfromexternallocations.Heresanexampleofpullinginthe
modulewedefinedaboveandutilizingit:

?
1 modulecakeFactoryfrom"http://addyosmani.com/factory/cakes.js";
2 cakeFactory.oven.makeCupcake("sprinkles");
3 cakeFactory.oven.makeMuffin("large");

ModuleLoaderAPI
ThemoduleloaderproposeddescribesadynamicAPIforloadingmodulesinhighlycontrolled
contexts.Signaturessupportedontheloaderinclude load(url,moduleInstance,error) forloading
modules, createModule(object,globalModuleReferences) andothers.

Heresanotherexamplefordynamicallyloadinginthemoduleweinitiallydefined.Notethatunlikethe
lastexamplewherewepulledinamodulefromaremotesource,themoduleloaderAPIisbettersuited
todynamiccontexts.

1 Loader.load("http://addyosmani.com/factory/cakes.js",
2 function(cakeFactory){
3 cakeFactory.oven.makeCupcake("chocolate");
4 });

CommonJSlikeModulesForTheServer

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 132/188
26/04/2015 LearningJavaScriptDesignPatterns

Fordeveloperswhoaremoreinterestedinserverenvironments,themodulesystemproposedfor
ES.nextisntjustconstrainedtolookingatmodulesinthebrowser.Belowforexample,wecanseea
CommonJSlikemoduleproposedforuseontheserver:

?
1 //io/File.js
2 exportfunctionopen(path){...};
3 exportfunctionclose(hnd){...};

?
1 //compiler/LexicalHandler.js
2 modulefilefrom"io/File";
3
4 import{open,close}fromfile;
5 exportfunctionscan(in){
6 try{
7 varh=open(in)...
8 }
9 finally{close(h)}
10 }

1 modulelexerfrom"compiler/LexicalHandler";
2 modulestdlibfrom"@std";
3
4 //...scan(cmdline[0])...

ClassesWithConstructors,Getters&Setters
Thenotionofaclasshasalwaysbeenacontentiousissuewithpuristsandwevesofargotalongwith
eitherfallingbackonJavaScriptsprototypalnatureorthroughusingframeworksorabstractionsthat
offertheabilitytouseclassdefinitionsinaformthatdesugarstothesameprototypalbehavior.

InHarmony,classeshavebeenproposedforthelanguagealongwithconstructorsand(finally)some
senseoftrueprivacy.Inthefollowingexamples,inlinecommentsareprovidedtohelpexplainhow
classesarestructured.

Readingthrough,onemayalsonoticethelackofthewordfunctioninhere.Thisisntatypoerror:
TC39havebeenmakingaconsciousefforttodecreaseourabuseofthe function keywordforeverything
andthehopeisthatthiswillhelpsimplifyhowwewritecode.

1 classCake{
2
3 //Wecandefinethebodyofaclass"constructor
4 //functionbyusingthekeyword"constructor"followed
5 //byanargumentlistofpublicandprivatedeclarations.
6 constructor(name,toppings,price,cakeSize){
7 publicname=name;
8 publiccakeSize=cakeSize;
9 publictoppings=toppings;
10 privateprice=price;
11
12 }
13
14 //AsapartofES.next'seffortstodecreasetheunnecessary
15 //useof"function"foreverything,you'llnoticethatit's

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 133/188
26/04/2015 LearningJavaScriptDesignPatterns

16 //droppedforcasessuchasthefollowing.Hereanidentifier
17 //followedbyanargumentlistandabodydefinesanewmethod
18
19 addTopping(topping){
20 public(this).toppings.push(topping);
21 }
22
23 //Getterscanbedefinedbydeclaringgetbefore
24 //anidentifier/methodnameandacurlybody.
25 getallToppings(){
26 returnpublic(this).toppings;
27 }
28
29 getqualifiesForDiscount(){
30 returnprivate(this).price>5;
31 }
32
33 //Similartogetters,setterscanbedefinedbyusing
34 //the"set"keywordbeforeanidentifier
35 setcakeSize(cSize){
36 if(cSize<0){
37 thrownewError("Cakemustbeavalidsize
38 eithersmall,mediumorlarge");
39 }
40 public(this).cakeSize=cSize;
41 }
42
43
44 }

ESHarmonyConclusions
Asweveseen,Harmonymightcomewithsomeexcitingnewadditionsthatwilleasethedevelopment
ofmodularapplicationsandhandlingconcernssuchasdependencymanagement.

Atpresent,ourbestoptionsforusingHarmonysyntaxintodaysbrowsersisthroughatranspilersuch
asGoogleTraceurorEsprima.TherearealsoprojectssuchasRequireHMwhichallowustouse
HarmonymoduleswithAMD.OurbestbetshoweveruntilwehavespecificationfinalizationareAMD
(forinbrowsermodules)andCommonJS(forthoseontheserver).

RelatedReading

AFirstLookAtTheUpcomingJavaScriptModules

DavidHermanOnJavaScript/ES.Next(Video)

ESHarmonyModuleProposals

ESHarmonyModuleSemantics/StructureRationale

ESHarmonyClassProposals

Conclusions

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 134/188
26/04/2015 LearningJavaScriptDesignPatterns

InthissectionwereviewedseveraloftheoptionsavailableforwritingmodularJavaScriptusing
modernmoduleformats.

Theseformatshaveanumberofadvantagesoverusingthemodulepatternaloneincluding:avoiding
theneedtomanageglobalvariables,bettersupportforstaticanddynamicdependencymanagement,
improvedcompatibilitywithscriptloaders,bettercompatibilityformodulesontheserverandmore.

Inshort,Irecommendtryingoutwhatsbeensuggestedinthischapterastheseformatsofferagreat
dealofpowerandflexibilitythatcansignificantlyassistwithbetterorganizingourapplications.

DesignPatternsInjQuery

jQueryiscurrentlythemostpopularJavaScriptDOMmanipulationlibraryandprovidesanabstracted
layerforinteractingwiththeDOMinasafe,crossbrowsermanner.Interestingly,thelibraryalsoserves
asanexampleofhowdesignpatternscanbeeffectivelyusedtocreateanAPIwhichisbothreadable
andeasytouse.

WhilstinmanycasesthecorecontributorsthatwrotejQuerydidntsetouttousespecificpatterns,they
existthereregardlessandareusefultolearnfrom.Letstakealookatwhatsomeofthesepatternsare
andhowtheyareusedintheAPI.

TheCompositePattern
TheCompositePatterndescribesagroupofobjectsthatcanbetreatedinthesamewayasingle
instanceofanobjectmaybe.

Thisallowsustotreatbothindividualobjectsandcompositionsinauniformmanner,meaningthatthe
samebehaviorwillbeappliedregardlessofwhetherwereworkingwithoneitemorathousand.

InjQuery,whenwereapplyingmethodstoanelementorcollectionofelements,wecantreatbothsets
inauniformmannerasbothselectionsreturnajQueryobject.

ThisisdemonstratedbythecodesampleusingthejQueryselectorbelow.Hereitspossibletoaddan
classtobothselectionsforasingleelement(e.ganelementwithauniqueID)oragroupof
active
elementswiththesametagnameorclass,withoutadditionaleffort:

?
1 //Singleelements
2 $("#singleItem").addClass("active");
3 $("#container").addClass("active");
4
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 135/188
26/04/2015 LearningJavaScriptDesignPatterns
5 //Collectionsofelements
6 $("div").addClass("active");
7 $(".item").addClass("active");
8 $("input").addClass("active");

ThejQuery implementationcouldeitherdirectlyusenativeforloops(orjQuerys
addClass()
jQuery.each() / jQuery.fn.each() )toiteratethroughacollectioninordertoapplythemethodtoboth
singleitemsorgroups.Lookingthroughthesourcewecanseethisisindeedthecase:

1 addClass:function(value){
2 varclassNames,i,l,elem,
3 setClass,c,cl;
4
5 if(jQuery.isFunction(value)){
6 returnthis.each(function(j){
7 jQuery(this).addClass(value.call(this,j,this.className));
8 });
9 }
10
11 if(value&&typeofvalue==="string"){
12 classNames=value.split(rspace);
13
14 for(i=0,l=this.length;i<l;i++){
15 elem=this[i];
16
17 if(elem.nodeType===1){
18 if(!elem.className&&classNames.length===1){
19 elem.className=value;
20
21 }else{
22 setClass=""+elem.className+"";
23
24 for(c=0,cl=classNames.length;c<cl;c++){
25 if(!~setClass.indexOf(""+classNames[c]+"")){
26 setClass+=classNames[c]+"";
27 }
28 }
29 elem.className=jQuery.trim(setClass);
30 }
31 }
32 }
33 }
34
35 returnthis;
36 }

TheAdapterPattern
TheAdapterPatterntranslatesaninterfaceforanobjectorclassintoaninterfacecompatiblewitha
specificsystem.

Adaptersbasicallyallowobjectsorclassestofunctiontogetherwhichnormallycouldntduetotheir
incompatibleinterfaces.Theadaptertranslatescallstoitsinterfaceintocallstotheoriginalinterfaceand
thecoderequiredtoachievethisisusuallyquiteminimal.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 136/188
26/04/2015 LearningJavaScriptDesignPatterns

OneexampleofanadapterwemayhaveusedisthejQuery jQuery.fn.css() method.Ithelpsnormalize


theinterfacestohowstylescanbeappliedacrossanumberofbrowsers,makingittrivialforustousea
simplesyntaxwhichisadaptedtousewhatthebrowseractuallysupportsbehindthescenes:

1 //Crossbrowseropacity:
2 //opacity:0.9;Chrome4+,FF2+,Saf3.1+,Opera9+,IE9,iOS3.2+,Android2.1+
3 //filter:alpha(opacity=90);IE6IE8
4
5 //Settingopacity
6 $(".container").css({opacity:.5});
7
8 //Gettingopacity
9 varcurrentOpacity=$(".container").css('opacity');

ThecorrespondingjQuerycorecssHookwhichmakestheabovepossiblecanbeseenbelow:

1 get:function(elem,computed){
2 //IEusesfiltersforopacity
3 returnropacity.test((
4 computed&&elem.currentStyle?
5 elem.currentStyle.filter:elem.style.filter)||"")?
6 (parseFloat(RegExp.$1)/100)+"":
7 computed?"1":"";
8 },
9
10 set:function(elem,value){
11 varstyle=elem.style,
12 currentStyle=elem.currentStyle,
13 opacity=jQuery.isNumeric(value)?
14 "alpha(opacity="+value*100+")":"",
15 filter=currentStyle&&currentStyle.filter||style.filter||"";
16
17 //IEhastroublewithopacityifitdoesnothavelayout
18 //Forceitbysettingthezoomlevel
19 style.zoom=1;
20
21 //ifsettingopacityto1,andnootherfilters
22 //existattempttoremovefilterattribute#6652
23 if(value>=1&&jQuery.trim(filter.replace(ralpha,""))===""){
24
25 //Settingstyle.filtertonull,""&""stillleave
26 //"filter:"inthecssTextif"filter:"ispresentatall,
27 //clearTypeisdisabled,wewanttoavoidthisstyle.removeAttribute
28 //isIEOnly,butsoapparentlyisthiscodepath...
29 style.removeAttribute("filter");
30
31 //iftherethereisnofilterstyleappliedinacssrule,wearedone
32 if(currentStyle&&!currentStyle.filter){
33 return;
34 }
35 }
36
37 //otherwise,setnewfiltervalues
38 style.filter=ralpha.test(filter)?
39 filter.replace(ralpha,opacity):
40 filter+""+opacity;
41 }
42 };
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 137/188
26/04/2015 LearningJavaScriptDesignPatterns

TheFacadePattern
Aswereviewedearlierinthebook,theFacadePatternprovidesasimplerabstractedinterfacetoa
larger(potentiallymorecomplex)bodyofcode.

FacadescanbefrequentlyfoundacrossthejQuerylibraryandprovidedeveloperseasyaccessto
implementationsforhandlingDOMmanipulation,animationandofparticularinterest,crossbrowser
Ajax.

ThefollowingarefacadesforjQuerys $.ajax() :

?
1 $.get(url,data,callback,dataType);
2 $.post(url,data,callback,dataType);
3 $.getJSON(url,data,callback);
4 $.getScript(url,callback);

Thesearetranslatedbehindthescenesto:

?
1 //$.get()
2 $.ajax({
3 url:url,
4 data:data,
5 dataType:dataType
6 }).done(callback);
7
8 //$.post
9 $.ajax({
10 type:"POST",
11 url:url,
12 data:data,
13 dataType:dataType
14 }).done(callback);
15
16 //$.getJSON()
17 $.ajax({
18 url:url,
19 dataType:"json",
20 data:data,
21 }).done(callback);
22
23 //$.getScript()
24 $.ajax({
25 url:url,
26 dataType:"script",
27 }).done(callback);

Whatsevenmoreinterestingisthattheabovefacadesareactuallyfacadesintheirownright,hidinga
greatdealofcomplexitybehindthescenes.

Thisisbecausethe jQuery.ajax() implementationinjQuerycoreisanontrivialpieceofcodetosaythe


least.AtminimumitnormalizesthecrossbrowserdifferencesbetweenXHR(XMLHttpRequest)and
makesittrivialforustoperformcommonHTTPactions(e.g get , post etc),workwithDeferredsand

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 138/188
26/04/2015 LearningJavaScriptDesignPatterns

soon.

Asitwouldtakeanentirechaptertoshowallofthecoderelatedtotheabovefacades,hereisinsteadthe
codeinjQuerycorenormalizingXHR:

1 //Functionstocreatexhrs
2 functioncreateStandardXHR(){
3 try{
4 returnnewwindow.XMLHttpRequest();
5 }catch(e){}
6 }
7
8 functioncreateActiveXHR(){
9 try{
10 returnnewwindow.ActiveXObject("Microsoft.XMLHTTP");
11 }catch(e){}
12 }
13
14 //Createtherequestobject
15 jQuery.ajaxSettings.xhr=window.ActiveXObject?
16 /*Microsoftfailedtoproperly
17 *implementtheXMLHttpRequestinIE7(can'trequestlocalfiles),
18 *soweusetheActiveXObjectwhenitisavailable
19 *AdditionallyXMLHttpRequestcanbedisabledinIE7/IE8so
20 *weneedafallback.
21 */
22 function(){
23 return!this.isLocal&&createStandardXHR()||createActiveXHR();
24 }:
25 //Forallotherbrowsers,usethestandardXMLHttpRequestobject
26 createStandardXHR;
27 ...

WhilstthefollowingblockofcodeisalsoalevelabovetheactualjQueryXHR( jqXHR )implementation,


itstheconveniencefacadethatweactuallymostcommonlyinteractwith:

?
1 //Requesttheremotedocument
2 jQuery.ajax({
3 url:url,
4 type:type,
5 dataType:"html",
6 data:params,
7 //Completecallback(responseTextisusedinternally)
8 complete:function(jqXHR,status,responseText){
9 //StoretheresponseasspecifiedbythejqXHRobject
10 responseText=jqXHR.responseText;
11 //Ifsuccessful,injecttheHTMLintoallthematchedelements
12 if(jqXHR.isResolved()){
13 //Gettheactualresponseincase
14 //adataFilterispresentinajaxSettings
15 jqXHR.done(function(r){
16 responseText=r;
17 });
18 //Seeifaselectorwasspecified
19 self.html(selector?
20 //Createadummydivtoholdtheresults
21 jQuery("<div>")
22 //injectthecontentsofthedocumentin,removingthescripts
23 //toavoidany'PermissionDenied'errorsinIE
24 .append(responseText.replace(rscript,""))
25
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 139/188
26/04/2015 LearningJavaScriptDesignPatterns
26 //Locatethespecifiedelements
27 .find(selector):
28
29 //Ifnot,justinjectthefullresult
30 responseText);
31 }
32
33 if(callback){
34 self.each(callback,[responseText,status,jqXHR]);
35 }
36 }
37 });
38
39 returnthis;
40 }
41 </div>

TheObserverPattern
AnotherpatternwereviewedearlieristheObserver(Publish/Subscribe)pattern.Thisiswherethe
objectsinasystemmaysubscribetootherobjectsandbenotifiedbythemwhenaneventofinterest
occurs.

jQuerycorehascomewithbuiltinsupportforapublish/subscribelikesystemforafewyearsnow,
whichitreferstoascustomevents.

Inearlierversionsofthelibrary,accesstothesecustomeventswaspossibleusing jQuery.bind()
(subscribe), jQuery.trigger() (publish)and jQuery.unbind() (unsubscribe),butinrecentversionsthiscan
bedoneusing jQuery.on() , jQuery.trigger() and jQuery.off() .

Belowwecanseeanexampleofthisbeingusedinpractice:

1 //Equivalenttosubscribe(topicName,callback)
2 $(document).on("topicName",function(){
3 //..performsomebehaviour
4 });
5
6 //Equivalenttopublish(topicName)
7 $(document).trigger("topicName");
8
9 //Equivalenttounsubscribe(topicName)
10 $(document).off("topicName");

Callsto jQuery.on() and jQuery.off() eventuallygothroughthejQueryeventssystem.SimilartoAjax,


astheimplementationforthisisrelativelylong,wecaninsteadlookatwhereandhowtheactualevent
handlersforcustomeventsareattached:

?
1 jQuery.event={
2
3 add:function(elem,types,handler,data,selector){
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 140/188
26/04/2015 LearningJavaScriptDesignPatterns
4
5 varelemData,eventHandle,events,
6 t,tns,type,namespaces,handleObj,
7 handleObjIn,quick,handlers,special;
8
9 ...
10
11 //Inittheelement'seventstructureandmainhandler,
12 //ifthisisthefirst
13 events=elemData.events;
14 if(!events){
15 elemData.events=events={};
16 }
17 ...
18
19 //Handlemultipleeventsseparatedbyaspace
20 //jQuery(...).bind("mouseovermouseout",fn);
21 types=jQuery.trim(hoverHack(types)).split("");
22 for(t=0;t<types.length;t++){
23
24 ...
25
26 //Inittheeventhandlerqueueifwe'rethefirst
27 handlers=events[type];
28 if(!handlers){
29 handlers=events[type]=[];
30 handlers.delegateCount=0;
31
32 //OnlyuseaddEventListener/attachEventifthespecial
33 //eventshandlerreturnsfalse
34 if(!special.setup||special.setup.call(elem,data,
35 //namespaces,eventHandle)===false){
36 //Bindtheglobaleventhandlertotheelement
37 if(elem.addEventListener){
38 elem.addEventListener(type,eventHandle,false);
39
40 }elseif(elem.attachEvent){
41 elem.attachEvent("on"+type,eventHandle);
42 }
43 }
44 }

ForthosethatprefertousetheconventionalnamingschemefortheObserverpattern,BenAlman
createdasimplewrapperaroundtheabovemethodswhichprovidesusaccessto jQuery.publish() ,
jQuery.subscribe ,and jQuery.unsubscribe methods.Ivepreviouslylinkedtothemearlierinthebook,but
wecanseethewrapperinfullbelow.

1 (function($){
2
3 varo=$({});
4
5 $.subscribe=function(){
6 o.on.apply(o,arguments);
7 };
8
9 $.unsubscribe=function(){
10 o.off.apply(o,arguments);
11 };
12
13 $.publish=function(){
14 o.trigger.apply(o,arguments);
15 };
16

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 141/188
26/04/2015 LearningJavaScriptDesignPatterns
17 }(jQuery));

InrecentversionsofjQuery,amultipurposecallbacksobject( jQuery.Callbacks )wasmadeavailableto


enableuserstowritenewsolutionsbasedoncallbacklists.Onesuchsolutiontowriteusingthisfeature
isanotherPublish/Subscribesystem.Animplementationofthisisthefollowing:

1 vartopics={};
2
3 jQuery.Topic=function(id){
4 varcallbacks,
5 topic=id&&topics[id];
6 if(!topic){
7 callbacks=jQuery.Callbacks();
8 topic={
9 publish:callbacks.fire,
10 subscribe:callbacks.add,
11 unsubscribe:callbacks.remove
12 };
13 if(id){
14 topics[id]=topic;
15 }
16 }
17 returntopic;
18 };

whichcanthenbeusedasfollows:
?

1 //Subscribers
2 $.Topic("mailArrived").subscribe(fn1);
3 $.Topic("mailArrived").subscribe(fn2);
4 $.Topic("mailSent").subscribe(fn1);
5
6 //Publisher
7 $.Topic("mailArrived").publish("helloworld!");
8 $.Topic("mailSent").publish("woo!mail!");
9
10 //Here,"helloworld!"getspushedtofn1andfn2
11 //whenthe"mailArrived"notificationispublished
12 //with"woo!mail!"alsobeingpushedtofn1when
13 //the"mailSent"notificationispublished.
14
15 //Outputs:
16 //helloworld!
17 //fn2says:helloworld!
18 //woo!mail!

TheIteratorPattern
TheIteratorisadesignpatternwhereiterators(objectsthatallowustotraversethroughalltheelements
ofacollection)accesstheelementsofanaggregateobjectsequentiallywithoutneedingtoexposeits
underlyingform.

Iteratorsencapsulatetheinternalstructureofhowthatparticulariterationoccurs.InthecaseofjQuerys

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 142/188
26/04/2015 LearningJavaScriptDesignPatterns

iterator,weareactuallyabletousetheunderlyingcodebehind jQuery.each() toiterate


jQuery.fn.each()
throughacollection,withoutneedingtoseeorunderstandthecodeworkingbehindthescenes
providingthiscapability.

Thisisapatternthatcouldbeconsideredaspecialcaseofthefacade,whereweexplicitlydealwith
problemsrelatedtoiteration.

?
1 $.each(["john","dave","rick","julian"],function(index,value){
2 console.log(index+":""+value);
3 });
4
5 $("li").each(function(index){
6 console.log(index+":"+$(this).text());
7 });

Herewecanseethecodefor jQuery.fn.each() :

1 //Executeacallbackforeveryelementinthematchedset.
2 each:function(callback,args){
3 returnjQuery.each(this,callback,args);
4 }

Followedbythecodebehind jQuery.each() whichhandlestwowaysofiteratingthroughobjects:

?
1 each:function(object,callback,args){
2 varname,i=0,
3 length=object.length,
4 isObj=length===undefined||jQuery.isFunction(object);
5
6 if(args){
7 if(isObj){
8 for(nameinobject){
9 if(callback.apply(object[name],args)===false){
10 break;
11 }
12 }
13 }else{
14 for(;i<length;){
15 if(callback.apply(object[i++],args)===false){
16 break;
17 }
18 }
19 }
20
21 //Aspecial,fast,caseforthemostcommonuseofeach
22 }else{
23 if(isObj){
24 for(nameinobject){
25 if(callback.call(object[name],name,object[name])===false){
26 break;
27 }
28 }
29 }else{
30 for(;i<length;){
31 if(callback.call(object[i],i,object[i++])===false){
32 break;
33 }
34 }
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 143/188
26/04/2015 LearningJavaScriptDesignPatterns
35 }
36 }
37
38 returnobject;
39 };

TheLazyInitializationPattern
LazyInitializationisadesignpatternwhichallowsustodelayexpensiveprocessesuntilthefirst
instancetheyareneeded.Anexampleofthisisthe .ready() functioninjQuerythatonlyexecutesa
callbackoncetheDOMisready.

?
1 $(document).ready(function(){
2
3 //Theajaxrequestwon'tattempttoexecuteuntil
4 //theDOMisready
5
6 varjqxhr=$.ajax({
7 url:"http://domain.com/api/",
8 data:"display=latest&order=ascending"
9 })
10 .done(function(data)){
11 $(".status").html("contentloaded");
12 console.log("Dataoutput:"+data);
13 });
14
15 });

jQuery.fn.ready() ispoweredby jQuery.bindReady() ,seenbelow:

1 bindReady:function(){
2 if(readyList){
3 return;
4 }
5
6 readyList=jQuery.Callbacks("oncememory");
7
8 //Catchcaseswhere$(document).ready()iscalledafterthe
9 //browsereventhasalreadyoccurred.
10 if(document.readyState==="complete"){
11 //Handleitasynchronouslytoallowscriptstheopportunitytodelayready
12 returnsetTimeout(jQuery.ready,1);
13 }
14
15 //Mozilla,Operaandwebkitsupportthisevent
16 if(document.addEventListener){
17 //Usethehandyeventcallback
18 document.addEventListener("DOMContentLoaded",DOMContentLoaded,false);
19
20 //Afallbacktowindow.onload,thatwillalwayswork
21 window.addEventListener("load",jQuery.ready,false);
22
23 //IfIEeventmodelisused
24 }elseif(document.attachEvent){

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 144/188
26/04/2015 LearningJavaScriptDesignPatterns
25 //ensurefiringbeforeonload,
26 //maybelatebutsafealsoforiframes
27 document.attachEvent("onreadystatechange",DOMContentLoaded);
28
29 //Afallbacktowindow.onload,thatwillalwayswork
30 window.attachEvent("onload",jQuery.ready);
31
32 //IfIEandnotaframe
33 //continuallychecktoseeifthedocumentisready
34 vartoplevel=false;
35
36 try{
37 toplevel=window.frameElement==null;
38 }catch(e){}
39
40 if(document.documentElement.doScroll&&toplevel){
41 doScrollCheck();
42 }
43 }
44 },

WhilstnotdirectlyusedinjQuerycore,somedevelopersmayalsobefamiliarwiththeconceptof
LazyLoadingviapluginssuchasthis.

LazyLoadingiseffectivelythesameasLazyinitializationandisatechniquewherebyadditionaldataon
apageisloadedwhenneeded(e.g.whenauserhasscrolledtotheendofthepage).Inrecentyearsthis
patternhasbecomequiteprominentandcanbecurrentlybefoundinboththeTwitterandFacebook
UIs.

TheProxyPattern
Therearetimeswhenitisnecessaryforustocontroltheaccessandcontextbehindanobjectandthisis
wheretheProxypatterncanbeuseful.

Itcanhelpuscontrolwhenanexpensiveobjectshouldbeinstantiated,provideadvancedwaysto
referencetheobjectormodifytheobjecttofunctionaparticularwayinspecificcontexts.

InjQuerycore,a jQuery.proxy() methodexistswhichacceptsasinputafunctionandreturnsanewone


whichwillalwayshaveaspecificcontext.Thisensuresthatthevalueof this withinafunctionisthe
valueweexpect.

Anexampleofwherethisisusefuliswhenweremakinguseoftimerswithina click eventhandler.


Imaginewehavethefollowinghandlerpriortoaddinganytimers:

1 $("button").on("click",function(){
2 //Withinthisfunction,"this"referstotheelementthatwasclicked
3 $(this).addClass("active");
4 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 145/188
26/04/2015 LearningJavaScriptDesignPatterns

Ifwewishedtoaddaharddelaybeforethe active classwasadded,wecoulduse setTimeout() to


achievethis.Unfortunatelythereisasmallproblemwiththissolution:whateverfunctionispassedto
setTimeout() willhaveadifferentvaluefor this withinthatfunction.Itwillinsteadrefertothe window

object,whichisnotwhatwedesire.

?
1 $("button").on("click",function(){
2 setTimeout(function(){
3 //"this"doesn'trefertoourelement!
4 //Itreferstowindow
5 $(this).addClass("active");
6 });
7 });

Toworkaroundthisproblem,wecanuse jQuery.proxy() toimplementatypeofproxypattern.By


callingitwiththefunctionandvaluewewouldlikeassignedto this itwillactuallyreturnafunction
thatretainsthevaluewedesirewithinthecorrectcontext.Hereshowthiswouldlook:

1 $("button").on("click",function(){
2
3 setTimeout($.proxy(function(){
4 //"this"nowreferstoourelementaswewanted
5 $(this).addClass("active");
6 },this),500);
7
8 //thelast"this"we'repassingtells$.proxy()thatourDOMelement
9 //isthevaluewewant"this"toreferto.
10 });

jQuerysimplementationof jQuery.proxy() canbefoundbelow:

?
1 //Bindafunctiontoacontext,optionallypartiallyapplyingany
2 //arguments.
3 proxy:function(fn,context){
4 if(typeofcontext==="string"){
5 vartmp=fn[context];
6 context=fn;
7 fn=tmp;
8 }
9
10 //Quickchecktodetermineiftargetiscallable,inthespec
11 //thisthrowsaTypeError,butwewilljustreturnundefined.
12 if(!jQuery.isFunction(fn)){
13 returnundefined;
14 }
15
16 //Simulatedbind
17 varargs=slice.call(arguments,2),
18 proxy=function(){
19 returnfn.apply(context,args.concat(slice.call(arguments)));
20 };
21
22 //Settheguidofuniquehandlertothesameoforiginalhandler,soitcanberem
23 proxy.guid=fn.guid=fn.guid||proxy.guid||jQuery.guid++;
24
25 returnproxy;
26 }

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 146/188
26/04/2015 LearningJavaScriptDesignPatterns

TheBuilderPattern
WhenworkingwiththeDOM,weoftenwanttoconstructnewelementsdynamicallyaprocesswhich
canincreaseincomplexitydependingonthefinalmarkup,attributesandpropertieswewishour
constructedelementstocontain.

Complexelementsrequirespecialcarewhenbeingdefined,especiallyifwewanttheflexibilitytoeither
literallydefinethefinalmarkupforourelements(whichcangetmessy)ortakeamorereadableobject
orientedrouteinstead.HavingamechanismforbuildingourcomplexDOMobjectsthatisindependent
fromtheobjectsthemselvesgivesusthisflexibilityandthatisexactlywhattheBuilderpatternprovides.

Buildersallowustoconstructcomplexobjectsbyonlyspecifyingthetypeandcontentoftheobject,
shieldingusfromtheprocessofcreatingorrepresentingtheobjectexplicitly.

ThejQuerydollarsignallowsustodojustthisasitprovidesanumberofdifferentmeansfor
dynamicallybuildingnewjQuery(andDOM)objects,byeitherpassinginthecompletemarkupforan
element,partialmarkupandcontentorusingthejQueryforconstruction:

1 $('<divclass="foo">bar</div>');
2
3 $('<pid="test">foo<em>bar</em></p>').appendTo("body");
4
5 varnewParagraph=$("<p/>").text("Helloworld");
6
7 $("<input/>")
8 .attr({"type":"text","id":"sample"})
9 .appendTo("#container");

BelowisasnippetfromjQuerycoresinternal jQuery.prototype methodwhichassistswiththe


constructionofjQueryobjectsfrommarkuppassedtothe jQuery() selector.Regardlessofwhetheror
not document.createElement isusedtocreateanewelement,areferencetotheelement(foundorcreated)
isinjectedintothereturnedobjectsofurthermethodssuchas .attr() canbeeasilyusedonitright
after.

1 //HANDLE:$(html)>$(array)
2 if(match[1]){
3 context=contextinstanceofjQuery?context[0]:context;
4 doc=(context?context.ownerDocument||context:document);
5
6 //Ifasinglestringispassedinandit'sasingletag
7 //justdoacreateElementandskiptherest
8 ret=rsingleTag.exec(selector);
9
10 if(ret){
11 if(jQuery.isPlainObject(context)){
12 selector=[document.createElement(ret[1])];
13 jQuery.fn.attr.call(selector,context,true);
14
15 }else{
16 selector=[doc.createElement(ret[1])];
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 147/188
26/04/2015 LearningJavaScriptDesignPatterns
17 }
18
19 }else{
20 ret=jQuery.buildFragment([match[1]],[doc]);
21 selector=(ret.cacheable?jQuery.clone(ret.fragment):ret.fragment).childN
22 }
23
24 returnjQuery.merge(this,selector);

jQueryPluginDesignPatterns
jQueryplugindevelopmenthasevolvedoverthepastfewyears.Wenolongerhavejustonewayto
writeplugins,butmany.Inreality,certainplugindesignpatternsmightworkbetterforaparticular
problemorcomponentthanothers.

SomedevelopersmaywishtousethejQueryUIwidgetfactory;itsgreatforcomplex,flexibleUI
components.Somemaynot.

Somemightliketostructuretheirpluginsmorelikemodules(similartothemodulepattern)orusea
moremodernmoduleformatsuchasAMD.

Somemightwanttheirpluginstoharnessthepowerofprototypalinheritance.Othersmaywishtouse
customeventsorPublish/Subscribetocommunicatefrompluginstotherestoftheirapp.Andsoon.

Ibegantothinkaboutpluginpatternsafternoticinganumberofeffortstocreateaonesizefitsall
jQuerypluginboilerplate.Whilesuchaboilerplateisagreatideaintheory,therealityisthatwerarely
writepluginsinonefixedway,usingasinglepatternallthetime.

LetusassumethatwevetriedourhandatwritingourownjQuerypluginsatsomepointandwere
comfortableputtingtogethersomethingthatworks.Itsfunctional.Itdoeswhatitneedstodo,but
perhapswefeelitcouldbestructuredbetter.Maybeitcouldbemoreflexibleorcouldbedesignedto
addressmoreoftheissuesdeveloperscommonlyruninto.Ifthissoundsfamiliar,thenyoumightfind
thischapteruseful.Init,weregoingtoexploreanumberofjQuerypluginpatternsthathaveworked
wellforotherdevelopersinthewild.

Note:Thischapteristargetedatintermediatetoadvanceddevelopers,althoughwewillbrieflyreview
somejQuerypluginfundamentalstobegin.

Ifyoudontfeelquitereadyforthisjustyet,ImhappytorecommendtheofficialjQuery
Plugins/Authoringguide,BenAlmanspluginstyleguideandRemySharpsSignsofaPoorlyWritten
jQueryPlugin.asreadingmaterialpriortostartingthissection.

Patterns
jQuerypluginshavefewconcreterules,whichisoneofthereasonsfortheincrediblediversityinhow
theyareimplementedacrossthecommunity.Atthemostbasiclevel,wecanwriteapluginsimplyby
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 148/188
26/04/2015 LearningJavaScriptDesignPatterns

addinganewfunctionpropertytojQuerys jQuery.fn object,asfollows:

1 $.fn.myPluginName=function(){
2 //ourpluginlogic
3 };

Thisisgreatforcompactness,butthefollowingwouldbeabetterfoundationtobuildon:

1 (function($){
2 $.fn.myPluginName=function(){
3 //ourpluginlogic
4 };
5 })(jQuery);

Here,wevewrappedourpluginlogicinananonymousfunction.Toensurethatouruseofthe $ sign
asashorthandcreatesnoconflictsbetweenjQueryandotherJavaScriptlibraries,wesimplypassitto
thisclosure,whichmapsittothedollarsign.Thisensuresthatitcantbeaffectedbyanythingoutsideof
itsscopeofexecution.

Analternativewaytowritethispatternwouldbetouse jQuery.extend() ,whichenablesustodefine


multiplefunctionsatonceandwhichsometimesmakemoresensesemantically:

1 (function($){
2 $.extend($.fn,{
3 myplugin:function(){
4 //yourpluginlogic
5 }
6 });
7 })(jQuery);

WehavenowreviewedsomejQuerypluginfundamentals,butalotmorecouldbedonetotakethis
further.ALightweightStartisthefirstcompleteplugindesignpatternwellbeexploringanditcovers
somebestpracticesthatwecanuseforbasiceverydayplugindevelopment,takingintoaccount
commongotchasworthapplying.

Note

Whilemostofthepatternsbelowwillbeexplained,Irecommendreadingthroughthecommentsinthe
code,becausetheywilloffermoreinsightintowhycertainbestpracticesareapplied.

Ishouldalsomentionthatnoneofthiswouldbepossiblewithoutthepreviouswork,inputandadvice
ofothermembersofthejQuerycommunity.Ivelistedtheminlinewitheachpatternsothatonecan
readupontheirindividualworkifinterested.

ALightweightStartPattern
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 149/188
26/04/2015 LearningJavaScriptDesignPatterns

Letsbeginourdeeperlookatpluginpatternswithsomethingbasicthatfollowsbestpractices
(includingthoseinthejQuerypluginauthoringguide).Thispatternisidealfordeveloperswhoare
eithernewtoplugindevelopmentorwhojustwanttoachievesomethingsimple(suchasautility
plugin).ALightweightStartusesthefollowing:

Commonbestpracticessuchasasemicolonplacedbeforethefunctionsinvocation(wellgo
throughwhyinthecommentsbelow)
window,document,undefined passedinasarguments.
Abasicdefaultsobject.
Asimplepluginconstructorforlogicrelatedtotheinitialcreationandtheassignmentofthe
elementtoworkwith.
Extendingtheoptionswithdefaults.
Alightweightwrapperaroundtheconstructor,whichhelpstoavoidissuessuchasmultiple
instantiations.
AdherencetothejQuerycorestyleguidelinesformaximizedreadability.

1 /*!
2 *jQuerylightweightpluginboilerplate
3 *Originalauthor:@ajpiano
4 *Furtherchanges,comments:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8
9 //thesemicolonbeforethefunctioninvocationisasafety
10 //netagainstconcatenatedscriptsand/orotherplugins
11 //thatarenotclosedproperly.
12 ;(function($,window,document,undefined){
13
14 //undefinedisusedhereastheundefinedglobal
15 //variableinECMAScript3andismutable(i.e.itcan
16 //bechangedbysomeoneelse).undefinedisn'treally
17 //beingpassedinsowecanensurethatitsvalueis
18 //trulyundefined.InES5,undefinedcannolongerbe
19 //modified.
20
21 //windowanddocumentarepassedthroughaslocal
22 //variablesratherthanasglobals,becausethis(slightly)
23 //quickenstheresolutionprocessandcanbemore
24 //efficientlyminified(especiallywhenbothare
25 //regularlyreferencedinourplugin).
26
27 //Createthedefaultsonce
28 varpluginName="defaultPluginName",
29 defaults={
30 propertyName:"value"
31 };
32
33 //Theactualpluginconstructor
34 functionPlugin(element,options){
35 this.element=element;
36
37 //jQueryhasanextendmethodthatmergesthe
38 //contentsoftwoormoreobjects,storingthe
39 //resultinthefirstobject.Thefirstobject
40 //isgenerallyemptybecausewedon'twanttoalter
41 //thedefaultoptionsforfutureinstancesoftheplugin
42 this.options=$.extend({},defaults,options);

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 150/188
26/04/2015 LearningJavaScriptDesignPatterns
43
44 this._defaults=defaults;
45 this._name=pluginName;
46
47 this.init();
48 }
49
50 Plugin.prototype.init=function(){
51 //Placeinitializationlogichere
52 //WealreadyhaveaccesstotheDOMelementand
53 //theoptionsviatheinstance,e.g.this.element
54 //andthis.options
55 };
56
57 //Areallylightweightpluginwrapperaroundtheconstructor,
58 //preventingagainstmultipleinstantiations
59 $.fn[pluginName]=function(options){
60 returnthis.each(function(){
61 if(!$.data(this,"plugin_"+pluginName)){
62 $.data(this,"plugin_"+pluginName,
63 newPlugin(this,options));
64 }
65 });
66 }
67
68 })(jQuery,window,document);

Usage:

1 $("#elem").defaultPluginName({
2 propertyName:"acustomvalue"
3 });

FurtherReading

Plugins/Authoring,jQuery
SignsofaPoorlyWrittenjQueryPlugin,RemySharp
HowtoCreateYourOwnjQueryPlugin,ElijahManor
StyleinjQueryPluginsandWhyItMatters,BenAlmon
CreateYourFirstjQueryPlugin,Part2,AndrewWirick

CompleteWidgetFactoryPattern
WhilethejQuerypluginauthoringguideisagreatintroductiontoplugindevelopment,itdoesnthelp
obscureawaycommonpluginplumbingtasksthatwehavetodealwithonaregularbasis.

ThejQueryUIWidgetFactoryisasolutiontothisproblemthathelpsusbuildcomplex,statefulplugins
basedonobjectorientedprinciples.Italsoeasescommunicationwithourpluginsinstance,obfuscating
anumberoftherepetitivetasksthatwewouldhavetocodewhenworkingwithbasicplugins.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 151/188
26/04/2015 LearningJavaScriptDesignPatterns

Statefulpluginshelpuskeeptrackoftheircurrentstate,alsoallowingustochangepropertiesofthe
pluginafterithasbeeninitialized.

OneofthegreatthingsabouttheWidgetFactoryisthatthemajorityofthejQueryUIlibraryactually
usesitasabaseforitscomponents.Thismeansthatifwerelookingforfurtherguidanceonstructure
beyondthispattern,wewonthavetolookbeyondthejQueryUIrepositoryonGitHub
(https://github.com/jquery/jqueryui).

ThisjQueryUIWidgetFactorypatterncoversalmostallofthesupporteddefaultfactorymethods,
includingtriggeringevents.Asperthelastpattern,commentsareincludedforallofthemethodsused
andfurtherguidanceisgivenintheinlinecomments.

?
1 /*!
2 *jQueryUIWidgetfactorypluginboilerplate(for1.8/9+)
3 *Author:@addyosmani
4 *Furtherchanges:@peolanha
5 *LicensedundertheMITlicense
6 */
7
8
9 ;(function($,window,document,undefined){
10
11 //defineourwidgetunderanamespaceofyourchoice
12 //withadditionalparameterse.g.
13 //$.widget("namespace.widgetname",(optional)an
14 //existingwidgetprototypetoinheritfrom,anobject
15 //literaltobecomethewidget'sprototype);
16
17 $.widget("namespace.widgetname",{
18
19 //Optionstobeusedasdefaults
20 options:{
21 someValue:null
22 },
23
24 //Setupwidget(e.g.elementcreation,applytheming
25 //,bindeventsetc.)
26 _create:function(){
27
28 //_createwillautomaticallyrunthefirsttime
29 //thiswidgetiscalled.Puttheinitialwidget
30 //setupcodehere,thenwecanaccesstheelement
31 //onwhichthewidgetwascalledviathis.element.
32 //Theoptionsdefinedabovecanbeaccessed
33 //viathis.optionsthis.element.addStuff();
34 },
35
36 //Destroyaninstantiatedpluginandcleanup
37 //modificationsthewidgethasmadetotheDOM
38 destroy:function(){
39
40 //this.element.removeStuff();
41 //ForUI1.8,destroymustbeinvokedfromthe
42 //basewidget
43 $.Widget.prototype.destroy.call(this);
44 //ForUI1.9,define_destroyinsteadanddon't
45 //worryabout
46 //callingthebasewidget
47 },
48
49 methodB:function(event){

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 152/188
26/04/2015 LearningJavaScriptDesignPatterns
50 //_triggerdispatchescallbacksthepluginuser
51 //cansubscribeto
52 //signature:_trigger("callbackName",[eventObject],
53 //[uiObject])
54 //e.g.this._trigger("hover",e/*wheree.type==
55 //"mouseenter"*/,{hovered:$(e.target)});
56 this._trigger("methodA",event,{
57 key:value
58 });
59 },
60
61 methodA:function(event){
62 this._trigger("dataChanged",event,{
63 key:value
64 });
65 },
66
67 //Respondtoanychangestheusermakestothe
68 //optionmethod
69 _setOption:function(key,value){
70 switch(key){
71 case"someValue":
72 //this.options.someValue=doSomethingWith(value);
73 break;
74 default:
75 //this.options[key]=value;
76 break;
77 }
78
79 //ForUI1.8,_setOptionmustbemanuallyinvoked
80 //fromthebasewidget
81 $.Widget.prototype._setOption.apply(this,arguments);
82 //ForUI1.9the_supermethodcanbeusedinstead
83 //this._super("_setOption",key,value);
84 }
85 });
86
87 })(jQuery,window,document);

Usage:

1 varcollection=$("#elem").widgetName({
2 foo:false
3 });
4
5 collection.widgetName("methodB");

FurtherReading

ThejQueryUIWidgetFactory
IntroductiontoStatefulPluginsandtheWidgetFactory,DougNeiner
WidgetFactory(explained),ScottGonzalez
UnderstandingjQueryUIWidgets:ATutorial,Hackingat0300

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 153/188
26/04/2015 LearningJavaScriptDesignPatterns

NestedNamespacingPluginPattern
Aswevepreviouslycoveredinthebook,namespacingourcodeisawaytoavoidcollisionswithother
objectsandvariablesintheglobalnamespace.Theyreimportantbecausewewanttosafeguardour
pluginfrombreakingintheeventthatanotherscriptonthepageusesthesamevariableorplugin
namesasours.Asagoodcitizenoftheglobalnamespace,wemustalsodoourbestnottopreventother
developersscriptsfromexecutingbecauseofthesameissues.

JavaScriptdoesntreallyhavebuiltinsupportfornamespacesasotherlanguagesdo,butitdoeshave
objectsthatcanbeusedtoachieveasimilareffect.Employingatoplevelobjectasthenameofour
namespace,wecaneasilycheckfortheexistenceofanotherobjectonthepagewiththesamename.If
suchanobjectdoesnotexist,thenwedefineit;ifitdoesexist,thenwesimplyextenditwithourplugin.

Objects(or,rather,objectliterals)canbeusedtocreatenestednamespaces,suchas
namespace.subnamespace.pluginName andsoon.Buttokeepthingssimple,thenamespacingboilerplate

belowshouldshowuseverythingweneedtogetstartedwiththeseconcepts.

?
1 /*!
2 *jQuerynamespaced"Starter"pluginboilerplate
3 *Author:@dougneiner
4 *Furtherchanges:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8 ;(function($){
9 if(!$.myNamespace){
10 $.myNamespace={};
11 };
12
13 $.myNamespace.myPluginName=function(el,myFunctionParam,options){
14 //Toavoidscopeissues,use"base"insteadof"this"
15 //toreferencethisclassfrominternaleventsandfunctions.
16 varbase=this;
17
18 //AccesstojQueryandDOMversionsofelement
19 base.$el=$(el);
20 base.el=el;
21
22 //AddareversereferencetotheDOMobject
23 base.$el.data("myNamespace.myPluginName",base);
24
25 base.init=function(){
26 base.myFunctionParam=myFunctionParam;
27
28 base.options=$.extend({},
29 $.myNamespace.myPluginName.defaultOptions,options);
30
31 //Putourinitializationcodehere
32 };
33
34 //SampleFunction,Uncommenttouse
35 //base.functionName=function(parameters){
36 //
37 //};
38 //Runinitializer
39 base.init();
40 };
41
42 $.myNamespace.myPluginName.defaultOptions={
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 154/188
26/04/2015 LearningJavaScriptDesignPatterns
43 myDefaultValue:""
44 };
45
46 $.fn.mynamespace_myPluginName=function
47 (myFunctionParam,options){
48 returnthis.each(function(){
49 (new$.myNamespace.myPluginName(this,
50 myFunctionParam,options));
51 });
52 };
53
54 })(jQuery);

Usage:

?
1 $("#elem").mynamespace_myPluginName({
2 myDefaultValue:"foobar"
3 });

FurtherReading

NamespacinginJavaScript,AngusCroll
UseYour$.fnjQueryNamespace,RyanFlorence
JavaScriptNamespacing,PeterMichaux
ModulesandnamespacesinJavaScript,AxelRauschmayer

CustomEventsPluginPattern(WithTheWidgetfactory)
IntheJavaScriptDesignPatternssectionofthebook,wediscussedtheObserverpatternandlaterwenton
tocoverjQueryssupportforcustomevents,whichofferasimilarsolutionforimplementing
Publish/Subscribe.ThissamepatterncanbeusedwhenwritingjQueryplugins.

Thebasicideahereisthatobjectsinapagecanpublisheventnotificationswhensomethinginteresting
occursinourapplication.Otherobjectsthensubscribeto(orlisten)fortheseeventsandrespond
accordingly.Thisresultsinthelogicforourapplicationbeingsignificantlymoredecoupled,aseach
objectnolongerneedstodirectlycommunicatewithanother.

InthefollowingjQueryUIwidgetfactorypattern,wellimplementabasiccustomeventbased
Publish/Subscribesystemthatallowsourplugintosubscribetoeventnotificationsfromtherestofour
application,whichwillberesponsibleforpublishingthem.

?
1 /*!
2 *jQuerycustomeventspluginboilerplate
3 *Author:DevPatch
4 *Furtherchanges:@addyosmani
5 *LicensedundertheMITlicense

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 155/188
26/04/2015 LearningJavaScriptDesignPatterns
6 */
7
8 //Inthispattern,weusejQuery'scustomeventstoadd
9 //pub/sub(publish/subscribe)capabilitiestowidgets.
10 //Eachwidgetwouldpublishcertaineventsandsubscribe
11 //toothers.Thisapproacheffectivelyhelpstodecouple
12 //thewidgetsandenablesthemtofunctionindependently.
13
14 ;(function($,window,document,undefined){
15 $.widget("ao.eventStatus",{
16 options:{
17
18 },
19
20 _create:function(){
21 varself=this;
22
23 //self.element.addClass("mywidget");
24
25 //subscribeto"myEventStart"
26 self.element.on("myEventStart",function(e){
27 console.log("eventstart");
28 });
29
30 //subscribeto"myEventEnd"
31 self.element.on("myEventEnd",function(e){
32 console.log("eventend");
33 });
34
35 //unsubscribeto"myEventStart"
36 //self.element.off("myEventStart",function(e){
37 ///console.log("unsubscribedtothisevent");
38 //});
39 },
40
41 destroy:function(){
42 $.Widget.prototype.destroy.apply(this,arguments);
43 },
44 });
45 })(jQuery,window,document);
46
47 //Publishingeventnotifications
48 //$(".mywidget").trigger("myEventStart");
49 //$(".mywidget").trigger("myEventEnd");

Usage:

?
1 varel=$("#elem");
2 el.eventStatus();
3 el.eventStatus().trigger("myEventStart");

FurtherReading

CommunicationBetweenjQueryUIWidgets,BenjaminSternthal

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 156/188
26/04/2015 LearningJavaScriptDesignPatterns

PrototypalInheritanceWithTheDOMToObjectBridgePattern
Ascoveredearlier,inJavaScript,wedonthavethetraditionalnotionofclassesthatwewouldfindin
otherclassicalprogramminglanguages,butwedohaveprototypalinheritance.Withprototypal
inheritance,anobjectinheritsfromanotherobject.WecanapplythisconcepttojQueryplugin
development.

Yepnope.jsauthorAlexSextonandjQueryteammemberScottGonzalezhavelookedatthistopicin
detail.Insum,theydiscoveredthatfororganizedmodulardevelopment,clearlyseparatingtheobject
thatdefinesthelogicforapluginfromtheplugingenerationprocessitselfcanbebeneficial.

Thebenefitisthattestingourpluginscodebecomessignificantlyeasierandwearealsoabletoadjust
thewaythingsworkbehindthesceneswithoutalteringthewaythatanyobjectAPIsweimplementare
used.

InSextonsarticleonthistopic,heimplementedabridgethatenablesustoattachourgenerallogictoa
particularplugin,whichweveimplementedinthepatternbelow.

Oneoftheotheradvantagesofthispatternisthatwedonthavetoconstantlyrepeatthesameplugin
initializationcode,thusensuringthattheconceptsbehindDRYdevelopmentaremaintained.Some
developersmightalsofindthispatterneasiertoreadthanothers.

1 /*!
2 *jQueryprototypalinheritancepluginboilerplate
3 *Author:AlexSexton,ScottGonzalez
4 *Furtherchanges:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8
9 //myObjectanobjectrepresentingaconceptwewishtomodel
10 //(e.g.acar)
11 varmyObject={
12 init:function(options,elem){
13 //Mixinthepassedinoptionswiththedefaultoptions
14 this.options=$.extend({},this.options,options);
15
16 //Savetheelementreference,bothasajQuery
17 //referenceandanormalreference
18 this.elem=elem;
19 this.$elem=$(elem);
20
21 //BuildtheDOM'sinitialstructure
22 this._build();
23
24 //returnthissothatwecanchainandusethebridgewithlesscode.
25 returnthis;
26 },
27 options:{
28 name:"Noname"
29 },
30 _build:function(){
31 //this.$elem.html("<h1>"+this.options.name+"</h1>");
32 },
33 myMethod:function(msg){
34 //Wehavedirectaccesstotheassociatedandcached
35 //jQueryelement
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 157/188
26/04/2015 LearningJavaScriptDesignPatterns
36 //this.$elem.append("<p>"+msg+"</p>");
37 }
38 };
39
40
41 //Object.createsupporttest,andfallbackforbrowserswithoutit
42 if(typeofObject.create!=="function"){
43 Object.create=function(o){
44 functionF(){}
45 F.prototype=o;
46 returnnewF();
47 };
48 }
49
50
51 //Createapluginbasedonadefinedobject
52 $.plugin=function(name,object){
53 $.fn[name]=function(options){
54 returnthis.each(function(){
55 if(!$.data(this,name)){
56 $.data(this,name,Object.create(object).init(
57 options,this));
58 }
59 });
60 };
61 };

Usage:

?
1 $.plugin("myobj",myObject);
2
3 $("#elem").myobj({name:"John"});
4
5 varcollection=$("#elem").data("myobj");
6 collection.myMethod("Iamamethod");

FurtherReading

UsingInheritancePatternsToOrganizeLargejQueryApplications,AlexSexton
HowtoManageLargeApplicationsWithjQueryorWhatever(furtherdiscussion),Alex
Sexton
PracticalExampleoftheNeedforPrototypalInheritance,NeerajSingh
PrototypalInheritanceinJavaScript,DouglasCrockford

jQueryUIWidgetFactoryBridgePattern
Ifyoulikedtheideaofgeneratingpluginsbasedonobjectsinthelastdesignpattern,thenyoumightbe
interestedinamethodfoundinthejQueryUIWidgetFactorycalled $.widget.bridge .

ThisbridgebasicallyservesasamiddlelayerbetweenaJavaScriptobjectthatiscreatedusing $.widget
andthejQuerycoreAPI,providingamorebuiltinsolutiontoachievingobjectbasedplugindefinition.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 158/188
26/04/2015 LearningJavaScriptDesignPatterns

Effectively,wereabletocreatestatefulpluginsusingacustomconstructor.

Moreover, $.widget.bridge providesaccesstoanumberofothercapabilities,includingthefollowing:

BothpublicandprivatemethodsarehandledasonewouldexpectinclassicalOOP(i.e.
publicmethodsareexposed,whilecallstoprivatemethodsarenotpossible).
Automaticprotectionagainstmultipleinitializations.
Automaticgenerationofinstancesofapassedobject,andstorageofthemwithinthe
selectionsinternal $.data cache.
Optionscanbealteredpostinitialization.

Forfurtherinformationonhowtousethispattern,pleaseseetheinlinecommentsbelow:

1 /*!
2 *jQueryUIWidgetfactory"bridge"pluginboilerplate
3 *Author:@erichynds
4 *Furtherchanges,additionalcomments:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8
9 //a"widgetName"objectconstructor
10 //required:thismustaccepttwoarguments,
11 //options:anobjectofconfigurationoptions
12 //element:theDOMelementtheinstancewascreatedon
13 varwidgetName=function(options,element){
14 this.name="myWidgetName";
15 this.options=options;
16 this.element=element;
17 this._init();
18 }
19
20 //the"widgetName"prototype
21 widgetName.prototype={
22
23 //_createwillautomaticallyrunthefirsttimethis
24 //widgetiscalled
25 _create:function(){
26 //creationcode
27 },
28
29 //required:initializationlogicfortheplugingoesinto_init
30 //Thisfireswhenourinstanceisfirstcreatedandwhen
31 //attemptingtoinitializethewidgetagain(bythebridge)
32 //afterithasalreadybeeninitialized.
33 _init:function(){
34 //initcode
35 },
36
37 //required:objectstobeusedwiththebridgemustcontainan
38 //"option".Postinitialization,thelogicforchangingoptions
39 //goeshere.
40 option:function(key,value){
41
42 //optional:get/changeoptionspostinitialization
43 //ignoreifyoudon'trequirethem.
44
45 //signature:$("#foo").bar({cool:false});
46 if($.isPlainObject(key)){
47 this.options=$.extend(true,this.options,key);
48
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 159/188
26/04/2015 LearningJavaScriptDesignPatterns
49 //signature:$("#foo").option("cool");getter
50 }elseif(key&&typeofvalue==="undefined"){
51 returnthis.options[key];
52
53 //signature:$("#foo").bar("option","baz",false);
54 }else{
55 this.options[key]=value;
56 }
57
58 //required:optionmustreturnthecurrentinstance.
59 //Whenreinitializinganinstanceonelements,option
60 //iscalledfirstandisthenchainedtothe_initmethod.
61 returnthis;
62 },
63
64 //noticenounderscoreisusedforpublicmethods
65 publicFunction:function(){
66 console.log("publicfunction");
67 },
68
69 //underscoresareusedforprivatemethods
70 _privateFunction:function(){
71 console.log("privatefunction");
72 }
73 };

Usage:

?
1 //connectthewidgetobjtojQuery'sAPIunderthe"foo"namespace
2 $.widget.bridge("foo",widgetName);
3
4 //createaninstanceofthewidgetforuse
5 varinstance=$("#foo").foo({
6 baz:true
7 });
8
9 //ourwidgetinstanceexistsintheelem'sdata
10 //Outputs:#elem
11 console.log(instance.data("foo").element);
12
13 //bridgeallowsustocallpublicmethods
14 //Outputs:"publicmethod"
15 instance.foo("publicFunction");
16
17 //bridgepreventscallstointernalmethods
18 instance.foo("_privateFunction");

FurtherReading

Using$.widget.bridgeOutsideoftheWidgetFactory,EricHynds

jQueryMobileWidgetsWithTheWidgetfactory
jQuerymobileisajQueryprojectframeworkthatencouragesthedesignofubiquitouswebapplications

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 160/188
26/04/2015 LearningJavaScriptDesignPatterns

thatworkbothonpopularmobiledevicesandplatformsandonthedesktop.Ratherthanwriting
uniqueapplicationsforeachdeviceorOS,wesimplywritethecodeonceanditshouldideallyrunon
manyoftheA,BandCgradebrowsersoutthereatthemoment.

ThefundamentalsbehindjQuerymobilecanalsobeappliedtopluginandwidgetdevelopment.

Whatsinterestinginthisnextpatternisthatalthoughtherearesmall,subtledifferencesinwritinga
mobileoptimizedwidget,thosefamiliarwithusingthejQueryUIWidgetFactorypatternfromearlier
shouldbeabletograspthisinnexttonotime.

ThemobileoptimizedwidgetbelowhasanumberofinterestingdifferencesthanthestandardUI
widgetpatternwesawearlier:

$.mobile.widget isreferencedasanexistingwidgetprototypefromwhichtoinherit.For
standardwidgets,passingthroughanysuchprototypeisunnecessaryforbasicdevelopment,
butusingthisjQuerymobilespecificwidgetprototypeprovidesinternalaccesstofurther
optionsformatting.
In _create() ,aguideisprovidedonhowtheofficialjQuerymobilewidgetshandleelement
selection,optingforarolebasedapproachthatbetterfitsthejQMmarkup.Thisisntatallto
saythatstandardselectionisntrecommended,onlythatthisapproachmightmakemore
sensegiventhestructureofjQueryMobilepages.
Guidelinesarealsoprovidedincommentformforapplyingourpluginmethodson
pagecreate aswellasforselectingthepluginapplicationviadatarolesanddataattributes.

?
1 /*!
2 *(jQuerymobile)jQueryUIWidgetfactorypluginboilerplate(for1.8/9+)
3 *Author:@scottjehl
4 *Furtherchanges:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8 ;(function($,window,document,undefined){
9
10 //defineawidgetunderanamespaceofourchoice
11 //here"mobile"hasbeenusedinthefirstargument
12 $.widget("mobile.widgetName",$.mobile.widget,{
13
14 //Optionstobeusedasdefaults
15 options:{
16 foo:true,
17 bar:false
18 },
19
20 _create:function(){
21 //_createwillautomaticallyrunthefirsttimethis
22 //widgetiscalled.Puttheinitialwidgetsetupcode
23 //here,thenwecanaccesstheelementonwhich
24 //thewidgetwascalledviathis.element
25 //Theoptionsdefinedabovecanbeaccessedvia
26 //this.options
27
28 //varm=this.element,
29 //p=m.parents(":jqmData(role="page")"),
30 //c=p.find(":jqmData(role="content")")
31 },
32

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 161/188
26/04/2015 LearningJavaScriptDesignPatterns
33 //Privatemethods/propsstartwithunderscores
34 _dosomething:function(){...},
35
36 //Publicmethodslikethesebelowcancanbecalled
37 //externally:
38 //$("#myelem").foo("enable",arguments);
39
40 enable:function(){...},
41
42 //Destroyaninstantiatedpluginandcleanupmodifications
43 //thewidgethasmadetotheDOM
44 destroy:function(){
45 //this.element.removeStuff();
46 //ForUI1.8,destroymustbeinvokedfromthe
47 //basewidget
48 $.Widget.prototype.destroy.call(this);
49 //ForUI1.9,define_destroyinsteadanddon't
50 //worryaboutcallingthebasewidget
51 },
52
53 methodB:function(event){
54 //_triggerdispatchescallbacksthepluginusercan
55 //subscribeto
56 //signature:_trigger("callbackName",[eventObject],
57 //[uiObject])
58 //e.g.this._trigger("hover",e/*wheree.type==
59 //"mouseenter"*/,{hovered:$(e.target)});
60 this._trigger("methodA",event,{
61 key:value
62 });
63 },
64
65 methodA:function(event){
66 this._trigger("dataChanged",event,{
67 key:value
68 });
69 },
70
71 //Respondtoanychangestheusermakestotheoptionmethod
72 _setOption:function(key,value){
73 switch(key){
74 case"someValue":
75 //this.options.someValue=doSomethingWith(value);
76 break;
77 default:
78 //this.options[key]=value;
79 break;
80 }
81
82 //ForUI1.8,_setOptionmustbemanuallyinvokedfrom
83 //thebasewidget
84 $.Widget.prototype._setOption.apply(this,arguments);
85 //ForUI1.9the_supermethodcanbeusedinstead
86 //this._super("_setOption",key,value);
87 }
88 });
89
90 })(jQuery,window,document);

Usage:

?
1 varinstance=$("#foo").widgetName({
2 foo:false
3 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 162/188
26/04/2015 LearningJavaScriptDesignPatterns
4
5 instance.widgetName("methodB");

WecanalsoselfinitializethiswidgetwheneveranewpageinjQueryMobileiscreated.jQueryMobiles
pageplugindispatchesacreateeventwhenajQueryMobilepage(foundviathe datarole="page"
attribute)isfirstinitialized.Wecanlistenforthatevent(calledpagecreate)andrunourplugin
automaticallywheneveranewpageiscreated.

1 $(document).on("pagecreate",function(e){
2 //Inhere,e.targetreferstothepagethatwascreated
3 //(it'sthetargetofthepagecreateevent)
4 //So,wecansimplyfindelementsonthispagethatmatcha
5 //selectorofourchoosing,andcallourpluginonthem.
6 //Here'showwe'dcallour"foo"pluginonanyelementwitha
7 //dataroleattributeof"foo":
8 $(e.target).find("[datarole="foo"]").foo(options);
9
10 //Or,betteryet,let'swritetheselectoraccountingfortheconfigurable
11 //dataattributenamespace
12 $(e.target).find(":jqmData(role="foo")").foo(options);
13 });

Wecannowsimplyreferencethescriptcontainingourwidgetand pagecreate bindinginapage


runningjQueryMobilesite,anditwillautomaticallyrunlikeanyotherjQueryMobileplugin.

RequireJSAndThejQueryUIWidgetFactory
AswecoveredinthesectiononModernModuleDesignPatterns,RequireJSisanAMDcompatiblescript
loaderthatprovidesacleansolutionforencapsulatingapplicationlogicinsidemanageablemodules.

Itsabletoloadmodulesinthecorrectorder(throughitsorderplugin),simplifiestheprocessof
combiningscriptsviaitsexcellentr.jsoptimizerandprovidesthemeansfordefiningdynamic
dependenciesonapermodulebasis.

Intheboilerplatepatternbelow,wedemonstratehowanAMD(andthusRequireJS)compatiblejQuery
UIwidgetcanbedefinedthatdoesthefollowing:

Allowsthedefinitionofwidgetmoduledependencies,buildingontopoftheprevious
jQueryUIWidgetFactorypatternpresentedearlier.
DemonstratesoneapproachtopassinginHTMLtemplateassetsforcreatingtemplated
widgets(usingUnderscore.jsmicrotemplating).
Includesaquicktiponadjustmentsthatwecanmaketoourwidgetmoduleifwewishto
laterpassitthroughtotheRequireJSoptimizer.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 163/188
26/04/2015 LearningJavaScriptDesignPatterns
1 /*!
2 *jQueryUIWidget+RequireJSmoduleboilerplate(for1.8/9+)
3 *Authors:@jrburke,@addyosmani
4 *LicensedundertheMITlicense
5 */
6
7 //NotefromJames:
8 //
9 //ThisassumesweareusingtheRequireJS+jQueryfile,and
10 //thatthefollowingfilesareallinthesamedirectory:
11 //
12 //requirejquery.js
13 //jqueryui.custom.min.js(customjQueryUIbuildwithwidgetfactory)
14 //templates/
15 //asset.html
16 //ao.myWidget.js
17
18 //Thenwecanconstructthewidgetasfollows:
19
20 //ao.myWidget.jsfile:
21 define("ao.myWidget",["jquery","text!templates/asset.html","underscore","jquery
22
23 //defineourwidgetunderanamespaceofourchoice
24 //"ao"isusedhereasademonstration
25 $.widget("ao.myWidget",{
26
27 //Optionstobeusedasdefaults
28 options:{},
29
30 //Setupwidget(e.g.createelement,applytheming,
31 //bindevents,etc.)
32 _create:function(){
33
34 //_createwillautomaticallyrunthefirsttime
35 //thiswidgetiscalled.Puttheinitialwidget
36 //setupcodehere,thenwecanaccesstheelement
37 //onwhichthewidgetwascalledviathis.element.
38 //Theoptionsdefinedabovecanbeaccessedvia
39 //this.options
40
41 //this.element.addStuff();
42 //this.element.addStuff();
43
44 //WecanthenuseUnderscoretemplatingwith
45 //withtheassetHtmlthathasbeenpulledin
46 //vartemplate=_.template(assetHtml);
47 //this.content.append(template({}));
48 },
49
50 //Destroyaninstantiatedpluginandcleanupmodifications
51 //thatthewidgethasmadetotheDOM
52 destroy:function(){
53 //this.element.removeStuff();
54 //ForUI1.8,destroymustbeinvokedfromthebase
55 //widget
56 $.Widget.prototype.destroy.call(this);
57 //ForUI1.9,define_destroyinsteadanddon'tworry
58 //aboutcallingthebasewidget
59 },
60
61 methodB:function(event){
62 //_triggerdispatchescallbacksthepluginusercan
63 //subscribeto
64 //signature:_trigger("callbackName",[eventObject],
65 //[uiObject])
66 this._trigger("methodA",event,{
67 key:value
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 164/188
26/04/2015 LearningJavaScriptDesignPatterns
68 });
69 },
70
71 methodA:function(event){
72 this._trigger("dataChanged",event,{
73 key:value
74 });
75 },
76
77 //Respondtoanychangestheusermakestotheoptionmethod
78 _setOption:function(key,value){
79 switch(key){
80 case"someValue":
81 //this.options.someValue=doSomethingWith(value);
82 break;
83 default:
84 //this.options[key]=value;
85 break;
86 }
87
88 //ForUI1.8,_setOptionmustbemanuallyinvokedfrom
89 //thebasewidget
90 $.Widget.prototype._setOption.apply(this,arguments);
91 //ForUI1.9the_supermethodcanbeusedinstead
92 //this._super("_setOption",key,value);
93 }
94
95 });
96 });

Usage:

index.html:

1 <scriptdatamain="scripts/main"src="http://requirejs.org/docs/release/1.0.1/minified

main.js

?
1 require({
2
3 paths:{
4 "jquery":"https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min
5 "jqueryui":"https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jqueryui.
6 "boilerplate":"../patterns/jquery.widgetfactory.requirejs.boilerplate"
7 }
8 },["require","jquery","jqueryui","boilerplate"],
9 function(req,$){
10
11 $(function(){
12
13 varinstance=$("#elem").myWidget();
14 instance.myWidget("methodB");
15
16 });
17 });

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 165/188
26/04/2015 LearningJavaScriptDesignPatterns

FurtherReading

FastModularCodeWithjQueryandRequireJS,JamesBurke
jQuerysBestFriends,AlexSexton
ManagingDependenciesWithRequireJS,RuslanMatveev

GloballyAndPerCallOverridableOptions(BestOptionsPattern)
Forournextpattern,welllookatanoptimalapproachtoconfiguringoptionsanddefaultsforaplugin.
Thewaymostofusareprobablyfamiliarwithdefiningpluginoptionsistopassthroughanobject
literalofdefaultsto $.extend() ,asdemonstratedinourbasicpluginboilerplate.

If,however,wereworkingwithapluginwithmanycustomizableoptionsthatwewouldlikeusersto
beabletooverrideeithergloballyoronapercalllevel,thenwecanstructurethingsalittlemore
optimally.

Instead,byreferringtoanoptionsobjectdefinedwithinthepluginnamespaceexplicitly(forexample,
$fn.pluginName.options )andmergingthiswithanyoptionspassedthroughtothepluginwhenitis

initiallyinvoked,usershavetheoptionofeitherpassingoptionsthroughduringplugininitializationor
overridingoptionsoutsideoftheplugin(asdemonstratedhere).

?
1 /*!
2 *jQuery"bestoptions"pluginboilerplate
3 *Author:@cowboy
4 *Furtherchanges:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8
9 ;(function($,window,document,undefined){
10
11 $.fn.pluginName=function(options){
12
13 //Here'sabestpracticeforoverriding"defaults"
14 //withspecifiedoptions.Notehow,ratherthana
15 //regulardefaultsobjectbeingpassedasthesecond
16 //parameter,weinsteadreferto$.fn.pluginName.options
17 //explicitly,mergingitwiththeoptionspasseddirectly
18 //totheplugin.Thisallowsustooverrideoptionsboth
19 //globallyandonapercalllevel.
20
21 options=$.extend({},$.fn.pluginName.options,options);
22
23 returnthis.each(function(){
24
25 varelem=$(this);
26
27 });
28 };
29
30 //Globallyoverridingoptions
31 //Hereareourpubliclyaccessibledefaultpluginoptions
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 166/188
26/04/2015 LearningJavaScriptDesignPatterns
32 //thatareavailableincasetheuserdoesn'tpassinall
33 //ofthevaluesexpected.Theuserisgivenadefault
34 //experiencebutcanalsooverridethevaluesasnecessary.
35 //e.g.$fn.pluginName.key="otherval";
36
37 $.fn.pluginName.options={
38
39 key:"value",
40 myMethod:function(elem,param){
41
42 }
43 };
44
45 })(jQuery,window,document);

Usage:

1 $("#elem").pluginName({
2 key:"foobar"
3 });

FurtherReading

jQueryPluginizationandtheaccompanyinggist,BenAlman

AHighlyConfigurableAndMutablePluginPattern
Inthispattern,similartoAlexSextonsprototypalinheritancepluginpattern,logicforourpluginisnt
nestedinajQuerypluginitself.Weinsteaddefineourpluginlogicusingaconstructorandanobject
literaldefinedonitsprototype.jQueryisthenusedfortheactualinstantiationofthepluginobject.

Customizationistakentothenextlevelbyemployingtwolittletricks,oneofwhichweveseenin
previouspatterns:

Optionscanbeoverriddenbothgloballyandpercollectionofelements/
OptionscanbecustomizedonaperelementlevelthroughHTML5dataattributes(asshown
below).Thisfacilitatespluginbehaviorthatcanbeappliedtoacollectionofelementsbut
thencustomizedinlinewithouttheneedtoinstantiateeachelementwithadifferentdefault
value.

Wedontseethelatteroptioninthewildtoooften,butitcanbeasignificantlycleanersolution(aslong
aswedontmindtheinlineapproach).Ifwonderingwherethiscouldbeuseful,imaginewritinga
draggablepluginforalargesetofelements.Wecouldgoaboutcustomizingtheiroptionsasfollows:

1 $(".itema").draggable({"defaultPosition":"topleft"});
2 $(".itemb").draggable({"defaultPosition":"bottomright"});
3 $(".itemc").draggable({"defaultPosition":"bottomleft"});
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 167/188
26/04/2015 LearningJavaScriptDesignPatterns
4 //etc

Butusingourpatternsinlineapproach,thefollowingwouldbepossible:

?
1 $(".items").draggable();

?
1 html
2 <liclass="item"datapluginoptions="{"defaultPosition":"topleft"}"></div>
3 <liclass="item"datapluginoptions="{"defaultPosition":"bottomleft"}"></div>

Andsoon.Wemaywellhaveapreferenceforoneoftheseapproaches,butitisjustanothervariation
worthbeingawareof.

?
1 /*
2 *"Highlyconfigurable"mutablepluginboilerplate
3 *Author:@markdalgleish
4 *Furtherchanges,comments:@addyosmani
5 *LicensedundertheMITlicense
6 */
7
8
9 //Notethatwiththispattern,asperAlexSexton's,thepluginlogic
10 //hasn'tbeennestedinajQueryplugin.Instead,wejustuse
11 //jQueryforitsinstantiation.
12
13 ;(function($,window,document,undefined){
14
15 //ourpluginconstructor
16 varPlugin=function(elem,options){
17 this.elem=elem;
18 this.$elem=$(elem);
19 this.options=options;
20
21 //ThisnextlinetakesadvantageofHTML5dataattributes
22 //tosupportcustomizationofthepluginonaperelement
23 //basis.Forexample,
24 //<divclass="item"datapluginoptions="{'message':'GoodbyeWorld!'}"></div>
25 this.metadata=this.$elem.data("pluginoptions");
26 };
27
28 //thepluginprototype
29 Plugin.prototype={
30 defaults:{
31 message:"Helloworld!"
32 },
33
34 init:function(){
35 //Introducedefaultsthatcanbeextendedeither
36 //globallyorusinganobjectliteral.
37 this.config=$.extend({},this.defaults,this.options,
38 this.metadata);
39
40 //Sampleusage:
41 //Setthemessageperinstance:
42 //$("#elem").plugin({message:"GoodbyeWorld!"});
43 //or
44 //varp=newPlugin(document.getElementById("elem"),
45 //{message:"GoodbyeWorld!"}).init()

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 168/188
26/04/2015 LearningJavaScriptDesignPatterns
46 //or,settheglobaldefaultmessage:
47 //Plugin.defaults.message="GoodbyeWorld!"
48
49 this.sampleMethod();
50 returnthis;
51 },
52
53 sampleMethod:function(){
54 //e.g.showthecurrentlyconfiguredmessage
55 //console.log(this.config.message);
56 }
57 }
58
59 Plugin.defaults=Plugin.prototype.defaults;
60
61 $.fn.plugin=function(options){
62 returnthis.each(function(){
63 newPlugin(this,options).init();
64 });
65 };
66
67 //optional:window.Plugin=Plugin;
68
69 })(jQuery,window,document);

Usage:

?
1 $("#elem").plugin({
2 message:"foobar"
3 });

FurtherReading

CreatingHighlyConfigurablejQueryPlugins,MarkDalgleish
WritingHighlyConfigurablejQueryPlugins,Part2,MarkDalgleish

WhatMakesAGoodPluginBeyondPatterns?
Attheendoftheday,designpatternsarejustonefacettowritingmaintainablejQueryplugins.There
areanumberofotherfactorsworthconsideringandIwouldliketosharemyowncriteriaforselecting
thirdpartypluginstoaddresssomeoftheotherconcerns.Ihopethishelpsincreasetheoverallquality
ofyourpluginprojects:

Quality

AdheretobestpracticeswithrespecttoboththeJavaScriptandjQuerythatyouwrite.Areeffortsbeing
madetolinttheplugincodeusingeitherjsHintorjsLint?Isthepluginwrittenoptimally?

CodeStyle

DoesthepluginfollowaconsistentcodestyleguidesuchasthejQueryCoreStyleGuidelines?Ifnot,is

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 169/188
26/04/2015 LearningJavaScriptDesignPatterns

yourcodeatleastrelativelycleanandreadable?

Compatibility

WhichversionsofjQueryistheplugincompatiblewith?HasitbeentestedwiththelatestjQuerygit
buildsorlateststable?IfthepluginwaswrittenbeforejQuery1.6,thenitmighthaveissueswith
attributesandproperties,becausethewaytheywereapproachedchangedinthatrelease.

NewversionsofjQueryofferimprovementsandopportunitiesforthejQueryprojecttoimproveon
whatthecorelibraryoffers.Withthiscomesoccasionalbreakages(mainlyinmajorreleases)aswemove
towardsabetterwayofdoingthings.Idliketoseepluginauthorsupdatetheircodewhennecessaryor,
ataminimum,testtheirpluginswithnewversionstomakesureeverythingworksasexpected.

Reliability

Thepluginshouldcomewithitsownsetofunittests.Notonlydotheseproveitactuallyfunctionsas
expected,buttheycanalsoimprovethedesignwithoutbreakingitforendusers.Iconsiderunittests
essentialforanyseriousjQuerypluginthatismeantforaproductionenvironment,andtheyrenotthat
hardtowrite.ForanexcellentguidetoautomatedJavaScripttestingwithQUnit,youmaybeinterested
inAutomatingJavaScriptTestingWithQUnit,byJrnZaefferer.

Performance

Ifthepluginneedstoperformtasksthatrequireextensiveprocessingorheavilymanipulationofthe
DOM,oneshouldfollowbestpracticesforbenchmarkingtohelpminimizethis.UsejsPerf.comtotest
segmentsofthecodetoa)howwellitperformsindifferentbrowsersandb)discoverwhat,ifanything,
mightbeoptimizedfurther.

Documentation

Iftheintensionisforotherdeveloperstousetheplugin,ensurethatitswelldocumented.Document
theAPIandhowthepluginistobeused.Whatmethodsandoptionsdoesthepluginsupport?Doesit
haveanygotchasthatusersneedtobeawareof?Ifuserscannotfigureouthowtousetheplugin,theyll
likelylookforanalternative.Itisalsoofgreathelptocommentyourplugincode.Thisisbyfarthebest
giftyoucanofferotherdevelopers.Ifsomeonefeelstheycannavigateyourcodebasewellenoughto
useitorimproveit,thenyouvedoneagoodjob.

Likelihoodofmaintenance

Whenreleasingaplugin,estimatehowmuchtimemayberequiredformaintenanceandsupport.Weall
lovetoshareourpluginswiththecommunity,butoneneedstosetexpectationsforonesabilityto
answerquestions,addressissuesandmakecontinuousimprovements.Thiscanbedonesimplyby
statingtheprojectintentionsformaintenancesupportupfrontintheREADMEfile.

Conclusions

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 170/188
26/04/2015 LearningJavaScriptDesignPatterns

Inthischapter,weexploredseveraltimesavingdesignpatternsandbestpracticesthatcanbeemployed
toimprovehowjQuerypluginscanbewritten.Somearebettersuitedtocertainusecasesthanothers,
butIhopeonthewholethesepatternsareuseful.

Remember,whenselectingapattern,itisimportanttobepractical.Dontuseapluginpatternjustfor
thesakeofit,rather,investtimeinunderstandingtheunderlyingstructure,andestablishhowwellit
solvesyourproblemorfitsthecomponentyouretryingtobuild.

NamespacingPatterns
Inthissection,weregoingtoexplorepatternsfornamespacinginJavaScript.Namespacescanbe
consideredalogicalgroupingofunitsofcodeunderauniqueidentifier.Theidentifiercanbereferenced
inmanynamespacesandeachidentifiercanitselfcontainahierarchyofitsownnested(orsub)
namespaces.

Inapplicationdevelopment,weemploynamespacesforanumberofimportantreasons.InJavaScript,
theyhelpusavoidcollisionswithotherobjectsorvariablesintheglobalnamespace.Theyrealso
extremelyusefulforhelpingorganizeblocksoffunctionalityinacodebasesothatitcanbemoreeasily
referencedandused.

Namespacinganyseriousscriptorapplicationiscriticalasitsimportanttosafeguardourcodefrom
breakingintheeventofanotherscriptonthepageusingthesamevariableormethodnamesweare.
Withthenumberofthirdpartytagsregularlyinjectedintopagesthesedays,thiscanbeacommon
problemweallneedtotackleatsomepointinourcareers.Asawellbehavedcitizenoftheglobal
namespace,itsalsoimperativethatwebesttosimilarlynotpreventotherdevelopersscriptsexecuting
duetothesameissues.

WhilstJavaScriptdoesntreallyhavebuiltinsupportfornamespaceslikeotherlanguages,itdoeshave
objectsandclosureswhichcanbeusedtoachieveasimilareffect.

NamespacingFundamentals
NamespacescanbefoundinalmostanyseriousJavaScriptapplication.Unlesswereworkingwitha
simplecodesnippet,itsimperativethatwedoourbesttoensurethatwereimplementingnamespacing
correctlyasitsnotjustsimpletopickup,itllalsoavoidthirdpartycodeclobberingourown.The
patternswellbeexamininginthissectionare:

1. Singleglobalvariables
2. Prefixnamespacing
3. Objectliteralnotation
4. Nestednamespacing
5. ImmediatelyinvokedFunctionExpressions
6. Namespaceinjection

1.Singleglobalvariables
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 171/188
26/04/2015 LearningJavaScriptDesignPatterns

OnepopularpatternfornamespacinginJavaScriptisoptingforasingleglobalvariableasourprimary
objectofreference.Askeletonimplementationofthiswherewereturnanobjectwithfunctionsand
propertiescanbefoundbelow:

?
1 varmyApplication=(function(){
2 function(){
3 //...
4 },
5 return{
6 //...
7 }
8 })();

Althoughthisworksforcertainsituations,thebiggestchallengewiththesingleglobalvariablepattern
isensuringthatnooneelsehasusedthesameglobalvariablenameaswehaveinthepage.

2.Prefixnamespacing
Onesolutiontotheaboveproblem,asmentionedbyPeterMichaux,istouseprefixnamespacing.Itsa
simpleconceptatheart,buttheideaisweselectauniqueprefixnamespacewewishtouse(inthis
example, myApplication_ )andthendefineanymethods,variablesorotherobjectsaftertheprefixas
follows:

?
1 varmyApplication_propertyA={};
2 varmyApplication_propertyB={};
3 functionmyApplication_myMethod(){
4 //...
5 }

Thisiseffectivefromtheperspectiveofdecreasingthechancesofaparticularvariableexistinginthe
globalscope,butrememberthatauniquelynamedobjectcanhavethesameeffect.

Thisaside,thebiggestissuewiththepatternisthatitcanresultinalargenumberofglobalobjectsonce
ourapplicationstartstogrow.Thereisalsoquiteaheavyrelianceonourprefixnotbeingusedbyany
otherdevelopersintheglobalnamespace,sobecarefulifoptingtousethis.

FormoreonPetersviewsaboutthesingleglobalvariablepattern,readhisexcellentpostonthem
http://michaux.ca/articles/javascriptnamespacing.

3.Objectliteralnotation
Objectliteralnotation(whichwealsocoverinthemodulepatternsectionofthebook)canbethoughtof
asanobjectcontainingacollectionofkey:valuepairswithacolonseparatingeachpairofkeysand
valueswherekeyscanalsorepresentnewnamespaces.

?
1 varmyApplication={
2
3 //Aswe'veseen,wecaneasilydefinefunctionalityfor
4 //thisobjectliteral..
5 getInfo:function(){
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 172/188
26/04/2015 LearningJavaScriptDesignPatterns
6 //...
7 },
8
9 //butwecanalsopopulateittosupport
10 //furtherobjectnamespacescontaininganything
11 //anythingwewish:
12 models:{},
13 views:{
14 pages:{}
15 },
16 collections:{}
17 };

Onecanalsooptforaddingpropertiesdirectlytothenamespace:

1 myApplication.foo=function(){
2 return"bar";
3 }
4
5 myApplication.utils={
6 toString:function(){
7 //...
8 },
9 export:function(){
10 //...
11 }
12 }

Objectliteralshavetheadvantageofnotpollutingtheglobalnamespacebutassistinorganizingcode
andparameterslogically.Theyaretrulybeneficialifwewishtocreateeasilyreadablestructuresthat
canbeexpandedtosupportdeepnesting.Unlikesimpleglobalvariables,objectliteralsoftenalsotake
intoaccounttestsfortheexistenceofavariablebythesamenamesothechancesofcollisionoccurring
aresignificantlyreduced.

Inthenextsample,wedemonstrateanumberofdifferentwaysinwhichwecanchecktoseeifa
variable(objectorpluginnamespace)alreadyexists,definingitifitdoesnt.

?
1 //Thisdoesn'tcheckforexistenceof"myApplication"in
2 //theglobalnamespace.Badpracticeaswecaneasily
3 //clobberanexistingvariable/namespacewiththesamename
4 varmyApplication={};
5
6 //Thefollowingoptions*do*checkforvariable/namespaceexistence.
7 //Ifalreadydefined,weusethatinstance,otherwiseweassignanew
8 //objectliteraltomyApplication.
9 //
10 //Option1:varmyApplication=myApplication||{};
11 //Option2:if(!MyApplication){MyApplication={}};
12 //Option3:window.myApplication||(window.myApplication={});
13 //Option4:varmyApplication=$.fn.myApplication=function(){};
14 //Option5:varmyApplication=myApplication===undefined?{}:myApplication;

WelloftenseedevelopersoptingforOption1orOption2theyarebothstraightforwardto
understandandareequivalentintermsoftheirendresult.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 173/188
26/04/2015 LearningJavaScriptDesignPatterns

Option3assumesthatwereworkingintheglobalnamespace,butitcouldalsobewrittenas:

1 myApplication||(myApplication={});

Thisvariationassumesthat myApplication hasalreadybeeninitializedandsoitsonlyreallyusefulfora


parameter/argumentscenarioasinthefollowingexample:

?
1 functionfoo(){
2 myApplication||(myApplication={});
3 }
4
5 //myApplicationhasn'tbeeninitialized,
6 //sofoo()throwsaReferenceError
7
8 foo();
9
10 //HoweveracceptingmyApplicationasan
11 //argument
12
13 functionfoo(myApplication){
14 myApplication||(myApplication={});
15 }
16
17 foo();
18
19 //EvenifmyApplication===undefined,thereisnoerror
20 //andmyApplicationgetssetto{}correctly

Options4canbeusefulforwritingjQuerypluginswhere:

1 //Ifweweretodefineanewplugin..
2 varmyPlugin=$.fn.myPlugin=function(){...};
3
4 //Thenlaterratherthanhavingtotype:
5 $.fn.myPlugin.defaults={};
6
7 //Wecando:
8 myPlugin.defaults={};

Thisresultsinbettercompression(minification)andcansaveonscopelookups.

Option5isalittlesimilartoOption4,butisalongformwhichevaluateswhether myApplication is
undefined inlinesuchthatitsdefinedasanobjectifnot,otherwisesettoanexistingvaluefor
myApplication ifso.

Itisshownjustforthesakeofbeingthoroughbutinmostsituations,Options14willmorethansuffice
formostneeds.

Thereisofcourseagreatdealofvarianceinhowandwhereobjectliteralsareusedfororganizingand
structuringcode.ForsmallerapplicationswishingtoexposeanestedAPIforaparticularselfenclosed
module,wemayjustfindourselvesusingtheRevealingModulePattern,whichwecoveredearlierin
thebook:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 174/188
26/04/2015 LearningJavaScriptDesignPatterns
?
1 varnamespace=(function(){
2
3 //definedwithinthelocalscope
4 varprivateMethod1=function(){/*...*/},
5 privateMethod2=function(){/*...*/}
6 privateProperty1="foobar";
7
8 return{
9
10 //theobjectliteralreturnedherecanhaveasmany
11 //nesteddepthsaswewish,howeverasmentioned,
12 //thiswayofdoingthingsworksbestforsmaller,
13 //limitedscopeapplicationsinmypersonalopinion
14 publicMethod1:privateMethod1,
15
16 //nestednamespacewithpublicproperties
17 properties:{
18 publicProperty1:privateProperty1
19 },
20
21 //anothertestednamespace
22 utils:{
23 publicMethod2:privateMethod2
24 }
25 ...
26 }
27 })();

Thebenefitofobjectliteralsisthattheyofferusaveryelegantkey/valuesyntaxtoworkwith;one
wherewereabletoeasilyencapsulateanydistinctlogicorfunctionalityforourapplicationinaway
thatclearlyseparatesitfromothersandprovidesasolidfoundationforextendingourcode.

Apossibledownsidehoweveristhatobjectliteralshavethepotentialtogrowintolongsyntactic
constructs.Optingtotakeadvantageofthenestednamespacepattern(whichalsousesthesamepattern
asitsbase)

Thispatternhasanumberofotherusefulapplicationstoo.Inadditiontonamespacing,itsoftenof
benefittodecouplethedefaultconfigurationforourapplicationintoasingleareathatcanbeeasily
modifiedwithouttheneedtosearchthroughourentirecodebasejusttoalterthemobjectliteralswork
greatforthispurpose.Heresanexampleofahypotheticalobjectliteralforconfiguration:

?
1 varmyConfig={
2
3 language:"english",
4
5 defaults:{
6 enableGeolocation:true,
7 enableSharing:false,
8 maxPhotos:20
9 },
10
11 theme:{
12 skin:"a",
13 toolbars:{
14 index:"uinavigationtoolbar",
15 pages:"uicustomtoolbar"
16 }
17 }
18

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 175/188
26/04/2015 LearningJavaScriptDesignPatterns
19 }

NotethatJSONisasubsetofobjectliteralnotationandtherearereallyonlyminorsyntactical
differencesbetweenitandtheabove(e.gJSONkeysmustbestrings).Ifforanyreasononewishestouse
JSONforstoringconfigurationdatainstead(e.g.forsimplerstoragewhensendingtothebackend),feel
freeto.Formoreontheobjectliteralpattern,IrecommendreadingRebeccaMurpheysexcellentarticle
onthetopicasshecoversafewareaswedidnttouchupon.

4.Nestednamespacing
Anextensionoftheobjectliteralpatternisnestednamespacing.Itsanothercommonpatternusedthat
offersalowerriskofcollisionduetothefactthatevenifanamespacealreadyexists,itsunlikelythe
samenestedchildrendo.

Doesthislookfamiliar?

?
1 YAHOO.util.Dom.getElementsByClassName("test");

OlderversionsofYahoo!sYUIlibraryusethenestedobjectnamespacingpatternregularly.Duringmy
timeasanengineeratAOL,wealsousedthispatterninmanyofourlargerapplications.Asample
implementationofnestednamespacingmaylooklikethis:

?
1 varmyApp=myApp||{};
2
3 //performasimilarexistencecheckwhendefiningnested
4 //children
5 myApp.routers=myApp.routers||{};
6 myApp.model=myApp.model||{};
7 myApp.model.special=myApp.model.special||{};
8
9 //nestednamespacescanbeascomplexasrequired:
10 //myApp.utilities.charting.html5.plotGraph(/*..*/);
11 //myApp.modules.financePlanner.getSummary();
12 //myApp.services.social.facebook.realtimeStream.getLatest();

Note:TheabovediffersfromhowYUI3approachesnamespacingasmodulesthereuseasandboxed
APIhostobjectwithfarlessandfarshallowernamespacing.

Wecanalsoopttodeclarenewnestednamespaces/propertiesasindexedpropertiesasfollows:

1 myApp["routers"]=myApp["routers"]||{};
2 myApp["models"]=myApp["models"]||{};
3 myApp["controllers"]=myApp["controllers"]||{};

Bothoptionsarereadable,organizedandofferarelativelysafewayofnamespacingourapplicationina
similarfashiontowhatwemaybeusedtoinotherlanguages.Theonlyrealcaveathoweveristhatit
requiresourbrowsersJavaScriptenginefirstlocatingthemyAppobjectandthendiggingdownuntilit
getstothefunctionweactuallywishtouse.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 176/188
26/04/2015 LearningJavaScriptDesignPatterns

Thiscanmeananincreasedamountofworktoperformlookups,howeverdeveloperssuchasJuriy
Zaytsevhavepreviouslytestedandfoundtheperformancedifferencesbetweensingleobject
namespacingvsthenestedapproachtobequitenegligible.

5.ImmediatelyinvokedFunctionExpressions(IIFE)s
Earlierinthebook,webrieflycoveredtheconceptofanIIFE(immediatelyinvokedfunctionexpression)
whichiseffectivelyanunnamedfunction,immediatelyinvokedafteritsbeendefined.Ifitsounds
familiaritsbecauseyoumayhavepreviouscomeacrossitreferredtoasaselfexecuting(orself
invoked)anonymousfunction,howeverIpersonallyfeelBenAlmansIIFEnamingismoreaccurate.In
JavaScript,becausebothvariablesandfunctionsexplicitlydefinedwithinsuchacontextmayonlybe
accessedinsideofit,functioninvocationprovidesaneasymeanstoachievingprivacy.

IIFEsareapopularapproachtoencapsulatingapplicationlogictoprotectitfromtheglobalnamespace
butalsohavetheiruseintheworldofnamespacing.

ExamplesofIIFEscanbefoundbelow:

1 //an(anonymous)immediatelyinvokedfunctionexpression
2 (function(){/*...*/})();
3
4 //anamedimmediatelyinvokedfunctionexpression
5 (functionfoobar(){/*..*/})();

Examplesofselfexecutingfunctions,whicharequitedifferentthanIIFEs,canbefoundbelow:

1 //namedselfexecutingfunction
2 functionfoobar(){foobar();}
3
4 //anonymousselfexecutingfunction
5 varfoobar=function(){arguments.callee();}

BacktotheIIFEs,aslightlymoreexpandedversionofthefirstIIFEexamplemightlooklike:

?
1 varnamespace=namespace||{};
2
3 //hereanamespaceobjectispassedasafunction
4 //parameter,whereweassignpublicmethodsand
5 //propertiestoit
6 (function(o){
7 o.foo="foo";
8 o.bar=function(){
9 return"bar";
10 };
11 })(namespace);
12
13 console.log(namespace);

Whilstreadable,thisexamplecouldbesignificantlyexpandedontoaddresscommondevelopment
concernssuchasdefinedlevelsofprivacy(public/privatefunctionsandvariables)aswellasconvenient
namespaceextension.Letsgothroughsomemorecode:

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 177/188
26/04/2015 LearningJavaScriptDesignPatterns
?
1 //namespace(ournamespacename)andundefinedarepassedhere
2 //toensure1.namespacecanbemodifiedlocallyandisn't
3 //overwrittenoutsideofourfunctioncontext
4 //2.thevalueofundefinedisguaranteedasbeingtruly
5 //undefined.Thisistoavoidissueswithundefinedbeing
6 //mutablepreES5.
7
8 ;(function(namespace,undefined){
9
10 //privateproperties
11 varfoo="foo",
12 bar="bar";
13
14 //publicmethodsandproperties
15 namespace.foobar="foobar";
16
17 namespace.say=function(msg){
18 speak(msg);
19 };
20
21 namespace.sayHello=function(){
22 namespace.say("helloworld");
23 };
24
25 //privatemethod
26 functionspeak(msg){
27 console.log("Yousaid:"+msg);
28 };
29
30 //checktoevaluatewhether"namespace"existsinthe
31 //globalnamespaceifnot,assignwindow.namespacean
32 //objectliteral
33
34 })(window.namespace=window.namespace||{});
35
36
37 //wecanthentestourpropertiesandmethodsasfollows
38
39 //public
40
41 //Outputs:foobar
42 console.log(namespace.foobar);
43
44 //Outputs:Yousaid:helloworld
45 namespace.sayHello();
46
47 //assigningnewproperties
48 namespace.foobar2="foobar";
49
50 //Outputs:foobar
51 console.log(namespace.foobar2);

ExtensibilityisofcoursekeytoanyscalablenamespacingpatternandIIFEscanbeusedtoachievethis
quiteeasily.Inthebelowexample,ournamespaceisonceagainpassedasanargumenttoour
anonymousfunctionandisthenextended(ordecorated)withfurtherfunctionality:

?
1 //let'sextendthenamespacewithnewfunctionality
2 (function(namespace,undefined){
3
4 //publicmethod
5 namespace.sayGoodbye=function(){
6 namespace.say("goodbye");
7 }
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 178/188
26/04/2015 LearningJavaScriptDesignPatterns
8 })(window.namespace=window.namespace||{});
9
10 //Outputs:goodbye
11 namespace.sayGoodbye();

Ifyouwouldliketofindoutmoreaboutthispattern,IrecommendreadingBensIIFEpostformore
information.

6.Namespaceinjection
NamespaceinjectionisanothervariationontheIIFEwhereweinjectthemethodsandpropertiesfora
specificnamespacefromwithinafunctionwrapperusingthisasanamespaceproxy.Thebenefitthis
patternoffersiseasyapplicationoffunctionalbehaviourtomultipleobjectsornamespacesandcan
comeinusefulwhenapplyingasetofbasemethodstobebuiltonlater(e.g.gettersandsetters).

Thedisadvantagesofthispatternarethattheremaybeeasierormoreoptimalapproachestoachieving
thisgoal(e.g.deepobjectextension/merging)whichIcoverearlierinthesection.

Belowwecanseeanexampleofthispatterninaction,whereweuseittopopulatethebehaviourfortwo
namespaces:oneinitiallydefined(utils)andanotherwhichwedynamicallycreateasapartofthe
functionalityassignmentforutils(anewnamespacecalledtools).

?
1 varmyApp=myApp||{};
2 myApp.utils={};
3
4 (function(){
5 varval=5;
6
7 this.getValue=function(){
8 returnval;
9 };
10
11 this.setValue=function(newVal){
12 val=newVal;
13 }
14
15 //alsointroduceanewsubnamespace
16 this.tools={};
17
18 }).apply(myApp.utils);
19
20 //injectnewbehaviourintothetoolsnamespace
21 //whichwedefinedviatheutilitiesmodule
22
23 (function(){
24 this.diagnose=function(){
25 return"diagnosis";
26 }
27 }).apply(myApp.utils.tools);
28
29 //note,thissameapproachtoextensioncouldbeapplied
30 //toaregularIIFE,byjustpassinginthecontextas
31 //anargumentandmodifyingthecontextratherthanjust
32 //"this"
33
34 //Usage:
35
36 //Outputsourpopulatednamespace

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 179/188
26/04/2015 LearningJavaScriptDesignPatterns
37 console.log(myApp);
38
39 //Outputs:5
40 console.log(myApp.utils.getValue());
41
42 //Setsthevalueof`val`andreturnsit
43 myApp.utils.setValue(25);
44 console.log(myApp.utils.getValue());
45
46 //Testinganotherleveldown
47 console.log(myApp.utils.tools.diagnose());

AngusCrollhasalsopreviouslysuggestedtheideaofusingthecallAPItoprovideanaturalseparation
betweencontextsandarguments.Thispatterncanfeelalotmorelikeamodulecreator,butasmodules
stillofferanencapsulationsolution,wellbrieflycoveritforthesakeofthoroughness:

?
1 //defineanamespacewecanuselater
2 varns=ns||{},
3 ns2=ns2||{};
4
5 //themodule/namespacecreator
6 varcreator=function(val){
7
8 varval=val||0;
9
10 this.next=function(){
11 returnval++
12 };
13
14 this.reset=function(){
15 val=0;
16 }
17 }
18
19 creator.call(ns);
20
21 //ns.next,ns.resetnowexist
22 creator.call(ns2,5000);
23
24 //ns2containsthesamemethods
25 //buthasanoverriddenvalueforval
26 //of5000

Asmentioned,thistypeofpatternisusefulforassigningasimilarbasesetoffunctionalitytomultiple
modulesornamespaces.Iwouldhoweveronlyreallysuggestusingitwhereexplicitlydeclaring
functionalitywithinanobject/closurefordirectaccessdoesntmakesense.

Advancednamespacingpatterns
WellnowexploresomeadvancedpatternsandutilitiesthatIhavefoundinvaluablewhenworkingon
largerapplicationssomeofwhichhaverequiredarethinkoftraditionalapproachestoapplication
namespacing.IllnotethatIamnotadvocatinganyofthefollowingasthewaytonamespace,butrather
waysthatIhavefoundworkinpractice.

Automatingnestednamespacing

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 180/188
26/04/2015 LearningJavaScriptDesignPatterns

Aswevereviewed,nestednamespacescanprovideanorganizedhierarchyofstructureforaunitof
code.Anexampleofsuchanamespacecouldbethefollowing:application.utilities.drawing.canvas.2d.This
canalsobeexpandedusingtheobjectliteralpatterntobe:

?
1 varapplication={
2 utilities:{
3 drawing:{
4 canvas:{
5 2d:{
6 //...
7 }
8 }
9 }
10 }
11 };

Oneoftheobviouschallengeswiththispatternisthateachadditionallayerwewishtocreaterequires
yetanotherobjecttobedefinedasachildofsomeparentinourtoplevelnamespace.Thiscanbecome
particularlylaboriouswhenmultipledepthsarerequiredasourapplicationincreasesincomplexity.

Howcanthisproblembebettersolved?InJavaScriptPatterns,StoyanStefanovpresentsaveryclever
approachforautomaticallydefiningnestednamespacesunderanexistingglobalvariable.Hesuggestsa
conveniencemethodthattakesasinglestringargumentforanest,parsesthisandautomatically
populatesourbasenamespacewiththeobjectsrequired.

Themethodhesuggestsusingisthefollowing,whichIveupdatedittobeagenericfunctionforeasier
reusewithmultiplenamespaces:

?
1 //toplevelnamespacebeingassignedanobjectliteral
2 varmyApp=myApp||{};
3
4 //aconveniencefunctionforparsingstringnamespacesand
5 //automaticallygeneratingnestednamespaces
6 functionextend(ns,ns_string){
7 varparts=ns_string.split("."),
8 parent=ns,
9 pl;
10
11 pl=parts.length;
12
13 for(vari=0;i<pl;i++){
14 //createapropertyifitdoesn'texist
15 if(typeofparent[parts[i]]==="undefined"){
16 parent[parts[i]]={};
17 }
18
19 parent=parent[parts[i]];
20 }
21
22 returnparent;
23 }
24
25 //Usage:
26 //extendmyAppwithadeeplynestednamespace
27 varmod=extend(myApp,"modules.module2");
28
29 //thecorrectobjectwithnesteddepthsisoutput
30 console.log(mod);
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 181/188
26/04/2015 LearningJavaScriptDesignPatterns
31
32 //minortesttochecktheinstanceofmodcanalso
33 //beusedoutsideofthemyAppnamesapceasaclone
34 //thatincludestheextensions
35
36 //Outputs:true
37 console.log(mod==myApp.modules.module2);
38
39 //furtherdemonstrationofeasiernestednamespace
40 //assignmentusingextend
41 extend(myApp,"moduleA.moduleB.moduleC.moduleD");
42 extend(myApp,"longer.version.looks.like.this");
43 console.log(myApp);

Webinspectoroutput:

Whereonewouldpreviouslyhavehadtoexplicitlydeclarethevariousnestsfortheirnamespaceas
objects,thiscannowbeeasilyachievedusingasingle,cleanerlineofcode.

Dependencydeclarationpattern
Werenowgoingtoexploreaminoraugmentationtothenestednamespacingpatternwhichwellrefer
toastheDependencyDeclarationpattern.Weallknowthatlocalreferencestoobjectscandecrease
overalllookuptimes,butletsapplythistonamespacingtoseehowitmightlookinpractice:

1 //commonapproachtoaccessingnestednamespaces
2 myApp.utilities.math.fibonacci(25);
3 myApp.utilities.math.sin(56);
4 myApp.utilities.drawing.plot(98,50,60);
5
6 //withlocal/cachedreferences
7 varutils=myApp.utilities,
8 maths=utils.math,
9 drawing=utils.drawing;
10
11 //easiertoaccessthenamespace

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 182/188
26/04/2015 LearningJavaScriptDesignPatterns
12 maths.fibonacci(25);
13 maths.sin(56);
14 drawing.plot(98,50,60);
15
16 //notethattheaboveisparticularlyperformantwhen
17 //comparedtohundredsorthousandsofcallstonested
18 //namespacesvs.alocalreferencetothenamespace

Workingwithalocalvariablehereisalmostalwaysfasterthanworkingwithatoplevelglobal
(e.g.myApp).Itsalsobothmoreconvenientandmoreperformantthanaccessingnestedproperties/sub
namespacesoneverysubsequentlineandcanimprovereadabilityinmorecomplexapplications.

Stoyanrecommendsdeclaringlocalizednamespacesrequiredbyafunctionormoduleatthetopofour
functionscope(usingthesinglevariablepattern)andcallsthisadependencydeclarationpattern.One
ofthebenefitsthisoffersisadecreaseinlocatingdependenciesandresolvingthem,shouldwehavean
extendablearchitecturethatdynamicallyloadsmodulesintoournamespacewhenrequired.

Inmyopinionthispatternworksbestwhenworkingatamodularlevel,localizinganamespacetobe
usedbyagroupofmethods.Localizingnamespacesonaperfunctionlevel,especiallywherethereis
significantoverlapbetweennamespacedependencieswouldbesomethingIwouldrecommend
avoidingwherepossible.Instead,defineitfurtherupandjusthavethemallaccessthesamereference.

Deepobjectextension
Analternativeapproachtoautomaticnamespacingisdeepobjectextension.Namespacesdefinedusing
objectliteralnotationmaybeeasilyextended(ormerged)withotherobjects(ornamespaces)suchthat
thepropertiesandfunctionsofbothnamespacescanbeaccessibleunderthesamenamespacepost
merge.

ThisissomethingthatsbeenmadefairlyeasytoaccomplishwithmodernJavaScriptframeworks(e.g.
seejQuerys$.extend),however,iflookingtoextendobject(namespaces)usingvanillaJS,thefollowing
routinemaybeofassistance.

1 //extend.js
2 //WrittenbyAndrewDupont,optimizedbyAddyOsmani
3
4 functionextend(destination,source){
5
6 vartoString=Object.prototype.toString,
7 objTest=toString.call({});
8
9 for(varpropertyinsource){
10 if(source[property]&&objTest===toString.call(source[property])){
11 destination[property]=destination[property]||{};
12 extend(destination[property],source[property]);
13 }else{
14 destination[property]=source[property];
15 }
16 }
17 returndestination;
18
19 };
20
21 console.group("objExtendnamespacingtests");
22
http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 183/188
26/04/2015 LearningJavaScriptDesignPatterns
23 //defineatoplevelnamespaceforusage
24 varmyNS=myNS||{};
25
26 //1.extendnamespacewitha"utils"object
27 extend(myNS,{
28 utils:{
29 }
30 });
31
32 console.log("test1",myNS);
33 //myNS.utilsnowexists
34
35 //2.extendwithmultipledepths(namespace.hello.world.wave)
36 extend(myNS,{
37 hello:{
38 world:{
39 wave:{
40 test:function(){
41 //...
42 }
43 }
44 }
45 }
46 });
47
48 //testdirectassignmentworksasexpected
49 myNS.hello.test1="thisisatest";
50 myNS.hello.world.test2="thisisanothertest";
51 console.log("test2",myNS);
52
53 //3.whatifmyNSalreadycontainsthenamespacebeingadded
54 //(e.g."library")?wewanttoensurenonamespacesarebeing
55 //overwrittenduringextension
56
57 myNS.library={
58 foo:function(){}
59 };
60
61 extend(myNS,{
62 library:{
63 bar:function(){
64 //...
65 }
66 }
67 });
68
69 //confirmedthatextendisoperatingsafely(asexpected)
70 //myNSnowalsocontainslibrary.foo,library.bar
71 console.log("test3",myNS);
72
73
74 //4.whatifwewantedeasieraccesstoaspecificnamespacewithouthaving
75 //totypethewholenamespaceouteachtime?
76
77 varshorterAccess1=myNS.hello.world;
78 shorterAccess1.test3="helloagain";
79 console.log("test4",myNS);
80
81 //success,myApp.hello.world.test3isnow"helloagain"
82
83 console.groupEnd();

Note:Theaboveimplementationisnotcrossbrowsercompatibleforallobjectsandshouldbe
consideredaproofofconceptonly.OnemayfindtheUnderscore.js extend() methodasimpler,more

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 184/188
26/04/2015 LearningJavaScriptDesignPatterns

crossbrowserimplementationtostartwith
http://documentcloud.github.com/underscore/docs/underscore.html#section67.Alternatively,aversion
ofthejQuery$.extend()methodextractedfromcorecanbefoundhere:
https://github.com/addyosmani/jquery.parts.

FordevelopersthataregoingtousejQueryintheirapplication,onecanachievetheexactsameobject
namespaceextensibilitywith $.extend asfollows:

?
1 //toplevelnamespace
2 varmyApp=myApp||{};
3
4 //directlyassignanestednamespace
5 myApp.library={
6 foo:function(){
7 //...
8 }
9 };
10
11 //deepextend/mergethisnamespacewithanother
12 //tomakethingsinteresting,let'ssayit'sanamespace
13 //withthesamenamebutwithadifferentfunction
14 //signature:$.extend(deep,target,object1,object2)
15 $.extend(true,myApp,{
16 library:{
17 bar:function(){
18 //...
19 }
20 }
21 });
22
23 console.log("test",myApp);
24 //myAppnowcontainsbothlibrary.foo()andlibrary.bar()methods
25 //nothinghasbeenoverwrittenwhichiswhatwe'rehopingfor.

Forthesakeofthoroughness,pleaseseehereforjQuery$.extendequivalentstotherestofthe
namespacingexperimentsfoundinthissection.

Recommendation
Reviewingthenamespacepatternsweveexploredinthissection,theoptionthatIwouldpersonallyuse
formostlargerapplicationsisnestedobjectnamespacingwiththeobjectliteralpattern.Wherepossible,
Iwouldimplementthisusingautomatednestednamespacing,howeverthisisjustapersonal
preference.

IIFEsandsingleglobalvariablesmayworkfineforapplicationsinthesmalltomediumrange,however,
largercodebasesrequiringbothnamespacesanddeepsubnamespacesrequireasuccinctsolutionthat
promotesreadabilityandscales.Ifeelthispatternachievesalloftheseobjectiveswell.

Iwouldalsorecommendtryingoutsomeofthesuggestedadvancedutilitymethodsfornamespace
extensionastheyreallycansaveustimeinthelongrun.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 185/188
26/04/2015 LearningJavaScriptDesignPatterns

Conclusions
ThatsitforthisintroductoryadventureintotheworldofdesignpatternsinJavaScriptandjQueryI
hopeyouvefounditbeneficial.

Designpatternsmakeiteasyforustobuildontheshouldersofdeveloperswhohavedefinedsolutions
tochallengingproblemsandarchitecturesoveranumberofdecades.Thecontentsofthisbookshould
hopefullyprovidesufficientinformationtogetstartedusingthepatternswecoveredinyourown
scripts,pluginsandwebapplications.

Itsimportantforustobeawareofthesepatternsbutitsalsoessentialtoknowhowandwhentouse
them.Studytheprosandconsofeachpatternbeforeemployingthem.Takethetimeouttoexperiment
withpatternstofullyappreciatewhattheyofferandmakeusagejudgementsbasedonapatternstrue
valuetoyourapplication.

IfIveencouragedyourinterestinthisareafurtherandyouwouldliketolearnmoreaboutdesign
patterns,thereareanumberofexcellenttitlesonthisareaavailableforgenericsoftwaredevelopment
andofcourse,JavaScript.

Iamhappytorecommend:

1. PatternsOfEnterpriseApplicationArchitecturebyMartinFowler
2. JavaScriptPatternsbyStoyanStefanov

ThanksforreadingLearningJavaScriptDesignPatterns.Formoreeducationalmaterialonlearning
JavaScript,pleasefeelfreetoreadmorefrommeonmyblogathttp://addyosmani.comoronTwitter
@addyosmani.

Untilnexttime,theverybestofluckwithyouradventuresinJavaScript!

References
1. DesignPrinciplesandDesignPatternsRobertC
Martinhttp://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf
2. RalphJohnsonSpecialIssueofACMOnPatternsandPatternLanguages
http://www.cs.wustl.edu/~schmidt/CACMeditorial.html
3. HillsideEngineeringDesignPatternsLibraryhttp://hillside.net/patterns/
4. ProJavaScriptDesignPatternsRossHarmesandDustinDiazhttp://jsdesignpatterns.com/
5. DesignPatternDefinitionshttp://en.wikipedia.org/wiki/Design_Patterns

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 186/188
26/04/2015 LearningJavaScriptDesignPatterns

6. PatternsandSoftwareTerminologyhttp://www.cmcrossroads.com/bradapp/docs/patterns
intro.html
7. ReapthebenefitsofDesignPatternsJeffJudayhttp://articles.techrepublic.com.com/5100
10878_115173591.html
8. JavaScriptDesignPatternsSubramanyanGuhan
http://www.slideshare.net/rmsguhan/javascriptdesignpatterns
9. WhatAreDesignPatternsandDoINeedThem?JamesMoaoriello
http://www.developer.com/design/article.php/1474561
gobacktothecode.
10. SoftwareDesignPatternsAlexBarnett
http://alexbarnett.net/blog/archive/2007/07/20/softwaredesignpatterns.aspx
11. EvaluatingSoftwareDesignPatternsGunniRodehttp://www.rode.dk/thesis/
12. SourceMakingDesignPatternshttp://sourcemaking.com/design_patterns
13. TheSingletonPrototyp.icalhttp://prototyp.ical.ly/index.php/2007/03/01/javascriptdesign
patterns1thesingleton/
14. JavaScriptPatternsStoyanStevanovhttp://www.slideshare.net/stoyan/javascriptpatterns
15. StackOverflowDesignPatternImplementationsinJavaScript(discussion)
http://stackoverflow.com/questions/24642/whataresomeexamplesofdesignpattern
implementationsusingjavascript
16. TheElementsofaDesignPatternJaredSpool
http://www.uie.com/articles/elements_of_a_design_pattern/
17. StackOverflowExamplesofPracticalJSDesignPatterns(discussion)
http://stackoverflow.com/questions/3722820/examplesofpracticaljavascriptobjectoriented
designpatterns
18. DesignPatternsinJavaScriptPart1NicholasZakas
http://www.webreference.com/programming/javascript/ncz/column5/
19. StackOverflowDesignPatternsinjQuery
http://stackoverflow.com/questions/3631039/designpatternsusedinthejquerylibrary
20. ClassifyingDesignPatternsByAntiClueElyseNeilson
http://www.anticlue.net/archives/000198.htm
21. DesignPatterns,PatternLanguagesandFrameworksDouglasSchmidt
http://www.cs.wustl.edu/~schmidt/patterns.html
22. ShowLoveToTheModulePatternChristianHeilmannhttp://www.waittill
i.com/2007/07/24/showlovetothemodulepattern/
23. SoftwareDesignsMadeSimpleAnoopMashudanan
http://www.scribd.com/doc/16352479/SoftwareDesignPatternsMadeSimple
24. JavaScriptDesignPatternsKlausKomendahttp://www.klauskomenda.com/code/javascript
programmingpatterns/
25. IntroductiontotheJavaScriptModulePatternhttps://www.unleashed
technologies.com/blog/2010/12/09/introductionjavascriptmoduledesignpattern
26. DesignPatternsExplainedhttp://c2.com/cgi/wiki?DesignPatterns
27. Mixinsexplainedhttp://en.wikipedia.org/wiki/Mixin
28. WorkingwithGoFsDesignPatternsInJavaScript
http://aspalliance.com/1782_Working_with_GoFs_Design_Patterns_in_JavaScript_Programm
ing.all
29. UsingObject.createhttp://stackoverflow.com/questions/2709612/usingobjectcreateinstead
ofnew
30. t3knomanstersJavaScriptDesignPatternshttp://t3knomanser.livejournal.com/922171.html

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 187/188
26/04/2015 LearningJavaScriptDesignPatterns

31. WorkingwithGoFDesignPatternsInJavaScriptProgramming
http://aspalliance.com/1782_Working_with_GoFs_Design_Patterns_in_JavaScript_Programm
ing.7
32. JavaScriptAdvantagesObjectLiterals
http://stackoverflow.com/questions/1600130/javascriptadvantagesofobjectliteral
33. JavaScriptClassPatternsLiamMcLennan
http://geekswithblogs.net/liammclennan/archive/2011/02/06/143842.aspx
34. UnderstandingproxiesinjQuery
http://stackoverflow.com/questions/4986329/understandingproxyinjquery
35. ObserverPatternUsingJavaScripthttp://www.codeproject.com/Articles/13914/Observer
DesignPatternUsingJavaScript
36. SpeakingontheObserverpatternhttp://www.javaworld.com/javaworld/javaqa/200105/04
qa0525observer.html
37. SingletonexamplesinJavaScriptHardcode.nl
http://www.hardcode.nl/subcategory_1/article_526singletonexamplesinjavascript.htm

LearningJavaScriptDesignPatterns.AddyOsmani2015.

http://addyosmani.com/resources/essentialjsdesignpatterns/book/ 188/188

Você também pode gostar