["state\tbefore\tyou\tcontinue. Your\ttransition\tis\tnice,\tbut\tthere\tis\ta\tsmall\tbug.\tCurrently,\tthe\thover\teffect\tcauses\tparts\tof the\tthumbnail\tto\tbe\tcut\toff.\tThis\tis\tbecause\tthe\ttransform\tapplied\tto\tthe\t.thumbnail- item\tdoes\tnot\tcause\tits\tparent\tto\tadjust\tits\tsize.\tThe\tsolution\tis\tto\tadd\ta\tbit\tof\tpadding\tto the\t.thumbnail-list.\tChange\tthe\tvertical\tpadding\tfor\t.thumbnail-list\tin styles.css. ... .thumbnail-list\t{ \t\tflex:\t0\t1\tauto; \t\torder:\t2; \t\tdisplay:\tflex; \t\tjustify-content:\tspace-between; \t\tlist-style:\tnone; \t\tpadding:\t0; \t\tpadding:\t20px\t0; \t\twhite-space:\tnowrap; \t\toverflow-x:\tauto; } ... You\tused\tthe\tshorthand\tfor\tthe\tpadding\tproperty.\tThe\tfirst\tvalue,\t20px,\tapplies\tto\tthe\ttop and\tbottom\tpadding,\twhile\tthe\tsecond\tvalue\tapplies\tto\tthe\tleft\tand\tright\tpadding.\tMake\ta similar\tadjustment\tinside\tyour\t@media\tquery,\tbut\tadd\tan\textra\tpadding\tof\t35px\tto\tthe\tleft and\tright. ... @media\tall\tand\t(min-width:\t768px)\t{ \t\t.main-content\t{ \t\t... \t\t} \t\t.thumbnail-list\t{ \t\t\t\tflex-direction:\tcolumn; \t\t\t\torder:\t0; \t\t\t\tmargin-left:\t20px; \t\t\t\tpadding:\t0\t35px; \t\t} \t\t... Save\tand\tcheck\tthe\tresults\tin\tyour\tbrowser.\tThis\tproduces\ta\tnicer\teffect\tfor\tthe\tthumbnails (Figure\t7.17). Figure\t7.17\t\tExtra\troom\tfor\tthe\thover\teffect\tin\tportrait\tand\tlandscape Using\ta\ttiming\tfunction Your\thover\teffect\tis\tlooking\tgood!\tBut\tit\tlacks\tthat\tvisual\tpop\tthat\twould\tmake\tit\treally special.\tWith\tCSS\ttransitions,\tyou\tcan\tnot\tonly\tspecify\thow\tmuch\ttime\ta\ttransition\tshould take,\tbut\talso\tmake\tit\ttransition\tat\tdifferent\tspeeds\tduring\tthat\ttime. There\tare\tseveral\ttiming\tfunctions\tthat\tyou\tcan\tuse\twith\ttransitions.\tBy\tdefault,\tthe\tlinear","timing\tfunction\tis\tused,\twhich\tmakes\tthe\ttransition\tanimate\tat\ta\tsingle,\tconstant\trate.\tThe others\tare\tmore\tinteresting,\tand\tgive\tthe\ttransition\tthe\tfeeling\tof\tspeeding\tup\tor\tslowing down. Update\tyour\ttransition\tin\tstyles.css\tso\tthat\tit\tuses\tthe\tease-in-out\ttiming\tfunction. This\twill\tmake\tthe\trate\tof\tthe\ttransition\tslower\tat\tthe\tbeginning\tand\tend\tand\tfaster\tin\tthe middle. ... .thumbnail-item\t{ \t\tdisplay:\tinline-block; \t\tmin-width:\t120px; \t\tmax-width:\t120px; \t\tborder:\t1px\tsolid\trgb(100%,\t100%,\t100%); \t\tborder:\t1px\tsolid\trgba(100%,\t100%,\t100%,\t0.8); \t\ttransition:\ttransform\t133ms\tease-in-out; } ... Save\tand\tthen\thover\tover\tone\tof\tyour\tthumbnails.\tThe\teffect\tis\tsubtle,\tbut\tnoticeable. There\tare\ta\tnumber\tof\ttiming\tfunctions\tavailable.\tSee\tthe\tlist\ton\tthe\tMDN\tat developer.mozilla.org\/e\u200b n-US\/\u200bdocs\/\u200bWeb\/C\u200b SS\/t\u200b ransition-timing- function. Your\ttransition\tuses\tthe\tsame\tduration\tvalue\tand\ttiming\tfunction\tfor\tboth\tthe\ttransition to\tthe\tend\tstate\tand\tthe\ttransition\tfrom\tthe\tend\tstate.\tThat\tdoes\tnot\thave\tto\tbe\tthe\tcase\t\u2013 you\tcan\tuse\tdifferent\tvalues\tdepending\ton\tthe\tdirection\tof\tthe\ttransition.\tIf\tyou\tspecify\ta transition\tproperty\ton\tboth\tthe\tbeginning-state\tdeclaration\tand\tthe\tend-state\tdeclaration, the\tbrowser\tuses\tthe\tvalue\tof\tthe\tdeclaration\tit\tis\tmoving\ttoward. It\tmight\tbe\teasier\tto\tsee\tthis\tin\taction.\tFor\ta\tquick\tdemonstration,\tadd\ta\ttransition declaration\tto\t.thumbnail-item:hover\tin\tstyles.css.\t(You\twill\tdelete\tit\tafter\ttrying\tit out\tin\tthe\tbrowser.) ... .thumbnail-item:hover\t{ \t\ttransform:\tscale(1.2); \t\ttransition:\ttransform\t1000ms\tease-in; } ... Save\tand\tagain\thover\tover\tone\tof\tthe\tthumbnails\tin\tthe\tbrowser.\tThe\tscaling\teffect\twill\tbe very\tslow,\ttaking\ta\tfull\tsecond\tto\tcomplete.\tThis\tis\tbecause\tit\tis\tusing\tthe\tvalue\tdeclared for\t.thumbnail-item:hover.\tNow,\tmove\tyour\tmouse\toff\tof\tthe\tthumbnail.\tThis\ttime,\tthe transition\ttakes\t133\tmilliseconds,\tthe\tvalue\tdeclared\tfor\t.thumbnail-item. Remove\tthe\ttransition\tdeclaration\tfrom\t.thumbnail-item:hover\tbefore\tyou\tcontinue. ... .thumbnail-item:hover\t{ \t\ttransform:\tscale(1.2); \t\ttransition:\ttransform\t1000ms\tease-in; } ... Transition\ton\tclass\tchange Your\tsecond\ttransition\twill\tmake\tthe\t.detail-image-frame\tlook\tlike\tit\tis\tzooming\tin from\tvery\tfar\taway. Instead\tof\tusing\ta\tpseudo-class\tselector\tto\ttrigger\ta\ttransition,\tthis\ttime\tyou\twill\tadd\tand remove\tclass\tnames\twith\tJavaScript\tto\ttrigger\ta\ttransition.\tWhy?\tBecause\tthere\tis\tno","pseudo-class\tthat\tcorresponds\tto\ta\tclick\tevent.\tUsing\tJavaScript\tgives\tyou\tmuch\tmore control\tover\thow\tand\twhen\tthese\tUI\tchanges\tare\ttriggered. Also,\tyou\twill\tset\tdifferent\tduration\ttimes\tfor\tthe\tbeginning\tand\tend\tof\tthe\ttransition.\tThe end\tresult\twill\tbe\tthat\twhen\tyou\tclick\ta\tthumbnail\tthe\tcorresponding\totter\timage\twill\tbe used\tfor\tthe\tdetail\timage.\tIt\twill\timmediately\tbe\tsized\tdown\tto\ta\ttiny\tdot\tin\tthe\tcenter\tof the\tdetail\tarea,\tthen\tit\twill\ttransition\tto\tits\tfull\tsize\t(Figure\t7.18). Figure\t7.18\t\tClicking\ta\tthumbnail\tscales\tit\tfrom\tvery\tsmall\tto\tfull\tsize Start\tby\tadding\ta\tstyle\tdeclaration\tfor\ta\tnew\tclass\tnamed\tis-tiny\tin\tstyles.css. ... .detail-image-frame\t{ \t\t... } .is-tiny\t{ \t\ttransform:\tscale(0.001); \t\ttransition:\ttransform\t0ms; } .detail-image\t{ \t\t... You\tadded\ttwo\tstyles\tfor\t.is-tiny.\tThe\tfirst\tscales\tthe\telement\tdown\tto\ta\tsmall\tfraction of\tits\toriginal\tsize.\tThe\tsecond\tspecifies\tthat\tany\ttransition\tfor\tthe\ttransform\tproperty should\tlast\t0\tmilliseconds,\tapplying\tthe\tstyle\tchange\timmediately.\tPut\tanother\tway,\tgoing toward\tthe\t.is-tiny\tclass\tstyles,\tthe\tdetail\timage\twill\teffectively\thave\tno\ttransition. Because\tit\tlasts\tfor\t0\tmilliseconds,\tthere\tis\tno\tneed\tto\tspecify\ta\ttiming\tfunction. Next,\tyou\twill\tadd\tanother\ttransition\tdeclaration\twith\ta\t333\tmillisecond\tduration.\tThis value\twill\tbe\tused\twhen\ttransitioning\taway\tfrom\tthe\t.is-tiny\tclass,\tmaking\tthe\tdetail image\tgrow\tto\tnormal\tsize\tover\ta\tperiod\tof\ta\tthird\tof\ta\tsecond.\tAdd\tthis\ttransition declaration\tto\tthe\t.detail-image-frame\tin\tstyles.css. ... .detail-image-frame\t{ \t\tposition:\trelative; \t\ttext-align:\tcenter; \t\ttransition:\ttransform\t333ms; } ... Save\tstyles.css\tbefore\tyou\tmove\ton. Triggering\ttransitions\twith\tJavaScript Now\tthat\tyour\ttransition\tstyles\tare\tin\tplace,\tyou\tneed\tto\ttrigger\tthem\twith\tJavaScript.\tTo give\tyour\tJavaScript\ta\thook,\tadd\ta\tdata\tattribute\tto\tthe\t.detail-image-frame\telement\tin","index.html. ... \t\t\t\t\t\t<div\tclass=\\\"detail-image-container\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"detail-image-frame\\\"\tdata-image-role=\\\"frame\\\"> \t\t\t\t<img\tclass=\\\"detail-image\\\"\tdata-image-role=\\\"target\\\"\tsrc=\\\"img\/otter1.jpg\\\"\talt=\\\"\\\"> \t\t\t\t<span\tclass=\\\"detail-image-title\\\"\tdata-image-role=\\\"title\\\">Stayin'\tAlive<\/span> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> ... Save\tindex.html.\tNow,\tin\tmain.js,\tyou\tjust\tneed\tto\tadd\tvariables\tfor\tyour\t.is-tiny class\tand\tdata-image-role=\\\"frame\\\"\tselector,\tand\tthen\tyou\twill\tupdate\tshowDetails to\tperform\tthe\tclass\tname\tchanges\tto\tthat\ttrigger\tthe\ttransition. Begin\twith\tthe\tvariables.\tAdd\ta\tDETAIL_FRAME_SELECTOR\tvariable\tfor\ta\tselector\tstring '[data-image-role=\\\"frame\\\"]'.\tAlso,\tadd\ta\tTINY_EFFECT_CLASS\tvariable\tfor\tthe\tis-tiny class\tname. var\tDETAIL_IMAGE_SELECTOR\t=\t'[data-image-role=\\\"target\\\"]'; var\tDETAIL_TITLE_SELECTOR\t=\t'[data-image-role=\\\"title\\\"]'; var\tDETAIL_FRAME_SELECTOR\t=\t'[data-image-role=\\\"frame\\\"]'; var\tTHUMBNAIL_LINK_SELECTOR\t=\t'[data-image-role=\\\"trigger\\\"]'; var\tHIDDEN_DETAIL_CLASS\t=\t'hidden-detail'; var\tTINY_EFFECT_CLASS\t=\t'is-tiny'; var\tESC_KEY\t=\t27; ... It\tis\tnot\trequired\tthat\tyou\tput\tyour\tvariables\tin\tthis\torder.\t(It\tmakes\tno\tdifference\tto\tthe browser.)\tBut\tit\tis\ta\tgood\tidea\tto\tkeep\tthem\torganized.\tIn\tmain.js,\tall\tof\tthe\tselector variables\tare\tgrouped\ttogether,\tfollowed\tby\tthe\tclass\tvariables,\tfollowed\tby\tthe\tnumeric code\tfor\tthe\tEscape\tkey. Now,\tupdate\tshowDetails\tin\tmain.js\tso\tthat\tit\tgets\ta\treference\tto\tthe\t[data-image- role=\\\"frame\\\"]\telement.\tTo\ttrigger\tthe\ttransition,\tyou\twill\tneed\tto\tadd\tthe TINY_EFFECT_CLASS\tand\tremove\tit. ... function\tshowDetails()\t{ \t\t'use\tstrict'; \t\tvar\tframe\t=\tdocument.querySelector(DETAIL_FRAME_SELECTOR); \t\tdocument.body.classList.remove(HIDDEN_DETAIL_CLASS); \t\tframe.classList.add(TINY_EFFECT_CLASS); \t\tframe.classList.remove(TINY_EFFECT_CLASS); } ... If\tyou\tsaved\tthis\tand\ttried\tit\tin\tthe\tbrowser,\tyou\twould\tnot\tsee\ta\ttransition\ttake\tplace. Why\tnot?\tBecause\tthe\tTINY_EFFECT_CLASS\tis\tadded\tand\tthen\timmediately\tremoved.\tThe net\tresult\tis\tthat\tthere\tis\tno\tactual\tclass\tchange\tto\trender.\tThis\tis\tan\toptimization\ton\tthe part\tof\tthe\tbrowser. You\tneed\tto\tadd\ta\tsmall\tdelay\tbefore\tremoving\tthe\tTINY_EFFECT_CLASS.\tJavaScript, however,\tdoes\tnot\thave\ta\tbuilt-in\tdelay\tor\tsleep\tfunction,\tas\tsome\tother\tlanguages\tdo. Time\tfor\ta\tworkaround! You\tare\tgoing\tto\tuse\tthe\tsetTimeout\tmethod,\twhich\ttakes\ta\tfunction\tand\ta\tdelay (specified\tin\tmilliseconds).\tAfter\tthe\tdelay,\tthe\tfunction\tis\tqueued\tfor\texecution\tby\tthe browser. Add\ta\tcall\tto\tsetTimeout\tafter\tcalling\tframe.classList.add\tin\tmain.js.\tPass it\ttwo\targuments:\ta\tfunction\twith\ta\tlist\tof\tsteps\tto\tperform\tand\tthe\tnumber\tof\tmilliseconds to\twait\tbefore\tinvoking\tthat\tfunction\targument.\tThere\tis\tonly\tone\tstep\tto\tperform,\tand\tthat is\tto\tremove\tTINY_EFFECT_CLASS. ... function\tshowDetails()\t{","'use\tstrict'; \t\tvar\tframe\t=\tdocument.querySelector(DETAIL_FRAME_SELECTOR); \t\tdocument.body.classList.remove(HIDDEN_DETAIL_CLASS); \t\tframe.classList.add(TINY_EFFECT_CLASS); \t\tsetTimeout(function\t()\t{ \t\t\t\tframe.classList.remove(TINY_EFFECT_CLASS); \t\t},\t50); } ... Let\u2019s\ttake\ta\tcloser\tlook\tat\twhat\tthis\tcode\tdoes.\tFirst,\tit\tadds\tthe\t.is-tiny\tclass\tto\tthe frame\telement.\tThis\tapplies\tyour\ttransform:\tscale(0.001). Then,\tthe\tbrowser\tis\ttold\tto\twait\t50\tmilliseconds,\tafter\twhich\tit\twill\tadd\tan\tanonymous function\tto\tits\texecution\tqueue.\tThe\tshowDetails\tfunction\tfinishes.\tFifty\tmilliseconds later,\tthe\tanonymous\tfunction\tis\tqueued\tfor\texecution.\t(Basically,\tit\tgets\tin\tline\tfor\tthe CPU,\twaiting\tbehind\tany\tother\tfunctions\tthat\twere\talready\tin\tline.) When\tthis\tanonymous\tfunction\truns,\tit\tremoves\tthe\tTINY_EFFECT_CLASS\tfrom\tthe\tframe\u2019s class\tlist.\tThis\tcauses\tthe\ttransform\ttransition\tto\trun\tover\ta\tperiod\tof\t333\tmilliseconds, making\tthe\tframe\tgrow\tto\tits\tnormal\tsize. Save\tyour\tchanges\tand\tadmire\tthe\tresults.\tClick\tthe\tthumbnails\tand\tenjoy\tthose\twacky otters\tzooming\tinto\tview.","Custom\tTiming\tFunctions Now,\tfor\tsome\ticing\ton\tyour\tOttergram\tcake:\tYou\tcan\tcreate\tcustom\ttiming\tfunctions\tfor your\ttransitions\tinstead\tof\tbeing\tlimited\tto\tthe\tbuilt-in\tones. Timing\tfunctions\tcan\tbe\tgraphed\tto\tshow\tthe\ttransition\u2019s\tprogress\tover\ttime.\tGraphs\tof the\tbuilt-in\ttiming\tfunctions\t(from\tthe\tsite\tcubic-bezier.com)\tare\tshown\tin Figure\t7.19. Figure\t7.19\t\tBuilt-in\ttiming\tfunctions The\tshapes\tin\tthese\tgraphs\tare\tknown\tas\tcubic\tBezier\tcurves.\tThe\tlines\tin\tthe\tgraphs describe\tthe\tbehavior\tof\tthe\tanimation\tover\ttime.\tThey\tare\tdefined\tby\tfour\tpoints.\tYou\tcan create\tcustom\ttransitions\tby\tspecifying\tthe\tfour\tpoints\tthat\tdefine\ta\tcurve.\tTry\tthe following\tcubic-bezier\tas\tpart\tof\tyour\ttransition\tdeclaration\tfor\t.detail-image- frame\tin\tstyles.css. ... .detail-image-frame\t{ \t\tposition:\trelative; \t\ttext-align:\tcenter; \t\ttransition:\ttransform\t333m\tcubic-bezier(1,.06,.28,1); } ... Save\tit\tand\tclick\ton\tsome\tthumbnails\tin\tthe\tbrowser\tto\tsee\tthe\tdifference\tin\tthe\ttransition. Thanks\tto\tdeveloper\tLea\tVerou\tand\ther\tsite\tcubic-bezier.com,\tcreating\tcustom timing\tfunctions\tis\tpainless\t(Figure\t7.20).","Figure\t7.20\t\tCreating\ta\tcustom\ttiming\tfunction\twith\tcubic-bezier.com On\tthe\tleft\tside\tis\ta\tcurve\twith\tred\tand\tblue\tdrag\thandles.\tThe\tcurve\tis\ta\tgraph\tof\thow much\tof\tthe\ttransition\thas\toccurred\tover\tthe\tduration.\tClick\tand\tdrag\tthe\thandles\tto change\tthe\tcurve.\tAs\tit\tchanges,\tthe\tdecimal\tvalues\tat\tthe\ttop\tof\tthe\tpage\tchange,\ttoo. On\tthe\tright\tside\tare\tthe\tbuilt-in\ttiming\tfunctions:\tease,\tlinear,\tease-in,\tease-out,\tand ease-in-out.\tClick\ton\tone,\tthen\ton\tthe\tGO!\tbutton\tnext\tto\tPreview\t&\tcompare.\tThe\ticons representing\tthe\ttwo\ttiming\tfunctions\t\u2013\tthe\tcustom\tcubic-bezier\tand\tthe\tbuilt-in\tfunction \u2013\twill\tanimate,\tallowing\tyou\tto\tsee\tyour\tcustom\ttiming\tin\taction\tand\tcompare\tit\tto\ta\tbuilt- in\toption. Create\ta\tcustom\ttiming\tfunction\tand,\twhen\tyou\tare\thappy\twith\tit,\tcopy\tand\tpaste\tthe values\tfrom\tthe\twebsite\tto\tyour\tcode\tin\tstyles.css: ... .detail-image-frame\t{ \t\tposition:\trelative; \t\ttext-align:\tcenter; \t\ttransition:\ttransform\t333m\tcubic-bezier(your\tvalues\there); } ... Congratulations!\tOttergram\tis\tfeature-complete!\tSave\tyour\tfile\tand\tadmire\tyour\tfinished product.\tYou\thave\ttaken\tOttergram\tfrom\ta\tsimple,\tstatic\tweb\tpage\tto\tan\tinteractive, responsive\tpage\twith\tanimated\tvisual\teffects. You\thave\tcome\ta\tlong\tway,\tand\thopefully\tyou\thave\tenjoyed\tlearning\tabout\tthe\tbasics\tof front-end\tdevelopment.\tIt\tis\ttime\tto\twave\tgoodbye\tto\tthe\totters,\tbecause\tyou\twill\tbe starting\ta\tnew\tproject\tin\tthe\tnext\tchapter.","For\tthe\tMore\tCurious:\tRules\tfor\tType\tCoercion As\tmentioned\tin\tChapter\t6,\tJavaScript\twas\toriginally\tcreated\tso\tthat\tfolks\twho\twere\tnot professional\tprogrammers\tcould\tadd\tinteractivity\tto\tweb\tpages.\tIt\twas\tthought\tthat\tthese \u201cregular\thumans\u201d\tshould\tnot\tneed\tto\tworry\tabout\twhether\ta\tvalue\twas\ta\tnumber,\tan object,\tor\ta\tbanana.\t(Just\tkidding\t\u2013\tthere\tis\tno\tbanana\ttype\tin\tJavaScript.) One\tof\tthe\tways\tthis\tis\tachieved\tis\tthrough\ttype\tcoercion.\tWith\ttype\tcoercion,\tyou\tcan compare\ttwo\tvalues,\tregardless\tof\ttheir\ttypes,\tusing\tthe\t==\toperator\tand\tconcatenate\ttwo values\tusing\tthe\t+\toperator.\tWhen\tyou\tdo,\tJavaScript\twill\tfigure\tout\ta\tway\tto\tmake\tthat work\t\u2013\teven\tif\tit\thas\tto\tdo\tsomething\ta\tlittle\tweird,\tlike\tchanging\tthe\tstring\t\\\"2\\\"\tto\tthe number\t2. This\thas\tmystified\tprogrammers\tand\tnonprogrammers\talike.\tMost\tprogrammers\tagree\tthat it\tis\tbest\tto\tuse\tstrict\tcomparison\tusing\tthe\t===\toperator.\tHowever,\tthe\trules\tfor\ttype coercion\tare\tvery\twell\tdefined\tin\tthe\tlanguage,\tand\tthey\tare\tworth\tknowing\tabout. Let\u2019s\tsay\tyou\tare\ttrying\tto\tcompare\ttwo\tvariables:\tx\t==\ty.\tIf\tthey\tare\tthe\tsame\ttype\tand have\tthe\tsame\tvalue,\tthe\tcomparison\tresults\tin\ta\tBoolean\ttrue.\tThe\tonly\texception\tto\tthis is:\tIf\teither\tx\tor\ty\thave\tthe\tvalue\tNaN\t(the\tlanguage\tconstant\tmeaning\t\u201cnot\ta\tnumber\u201d), then\tthe\tresult\tis\tfalse. However,\tif\tx\tand\ty\tare\tdifferent\ttypes,\tthings\tget\ta\tbit\ttricky.\tHere\tare\tsome\tof\tthe\trules JavaScript\tapplies: These\tcomparisons\tresult\tin\ttrue:\tnull\t==\tundefined\tand\tundefined\t==\tnull. When\tcomparing\ta\tstring\tand\ta\tnumber,\tfirst\tconvert\tthe\tstring\tto\tits\tnumerical equivalent.\tThis\tmeans\tthat\t\\\"3\\\"\t==\t3\tis\ttrue,\tand\t\\\"dog\\\"\t==\t20\tis\tfalse. When\tcomparing\ta\tBoolean\tto\tanother\ttype,\tfirst\tconvert\tthe\tBoolean\tto\ta number:\ttrue\tto\tthe\tnumber\t1,\tand\tfalse\tto\tthe\tnumber\t0.\tThis\tmeans\tthat\tfalse ==\t0\tis\ttrue,\tand\ttrue\t==\t1\tis\talso\ttrue. Finally,\tif\tyou\tcompare\ta\tstring\tor\ta\tnumber\tto\tan\tobject,\tfirst\ttry\tto\tconvert\tthe object\tto\ta\tprimitive\tvalue.\tIf\tthat\tconversion\tdoes\tnot\twork,\tthen\ttry\tconverting the\tobject\tto\ta\tstring. For\teven\tmore\tinformation,\tcheck\tout\tthe\tMDN\u2019s\tdiscussion\tat developer.mozilla.org\/e\u200b n-US\/\u200bdocs\/W\u200b eb\/\u200bJavaScript\/\u200b Equality_comparisons_and_sameness.","Part\tII\t Modules,\tObjects,\tand\tForms","8\t Modules,\tObjects,\tand\tMethods Over\tthe\tnext\tseven\tchapters,\tyou\twill\tbuild\ta\tshopping-cart\tstyle\tapplication\tcalled CoffeeRun\tto\tmanage\tcoffee\torders\tfor\ta\tfood\ttruck.\tYou\twill\tcreate\tCoffeeRun\tin\tthree layers\tof\tcode:\tthe\tUI,\tthe\tinternal\tlogic,\tand\tthe\tserver\tcommunication. In\tthis\tchapter,\tyou\twill\tcreate\tthe\tinternal\tlogic\tand\tinteract\twith\tit\tthrough\tthe\tDevTools console,\tas\tshown\tin\tFigure\t8.1. Figure\t8.1\t\tCoffeeRun,\tunder\tthe\thood Modules CoffeeRun\tis\tmore\tcomplex\tthan\tOttergram,\tso\tit\tis\timportant\tto\torganize\tyour\tcode\tto make\tit\teasier\tto\tdebug\tand\tto\textend.\tCoffeeRun\twill\tbe\tstructured\tin\tcomponents,\twhich are\tdiagrammed\tin\tFigure\t8.2.","Figure\t8.2\t\tOverview\tof\tcomponents\tand\tinteractions\tin\tCoffeeRun Each\tpart\tof\tthe\tapplication\twill\tfocus\ton\tone\tarea\tof\tresponsibility.\tThe\tcode\tfor\tyour application\u2019s\tinternal\tlogic\twill\tmanage\tthe\tdata.\tThe\tUI\tcode\twill\thandle\tevents\tand DOM\tmanipulation\t(much\tlike\tthe\tcode\tfor\tOttergram).\tThe\tserver\tcommunication\tcode will\ttalk\tto\ta\tremote\tserver,\tsaving\tand\tretrieving\tdata\tover\tthe\tnetwork. JavaScript\twas\tcreated\tfor\twriting\tvery\tsmall\tscripts\tthat\tadd\ttiny\tbits\tof\tinteractivity,\tnot for\twriting\tcomplex\tapplications.\tCoffeeRun\tis\tnot\textremely\tcomplex,\tbut\tit\tbreaks\tthe threshold\tfor\twhat\tshould\tbe\taccomplished\tin\ta\tsingle\tscript\tfile. To\tkeep\tyour\tcode\tneatly\tseparated,\tyou\twill\tcreate\tthree\tJavaScript\tfiles\tfor\tthe\tsubsets\tof functionality\twithin\tyour\tapplication.\tYou\twill\thave\tdifferent\tfiles\tfor\tyour\tinternal\tlogic, your\tUI,\tand\tyour\tserver\tcommunication\tcode.\tYou\twill\tachieve\tthis\tseparation\tby\twriting your\tcode\tin\tseparate\tunits,\tor\tmodules. How\tto\tgroup\tcode\tinto\tmodules\tis\tentirely\tup\tto\tthe\tdeveloper.\tMost\toften,\tcode\tis grouped\taround\tconcepts,\tlike\t\u201cinventory\u201d\tor\t\u201cfood\tmenu.\u201d\tIn\tterms\tof\tcode,\tmodules group\trelated\tfunctions\ttogether.\tSome\tof\tthe\tfunctions\twill\tbe\tavailable\texternally,\twhile others\twill\tonly\tbe\tused\tinternally\tby\tthe\tmodule. Think\tabout\ta\trestaurant.\tThe\tkitchen\thas\tlots\tof\ttools\tand\tingredients\tthat\tare\tavailable internally,\tbut\tthe\tcustomers\tonly\tsee\ta\tmenu\twith\ta\tfew\titems.\tThat\tmenu\tis\tthe customer\u2019s\tinterface\tto\tthe\tfood-making\tmodule\tcalled\tthe\tkitchen. Likewise,\tif\tthe\trestaurant\thas\ta\tbar,\tthe\tdrink-making\ttools\tand\tingredients\tare\tinternal; the\tcustomer\tcan\tonly\taccess\tthe\titems\ton\tthe\tdrink\tlist,\twhich\tis\ttheir\tinterface\tto\tthe drink-making\tmodule\tcalled\tthe\tbar. As\ta\tcustomer,\tyou\tcannot\tborrow\tthe\tbutcher\u2019s\tknife\tfrom\tthe\tkitchen\tor\tuse\tthe\tblender from\tthe\tbar.\tYou\tcannot\tgrab\tan\textra\tpat\tof\tbutter\tfrom\tthe\trefrigerator\tor\tpour\tan\textra shot\tin\tyour\tcocktail.\tYou\tare\trestricted\tto\tthe\tinterfaces\tprovided\tby\tthe\tkitchen\tand\tbar modules. Similarly,\teach\tof\tCoffeeRun\u2019s\tmodules\twill\tkeep\tsome\tof\tits\tfunctionality\tprivate.\tOnly\ta portion\tof\tits\tfunctionality\twill\tbe\tmade\tpublicly\taccessible,\tso\tthat\tother\tmodules\tcan interact\twith\tit. For\tCoffeeRun,\tyou\twill\tcontinue\tto\twork\tin\tES5,\twhich\tis\tthe\tbest-supported\tversion\tof JavaScript\tas\tof\tthis\twriting.\t(Your\tnext\tproject,\tChattrbox,\twill\tuse\tthe\tmost\trecent version,\tES6).\tES5\tdoes\tnot\thave\ta\tformal\tway\tto\torganize\tcode\tinto\tself-contained modules,\tbut\tyou\tcan\tget\tthe\tsame\tkind\tof\torganization\tby\tputting\trelated\tcode\t(variables and\tfunctions)\tinside\tthe\tbody\tof\ta\tfunction.","The\tmodule\tpattern Code\tcan\tbe\torganized\tusing\tfunctions,\tbut\tit\tis\ta\tcommon\tpractice\tto\tuse\ta\tvariation\tof\ta regular\tfunction\tfor\tthis\tpurpose.\tBefore\tyou\tget\tstarted\twith\tyour\tnew\tproject,\tlet\u2019s\ttake\ta brief\tlook\tat\tthe\tmodule\tpattern\tfor\torganizing\tcode,\texamining\thow\ta\tfunction\tfrom Ottergram\tcould\tbe\trewritten\tas\ta\tmodule. Here\tis\tthe\tcode\tfor\ta\tbasic\tmodule: (function\t()\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there })(); If\tthis\tis\tthe\tfirst\ttime\tyou\thave\tseen\tthis\tpattern,\tit\tprobably\tlooks\trather\todd.\tThis\tis known\tas\tan\timmediately\tinvoked\tfunction\texpression\t(or\tIIFE),\tand\tit\tis\tbest\tto\texamine\tit from\tthe\tinside\tout. The\tmain\tpart\tof\tit\tis\tthe\tanonymous\tfunction: function\t()\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there } You\tworked\twith\tanonymous\tfunctions\tin\tOttergram,\tso\tthis\tshould\tbe\tfamiliar. Here,\thowever,\tthe\tanonymous\tfunction\tis\tenclosed\tin\tparentheses: (function\t()\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there }) These\tenclosing\tparentheses\tare\tvery\timportant\tbecause\tthey\ttell\tthe\tbrowser,\t\u201cPlease\tdo not\tinterpret\tthis\tcode\tas\ta\tfunction\tdeclaration.\u201d The\tbrowser\tsees\tthe\tparentheses\tand\tsays,\t\u201cAh.\tOK.\tI\tget\tthat\tI\tam\tlooking\tat\tan anonymous\tfunction.\tI\twill\thold\toff\tfrom\tdoing\tanything\twith\tit.\u201d Most\tof\tthe\ttime,\tyou\tuse\tan\tanonymous\tfunction\tby\tpassing\tit\tas\tan\targument.\tIn\tthis case,\tyou\tare\tcalling\tit\timmediately.\tThis\tis\tdone\twith\tthe\tempty\tpair\tof\tparentheses: (function\t()\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there })() When\tthe\tbrowser\tsees\tthe\tempty\tparentheses,\tit\trealizes\tthat\tyou\twant\tit\tto\tinvoke whatever\tcomes\tbefore\tthem,\tand\tsays,\t\u201cOh!\tI\tsee\tthat\tI\u2019ve\tgot\tan\tanonymous\tfunction that\tI\tcan\trun!\u201d You\tmay\tbe\tthinking,\t\u201cThis\tis\tboth\tcrazy\tand\tuseless.\u201d\tActually,\tyou\thave\talready\twritten code\tthat\tworks\tsimilarly.\tRecall\tOttergram\u2019s\tinitializeEvents\tfunction.\tAfter\tyou declared\tit,\tyou\tcalled\tit\timmediately\tand\tnever\tcalled\tit\tagain.\tHere\tis\tthat\tcode\tfor reference. function\tinitializeEvents()\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/\tFunction\tdeclared \t\t'use\tstrict'; \t\tvar\tthumbnails\t=\tgetThumbnailsArray(); \t\tthumbnails.forEach(addThumbClickHandler); \t\taddKeyPressHandler(); } initializeEvents();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\/\/\tFunction\tcalled The\tpurpose\tof\tthis\tfunction\twas\tto\tbundle\tsome\tsteps\ttogether\tand\trun\tthem\twhen\tthe","page\tloads.\tHere\tis\tthat\tsame\tcode,\trewritten\tas\tan\tIIFE.\t(You\tdo\tnot\tneed\tto\tchange\tyour Ottergram\tcode;\tthis\tis\tjust\tto\tillustrate\tthe\tconcept.) function\tinitializeEvents()\t{ (function\t()\t{ \t\t'use\tstrict'; \t\tvar\tthumbnails\t=\tgetThumbnailsArray(); \t\tthumbnails.forEach(addThumbClickHandler); \t\taddKeyPressHandler(); } })(); initializeEvents(); IIFEs\tare\tuseful\twhen\tyou\twant\tto\trun\tsome\tcode\tonce\twithout\tcreating\tany\textra\tglobal variables\tor\tfunctions.\tTo\tunderstand\twhy\tthis\tis\timportant,\tconsider\tthe\tvariables\tand functions\tyou\twrote\tfor\tOttergram. In\tOttergram,\tyou\tbuilt\tup\ta\tcollection\tof\tuseful\tfunctions\tand\tthen\tcalled\tthem\tas\tneeded. These\tfunctions\thad\tnames\tlike\tgetThumbnailsArray\tand addKeyPressHandler.\tLuckily,\tthese\tnames\twere\tunique.\tIf\tyou\thad\ttried\tto\tdefine two\tfunctions\twith\tthe\tsame\tname,\tthe\tfirst\tone\twould\thave\tsimply\tbeen\treplaced\tby\tthe second\tone. When\tyou\tdefine\tfunctions\tor\tvariables,\tthey\tare\tadded\tto\tthe\tglobal\tnamespace\tby default.\tThis\tis\tthe\tbrowser\u2019s\tregistry\tof\tall\tof\tthe\tfunction\tand\tvariable\tnames\tfor\tyour JavaScript\tprogram,\talong\twith\tany\tbuilt-in\tfunctions\tand\tvariables.\tMore\tgenerally,\ta namespace\tis\tthe\tmeans\tby\twhich\tcode\tis\torganized:\tCode\tis\torganized\tin\tnamespaces\tthe same\tway\tfiles\ton\tyour\tcomputer\tare\torganized\tin\tfolders. In\tCoffeeRun,\tyou\tmay\thave\tfunctions\tthat\tcould\treasonably\thave\tthe\tsame\tname,\tlike add\tor\taddClickHandler.\tInstead\tof\tadding\tthem\tto\tthe\tglobal\tnamespace,\twhere they\tcould\tbe\taccidentally\toverwritten,\tyou\tcan\tdeclare\tthem\tinside\tof\ta\tfunction.\tThis protects\tthem\tfrom\tbeing\taccessed\tor\toverwritten\tby\tcode\toutside\tof\tthe\tfunction. As\tyou\tgroup\tcode\ttogether\tin\ta\tmodule,\tyou\twill\twant\tto\tmake\tsome,\tbut\tnot\tall,\tof\tthe functionality\taccessible\tto\tthe\tworld\toutside\tof\tthe\tmodule.\tTo\tdo\tthis,\tyou\twill\ttake advantage\tof\tthe\tfact\tthat\tIIFEs,\tlike\tany\tfunction,\tcan\taccept\targuments. Modifying\tan\tobject\twith\tan\tIIFE IIFEs\tare\tnot\tonly\tgood\tfor\trunning\tset-up\tcode,\tlike\tOttergram\u2019s\tinitializeEvents. They\tare\talso\tgood\tfor\trunning\tcode\tthat\taugments\tan\tobject,\twhich\tis\tusually\tpassed\tin\tas an\targument.\tTo\tillustrate\thow\tthis\tworks,\tour\tfriend\tinitializeEvents\twill\tbe\tused once\tagain. Here\tis\ta\tversion\tof\tinitializeEvents\twhose\tjob\tis\tto\tmodify\tthe\tthumbnails\tby adding\ta\tclick\thandler.\t(To\tsimplify\tthings,\tthe\taddKeyPressHandler\tcall\thas\tbeen removed.) function\tinitializeEvents()\t{ \t\t'use\tstrict'; \t\tvar\tthumbnails\t=\tgetThumbnailsArray(); \t\tthumbnails.forEach(addThumbClickHandler); } initializeEvents(); In\tthis\tform,\tinitializeEvents\tmodifies\tan\tarray\tof\tthumbnails\tusing","addThumbClickHandler.\tBut\tit\tcould\talso\treceive\tthe\tarray\tas\tan\targument.\tTo\tdo that,\tyou\twould\tdeclare\ta\tparameter\tas\tpart\tof\tthe\tfunction\tdefinition.\tThen,\twhen\tyou\tcall it,\tyou\twould\tpass\tin\tthe\tarray,\tlike\tthis: function\tinitializeEvents(thumbnails)\t{ \t\t'use\tstrict'; \t\tvar\tthumbnails\t=\tgetThumbnailsArray(); \t\tthumbnails.forEach(addThumbClickHandler); } var\tthumbnails\t=\tgetThumbnailsArray(); initializeEvents(thumbnails); To\trewrite\tthis\tas\tan\tIIFE,\tyou\twould\tremove\tthe\tfunction\tname,\twrap\tthe\tfunction\tin parentheses,\tand\tadd\ta\tpair\tof\tempty\tparentheses\tto\tinvoke\tthe\tfunction: (function\tinitializeEvents(thumbnails)\t{ \t\t'use\tstrict'; \t\tthumbnails.forEach(addThumbClickHandler); })(); var\tthumbnails\t=\tgetThumbnailsArray(); initializeEvents(thumbnails); However,\tyou\twould\tstill\tneed\tto\tpass\tin\tthe\tarray\tof\tthumbnails\tas\tan\targument.\tYou\tcan do\tthis\tby\tmoving\tthe\tcall\tto\tgetThumbnailsArray.\tInstead\tof\tassigning\tthe\tresult\tto a\tvariable,\tyou\twould\tpass\tthe\tresult\tto\tyour\tIIFE: (function\t(thumbnails)\t{ \t\t'use\tstrict'; \t\tthumbnails.forEach(addThumbClickHandler); })(getThumbnailsArray()); var\tthumbnails\t=\tgetThumbnailsArray(); In\tthis\tversion\tof\tthe\tcode,\tan\tarray\t(resulting\tfrom\tcalling\tgetThumbnailsArray)\tis passed\tin\tto\tthe\tIIFE.\tThe\tIIFE\treceives\tthis\tarray\tand\tplaces\tthe\tlabel\tthumbnails\ton it.\tInside\tthe\tbody\tof\tthe\tIIFE,\tthe\tevent\tlisteners\tare\tattached\tto\teach\titem\tin\tthe\tarray (Figure\t8.3). Figure\t8.3\t\tIIFE\tmodifying\tits\targuments Anything\tcan\tbe\tpassed\tto\tan\tIIFE\tfor\tmodification.\tYour\tCoffeeRun\tIIFEs\twill\tbe\tpassed the\twindow\tobject.\tBut\tinstead\tof\tattaching\ttheir\tmodule\tcode\tdirectly\tto\tthe\tglobal namespace,\tthey\twill\tattach\tcode\tto\ta\tsingle\tApp\tproperty\twithin\tthe\tglobal\tnamespace. Every\tCoffeeRun\tmodule\twill\tbe\tcontained\tin\tits\town\tfile\tand\tloaded\tinto\tthe\tbrowser\tby an\tindividual\t<script>\ttag.\tAn\toverview\tof\tthis\tprocess\tis\tshown\tin\tFigure\t8.4.","Figure\t8.4\t\t<script>\ttags\tload\tmodules,\twhich\tmodify\twindow.App","Setting\tUp\tCoffeeRun Enough\ttheory\t\u2013\tlet\u2019s\tget\tto\twork.\tBecause\tthis\tis\ta\tnew\tproject,\tstart\tby\tcreating\ta\tnew directory.\tOpen\tAtom\tand\tchoose\tFile\t\u2192\tAdd\tProject\tFolder\u2026.\tSelect\tyour\tfront-end- dev-book\tdirectory\tand\tclick\tNew\tFolder.\tName\tthe\tnew\tfolder\tcoffeerun\tand\tclick Open. Next,\tControl-click\t(right-click)\tyour\tnew\tcoffeerun\tfolder\tin\tAtom\u2019s\tnavigation\tpanel. Choose\tNew\tFile\tand\tenter\tindex.html\tfor\tthe\tfilename.\tControl-click\t(right-click)\ton coffeerun\tagain\tand\tchoose\tNew\tFolder.\tName\tthe\tfolder\tscripts. In\tyour\tfront-end-dev-book\tfolder,\tyou\tshould\tnow\thave\ta\tfolder\tfor\teach\tof\tyour projects,\tottergram\tand\tcoffeerun,\twith\tsimilar\tfile\tstructures\t(Figure\t8.5). Figure\t8.5\t\tCreating\tfiles\tand\tfolders\tfor\tCoffeeRun If\tyou\talready\thave\ta\tterminal\tsession\topen\tand\trunning\tbrowser-sync,\tclose\tbrowser- sync\tusing\tControl-C.\tIf\tyou\tdo\tnot,\topen\ta\tnew\tterminal\twindow.\tEither\tway,\tchange\tto your\tnew\tcoffeerun\tdirectory\t(refer\tto\tthe\tcommands\tin\tChapter\t1\tif\tyou\tare\tnot\tsure about\thow\tto\tdo\tthis)\tand\tstart\tbrowser-sync\tagain.\tAs\ta\treminder,\tthe\tcommand\tto\tstart it\tis\tbrowser-sync\tstart\t--server\t--files\t\\\"stylesheets\/*.css,\tscripts\/*.js, *.html\\\". In\tindex.html\tadd\tthe\tbasic\tskeleton\tof\tyour\tdocument.\t(Remember,\tAtom\u2019s autocomplete\twill\tdo\tmost\tof\tthis\tfor\tyou;\tjust\tstart\ttyping\t\u201chtml.\u201d) <!doctype\thtml> <html> \t\t<head> \t\t\t\t<meta\tcharset=\\\"utf-8\\\"> \t\t\t\t<title>coffeerun<\/title> \t\t<\/head> \t\t<body> \t\t<\/body> <\/html>","You\tare\tnow\tready\tto\tcreate\tyour\tfirst\tmodule!","Creating\tthe\tDataStore\tModule The\tfirst\tmodule\tyou\twill\twrite\twill\tstore\tcoffee\torder\tinformation\tin\ta\tsimple\tdatabase, not\tunlike\twriting\tdown\tthe\torders\tby\thand.\tEach\torder\twill\tbe\tstored\tby\tthe\tcustomer\u2019s email\taddress.\tTo\tget\tstarted,\tyou\twill\tonly\tkeep\ttrack\tof\ta\ttext\tdescription\tof\tthe\torder, like\t\u201cquadruple\tespresso\u201d\t(Figure\t8.6). Figure\t8.6\t\tInitial\tstructure\tof\tCoffeeRun\u2019s\tdatabase Later,\tyou\twill\talso\tkeep\ttrack\tof\tthe\tsize,\tflavor,\tand\tcaffeine\tstrength\tof\teach\tcoffee order.\tThe\tcustomer\u2019s\temail\taddress\twill\tserve\tas\tthe\tunique\tidentifier\tfor\tthe\tentire\torder, so\tall\tof\tthe\torder\tdetails\twill\tbe\tassociated\twith\ta\tsingle\temail\taddress.\t(Sorry,\tcoffee addicts!\tOnly\tone\torder\tper\tcustomer.) Create\ta\tnew\tfile\tcalled\tscripts\/datastore.js.\tNext,\tin\tindex.html,\tadd\tthe <script>\ttag\tto\tinclude\tthe\tnew\tfile\tin\tyour\tproject. <!doctype\thtml> <html> \t\t<head> \t\t\t\t<meta\tcharset=\\\"utf-8\\\"> \t\t\t\t<title>coffeerun<\/title> \t\t<\/head> \t\t<body> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t<\/body> <\/html> Save\tindex.html.\tIn\tscripts\/datastore.js,\tbegin\twith\tthe\tbasic\tIIFE\tfor\tyour module\tstructure: (function\t(window)\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there })(window); Now\tthat\tthe\tskeleton\tof\tyour\tmodule\texists\tand\thas\ta\tcorresponding\t<script>\ttag,\tit\tis time\tto\tattach\tit\tto\tthe\tnamespace\tfor\tyour\tapplication.","Adding\tModules\tto\ta\tNamespace Many\tother\tprogramming\tlanguages\thave\tspecial\tsyntax\tfor\tcreating\tmodules\tand packaging\tthem\ttogether.\tES5\tdoes\tnot.\tInstead,\tyou\tcan\tget\tthe\tsame\tkind\tof\torganization using\tobjects. You\tcan\tuse\tobjects\tto\tassociate\tany\tkind\tof\tdata\twith\ta\tkey\tname.\tIn\tfact,\tthis\tis\tprecisely how\tyou\twill\torganize\tyour\tmodules.\tSpecifically,\tyou\twill\tuse\ta\tsingle\tobject\tas\tthe namespace\tfor\tyour\tCoffeeRun\tapplication.\tThis\tnamespace\tis\twhere\tindividual\tmodules register\tthemselves,\twhich\tmakes\tthem\tavailable\tfor\tuse\tby\tyour\tother\tapplication\tcode. There\tare\tthree\tsteps\tto\tusing\tIIFEs\tto\tregister\tmodules\tin\ta\tnamespace: 1.\t Get\ta\treference\tto\tthe\tnamespace,\tif\tit\texists. 2.\t Create\tthe\tmodule\tcode. 3.\t Attach\tyour\tmodule\tcode\tto\tthe\tnamespace. Let\u2019s\tsee\twhat\tthat\tlooks\tlike\tin\tpractice.\tUpdate\tyour\tIIFE\tin\tdatastore.js\tas\tshown. We\twill\texplain\tthe\tcode\tafter\tyou\tenter\tit. (function\t(window)\t{ \t\t'use\tstrict'; \t\t\/\/\tCode\twill\tgo\there \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tDataStore()\t{ \t\t\t\tconsole.log('running\tthe\tDataStore\tfunction'); \t\t} \t\tApp.DataStore\t=\tDataStore; \t\twindow.App\t=\tApp; })(window); In\tthe\tbody\tof\tthe\tIIFE,\tyou\tdeclared\ta\tlocal\tvariable\tnamed\tApp.\tIf\tthere\tis\talready\tan App\tproperty\tof\tthe\twindow,\tyou\tassign\tthe\tlocal\tApp\tto\tit.\tIf\tnot,\tthe\tlabel\tApp\twill\trefer to\ta\tnew,\tempty\tobject,\trepresented\tby\t{}.\tThe\t||\tis\tthe\tdefault\toperator,\totherwise known\tas\tthe\tlogical\tor\toperator.\tIt\tcan\tbe\tused\tto\tprovide\ta\tvalid\tvalue\t(in\tthis\tcase,\t{}) if\tthe\tfirst\tchoice\t(window.App)\thas\tnot\tyet\tbeen\tcreated. Each\tof\tyour\tmodules\twill\tdo\tthis\tsame\tcheck.\tIt\tis\tlike\tsaying\t\u201cWhoever\tgets\tthere\tfirst: Go\tahead\tand\tstart\ta\tnew\tobject.\tEveryone\telse\twill\tuse\tthat\tobject.\u201d Next,\tyou\tdeclared\ta\tfunction\tnamed\tDataStore.\tYou\twill\tadd\tmore\tcode\tto\tthis function\tshortly. Finally,\tyou\tattached\tDataStore\tto\tthe\tApp\tobject\tand\treassigned\tthe\tglobal\tApp property\tto\tyour\tnewly\tmodified\tApp.\t(If\tit\tdid\tnot\talready\texist\tand\tyou\thad\tto\tcreate\tit as\tan\tempty\tobject,\tyou\tmust\tattach\tit.) Save\tyour\tfiles\tand\tswitch\tover\tto\tthe\tbrowser.\tOpen\tthe\tDevTools,\tclick\ton\tthe\ttab\tfor\tthe console,\tand\tcall\tyour\tDataStore\tfunction\twith\tthe\tfollowing\tcode: App.DataStore(); DataStore\truns\tand\tprints\tsome\ttext\tto\tthe\tconsole\t(Figure\t8.7).","Figure\t8.7\t\tRunning\tthe\tApp.DataStore\tfunction Notice\tthat\tyou\tdid\tnot\tneed\tto\twrite\twindow.App.DataStore();.\tThis\tis\tbecause\tthe window\tobject\tis\tthe\tglobal\tnamespace.\tAll\tof\tits\tproperties\tare\tavailable\tto\tany\tJavaScript code\tyou\twrite,\tincluding\tin\tthe\tconsole.","Constructors IIFEs\tlet\tyou\ttake\tadvantage\tof\tfunction\tscope\tto\tcreate\tnamespaces\tto\torganize\tlarge pieces\tof\tyour\tcode.\tThere\tis\tanother\tuse\tof\tfunctions\tthat\tmakes\tthem\tact\tlike\tfactories for\tobjects\tthat\tall\thave\tsimilar\tproperties\tand\tmethods.\tIn\tother\tlanguages,\tyou\tmight\tuse a\tclass\tfor\tthis\tkind\tof\torganization.\tStrictly\tspeaking,\tJavaScript\tdoes\tnot\thave\tclasses, but\tit\tdoes\tgive\tyou\ta\tway\tto\tcreate\tcustom\ttypes. You\thave\talready\tstarted\tto\tcreate\tthe\tDataStore\ttype.\tNow\tyou\twill\tcustomize\tit\tin two\tsteps.\tIn\tthe\tfirst\tstep,\tyou\twill\tgive\tit\ta\tproperty\tthat\twill\tbe\tused\tinternally\tfor storing\tdata.\tIn\tthe\tsecond\tstep,\tyou\twill\tgive\tit\ta\tset\tof\tmethods\tfor\tinteracting\twith\tthat data.\tYou\tdo\tnot\tneed\tto\tgive\tother\tobjects\tdirect\taccess\tto\tthat\tdata,\tso\tthis\ttype\twill provide\tan\texternal\tinterface\tthrough\ta\tset\tof\tmethods. Object\tfactory\tfunctions\tare\tcalled\tconstructors\tin\tJavaScript. Add\tthe\tfollowing\tcode\tto\tthe\tbody\tof\tthe\tDataStore\tfunction\tin\tdatastore.js. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tDataStore()\t{ \t\t\t\tconsole.log('running\tthe\tDataStore\tfunction'); \t\t\t\tthis.data\t=\t{}; \t\t} \t\tApp.DataStore\t=\tDataStore; \t\twindow.App\t=\tApp; })(window); The\tjob\tof\ta\tconstructor\tis\tto\tcreate\tand\tcustomize\ta\tnew\tobject.\tInside\tthe\tbody\tof\tthe constructor,\tyou\tcan\trefer\tto\tthat\tnew\tobject\twith\tthe\tkeyword\tthis.\tYou\tused\tthe\tdot operator\tto\tcreate\ta\tproperty\tnamed\tdata\ton\tyour\tnew\tobject\tand\tassigned\tan\tempty object\tto\tdata. You\tmay\thave\tnoticed\tthat\tyou\tcapitalized\tthe\tfirst\tletter\tof\tDataStore.\tThis\tis\ta convention\tin\tJavaScript\twhen\tnaming\tconstructors.\tIt\tis\tnot\tnecessary,\tbut\tit\tis\ta\tgood practice\tas\ta\tway\tto\ttell\tother\tdevelopers\tthat\tthe\tfunction\tshould\tbe\tused\tas\ta\tconstructor. To\tdifferentiate\ta\tconstructor\tfrom\ta\tregular\tfunction,\tyou\tuse\tthe\tkeyword\tnew\twhen\tyou call\tit.\tThis\ttells\tJavaScript\tto\tcreate\ta\tnew\tobject,\tset\tup\tthe\treference\tfrom\tthis\tto\tthat new\tobject,\tand\tto\timplicitly\treturn\tthat\tobject.\tThat\tmeans\tit\twill\treturn\tthe\tobject without\tan\texplicit\treturn\tstatement\tin\tthe\tconstructor. Save\tand\treturn\tto\tthe\tconsole.\tTo\tlearn\thow\tto\tuse\ta\tconstructor,\tyou\tare\tgoing\tto\tcreate two\tDataStore\tobjects\t(or\tinstances)\tand\tadd\tvalues\tto\tthem.\tBegin\tby\tcreating\tthe instances. var\tdsOne\t=\tnew\tApp.DataStore(); var\tdsTwo\t=\tnew\tApp.DataStore(); You\tcreated\tthese\tDataStore\tinstances\tby\tcalling\tthe\tDataStore\tconstructor.\tAt\tthis point,\teach\thas\tan\tempty\tdata\tproperty.\tAdd\tsome\tvalues\tto\tthem: dsOne.data['email']\t=\t'[email protected]'; dsOne.data['order']\t=\t'black\tcoffee'; dsTwo.data['email']\t=\t'[email protected]'; dsTwo.data['order']\t=\t'chai\ttea';","Then\tinspect\tthe\tvalues: dsOne.data; dsTwo.data; The\tresults\ttell\tyou\tthat\teach\tinstance\tholds\tdifferent\tinformation\t(Figure\t8.8). Figure\t8.8\t\tSaving\tvalues\tto\tinstances\tof\tthe\tDataStore\tconstructor A\tconstructor\u2019s\tprototype Using\ta\tDataStore\tinstance,\tyou\tcan\tmanually\tstore\tand\tretrieve\tdata.\tBut,\tin\tits current\tform,\tDataStore\tis\tjust\ta\troundabout\tway\tof\tcreating\tan\tobject\tliteral,\tand\tany module\tthat\twill\tuse\ta\tDataStore\tinstance\thas\tto\tbe\tcoded\tto\tuse\tthe\tdata\tproperty directly. This\tis\tnot\tgood\tsoftware\tdesign.\tIt\twould\tbe\tbetter\tif\tDataStore\tprovided\ta\tpublic interface\tfor\tadding,\tremoving,\tand\tretrieving\tdata\t\u2013\tall\twhile\tkeeping\tthe\tdetails\tof\thow\tit works\ta\tsecret. The\tsecond\tpart\tof\tcreating\tyour\tcustom\tDataStore\ttype\tis\tto\tprovide\tthese\tmethods for\tinteracting\twith\tthe\tdata.\tThe\tgoal\tis\tfor\tthese\tmethods\tto\tserve\tas\tthe\tinterface\tthat other\tmodules\tuse\twhen\tthey\tinteract\twith\ta\tDataStore\tinstance.\tTo\taccomplish\tthis, you\twill\tmake\tuse\tof\ta\tvery\tcool\tfeature\tof\tJavaScript\tfunctions,\tthe\tprototype\tproperty. Functions\tin\tJavaScript\tare\talso\tobjects.\tThis\tmeans\tthat\tthey\tcan\thave\tproperties.\tIn JavaScript,\tall\tinstances\tcreated\tby\ta\tconstructor\thave\taccess\tto\ta\tshared\tstorehouse\tof properties\tand\tmethods:\tthe\tprototype\tproperty\tof\tthe\tconstructor. To\tcreate\tthese\tinstances,\tyou\tused\tthe\tnew\tkeyword\twhen\tyou\tcalled\tthe\tconstructor.\tThe new\tkeyword\tnot\tonly\tcreates\tyour\tinstance\tand\treturns\tit\tbut\talso\tcreates\ta\tspecial\tlink from\tthe\tinstance\tto\tthe\tconstructor\u2019s\tprototype\tproperty.\tThis\tlink\texists\tfor\tany\tinstance created\twhen\tthe\tconstructor\tis\tcreated\twith\tthe\tnew\tkeyword.","When\tyou\tadd\ta\tproperty\tto\tthe\tprototype\tand\tassign\tit\ta\tfunction,\tevery\tinstance\tyou create\twith\tthe\tconstructor\twill\thave\taccess\tto\tthat\tfunction.\tYou\tcan\tuse\tthe\tkeyword this\tinside\tof\tthe\tfunction\tbody,\tand\tit\twill\trefer\tto\tthe\tinstance. To\tsee\tthis\tin\taction,\tcreate\tthe\tadd\tfunction\tin\tdatastore.js\tas\ta\tproperty\tof\tthe prototype.\tYou\tcan\talso\tdelete\tthe\tcall\tto\tconsole.log. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tDataStore()\t{ \t\t\t\tconsole.log('running\tthe\tDataStore\tfunction'); \t\t\t\tthis.data\t=\t{}; \t\t} \t\tDataStore.prototype.add\t=\tfunction\t(key,\tval)\t{ \t\t\t\tthis.data[key]\t=\tval; \t\t}; \t\tApp.DataStore\t=\tDataStore; \t\twindow.App\t=\tApp; })(window); You\tgave\tDataStore.prototype\tthe\tproperty\tadd\tand\tyou\tassigned\ta\tfunction\tto\tit.\tThat function\ttakes\ttwo\targuments,\tkey\tand\tval.\tInside\tthe\tfunction\tbody,\tyou\tused\tthose arguments\tto\tmake\tchanges\tto\tthe\tinstance\u2019s\tdata\tproperty. In\tterms\tof\thow\tDataStore\tworks\twith\tcoffee\torders,\tit\twill\tstore\tthe\torder\tinformation (the\tval),\tusing\tthe\tcustomer\u2019s\temail\taddress\t(the\tkey). You\tare\tnot\tsetting\tup\ta\ttrue\tdatabase,\tbut\tDataStore\tworks\twell\tenough\tfor CoffeeRun.\tIt\tis\table\tto\tsave\tsome\tinformation,\tval,\tunder\tthe\tunique\tidentifier\tspecified by\tkey.\tBecause\tyou\tare\tusing\ta\tJavaScript\tobject\tfor\tstorage,\teach\tkey\tis\tguaranteed\tto\tbe a\tunique\tentry\tin\tthe\tdatabase.\t(In\ta\tJavaScript\tobject,\ta\tproperty\tname\tis\talways\tunique, like\tfunction\tnames\twithin\ta\tnamespace.\tIf\tyou\ttried\tto\tstore\tdifferent\tvalues\tusing\tthe same\tkey,\tyou\twould\tjust\toverwrite\tany\tprevious\tvalues\tfor\tthat\tkey.) This\taspect\tof\tJavaScript\tobjects\tfulfills\tthe\tone\tmajor\trequirement\tof\tany\tdatabase: keeping\tthe\tindividual\tpieces\tof\tdata\tseparate. Save\tyour\tcode\tand\tswitch\tback\tto\tthe\tbrowser.\tCreate\tan\tinstance\tof\tDataStore\tin\tthe console\tand\tuse\tits\tadd\tmethod\tto\tstore\tsome\tinformation. var\tds\t=\tnew\tApp.DataStore(); ds.add('email',\t'[email protected]'); ds.add('order',\t'triple\tespresso'); ds.data; Inspect\tthe\tdata\tproperty\tto\tconfirm\tthat\tit\tworks\t(Figure\t8.9).","Figure\t8.9\t\tCalling\ta\tprototype\tmethod Adding\tmethods\tto\tthe\tconstructor The\tnext\tthing\tto\tdo\tis\tto\tcreate\tmethods\tfor\taccessing\tthe\tdata.\tIn\tdatastore.js,\tadd a\tmethod\tto\tlook\tup\ta\tvalue\tbased\ton\ta\tgiven\tkey\tand\tone\tto\tlook\tup\tall\tkeys\tand\tvalues. ... \t\tDataStore.prototype.add\t=\tfunction\t(key,\tval)\t{ \t\t\t\tthis.data[key]\t=\tval; \t\t}; \t\tDataStore.prototype.get\t=\tfunction\t(key)\t{ \t\t\t\treturn\tthis.data[key]; \t\t}; \t\tDataStore.prototype.getAll\t=\tfunction\t()\t{ \t\t\t\treturn\tthis.data; \t\t}; \t\tApp.DataStore\t=\tDataStore; \t\twindow.App\t=\tApp; })(window); You\tcreated\ta\tget\tmethod\tthat\taccepts\ta\tkey,\tlooks\tup\tthe\tvalue\tfor\tit\tin\tthe\tinstance\u2019s data\tproperty,\tand\treturns\tit.\tYou\talso\tcreated\ta\tgetAll\tmethod.\tIt\tis\talmost\tthe\tsame, but\tinstead\tof\tlooking\tup\tthe\tvalue\tfor\ta\tsingle\tkey,\tit\treturns\ta\treference\tto\tthe\tdata property. You\tcan\tnow\tadd\tand\tretrieve\tinformation\tfrom\ta\tDataStore\tinstance.\tTo\tcomplete\tthe cycle,\tyou\tneed\tto\tadd\ta\tmethod\tfor\tremoving\tinformation.\tAdd\tthat\tto\tdatastore.js now. ... \t\tDataStore.prototype.getAll\t=\tfunction\t()\t{ \t\t\t\treturn\tthis.data; \t\t}; \t\tDataStore.prototype.remove\t=\tfunction\t(key)\t{ \t\t\t\tdelete\tthis.data[key]; \t\t}; \t\tApp.DataStore\t=\tDataStore; \t\twindow.App\t=\tApp; })(window); The\tdelete\toperator\tremoves\ta\tkey\/value\tpair\tfrom\tan\tobject\twhen\tyour\tnew\tremove method\tis\tcalled. With\tthat,\tyou\thave\tcompleted\tthe\tDataStore\tmodule,\twhich\tprovides\tthe\tmost important\tpart\tof\tthe\tCoffeeRun\tapplication.\tIt\tcan\tstore\tdata,\tprovide\tstored\tdata\tin response\tto\tqueries,\tand\tdelete\tunnecessary\tdata\ton\tcommand.","To\tsee\tall\tof\tyour\tmethods\tin\taction,\tsave\tyour\tcode\tand\tgo\tto\tthe\tconsole\tafter\tbrowser- sync\thas\treloaded\tyour\tbrowser.\tEnter\tthe\tfollowing\tcode,\twhich\texercises\tall\tof\tthe methods\tof\tDataStore: var\tds\t=\tnew\tApp.DataStore(); ds.add('[email protected]',\t'tea'); ds.add('[email protected]',\t'eshpressho'); ds.getAll(); ds.remove('[email protected]'); ds.getAll(); ds.get('[email protected]'); ds.get('[email protected]'); As\tshown\tin\tFigure\t8.10,\tDataStore\u2019s\tinstance\tmethods\tshould\tnow\twork\tas\texpected. These\tmethods\tare\texactly\tthe\tway\tthat\tother\tmodules\twill\tinteract\twith\tyour\tapplication\u2019s database. Figure\t8.10\t\tWorking\twith\tDataStore\tusing\tonly\tits\tprototype\tmethods Your\tnext\tmodule\twill\tuse\tthe\tsame\tstructure:\tan\tIIFE\twith\ta\tparameter\tfor\tthe\tnamespace to\tmodify.\tBut\tit\twill\tprovide\tcompletely\tdifferent\tfunctionality\tfrom\tDataStore.","Creating\tthe\tTruck\tModule The\tnext\tmodule\tyou\twill\twrite\tis\tthe\tTruck\tmodule,\twhich\twill\tprovide\tall\tof\tthe functionality\tfor\tmanaging\tthe\tfood\ttruck.\tIt\twill\thave\tmethods\tfor\tcreating\tand\tdelivering orders\tand\tfor\tprinting\ta\tlist\tof\tpending\torders.\tFigure\t8.11\tshows\thow\tthe\tTruck\tmodule will\twork\twith\tthe\tDataStore\tmodule. Figure\t8.11\t\tTruck\tmodule\tinteracting\twith\tDataStore\tmodule When\ta\tTruck\tinstance\tis\tcreated,\tit\tis\tgiven\ta\tDataStore\tobject.\tA\tTruck\thas methods\tfor\tworking\twith\tcoffee\torders,\tbut\tit\tshould\tnot\tneed\tto\tworry\tabout\thow\tto store\tand\tmanage\tthat\tinformation.\tInstead,\tthe\tTruck\tjust\tpasses\tthose\tduties\tto\tthe DataStore.\tFor\texample,\twhen\tyou\tcall\tthe\tTruck\u2019s\tcreateOrder\tmethod,\tit\tcalls the\tDataStore\u2019s\tadd\tmethod. Create\tthe\tscripts\/truck.js\tfile\tand\tadd\ta\t<script>\ttag\tfor\tit\tto\tindex.html. <!doctype\thtml> <html> \t\t<head> \t\t\t\t<meta\tcharset=\\\"utf-8\\\"> \t\t\t\t<title>coffeerun<\/title> \t\t<\/head> \t\t<body> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t<\/body> <\/html> Save\tindex.html.\tIn\ttruck.js,\tset\tup\tyour\tmodule\twith\tan\tIIFE\tand\ta\tconstructor for\tthe\tTruck\ttype. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tTruck()\t{ \t\t}","App.Truck\t=\tTruck; \t\twindow.App\t=\tApp; })(window); Next,\tyou\twill\tadd\tparameters\tto\tyour\tconstructor\tso\tthat\teach\tinstance\twill\thave\ta\tunique identifier\tand\tits\town\tDataStore\tinstance.\tThe\tidentifier\tis\tjust\ta\tname\tfor differentiating\tone\tTruck\tinstance\tfrom\tanother.\tThe\tDataStore\tinstance\twill\tplay\ta much\tmore\timportant\trole. Add\tthe\tnew\tparameters\tin\ttruck.js. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tfunction\tTruck(truckId,\tdb)\t{ \t\t\t\tthis.truckId\t=\ttruckId; \t\t\t\tthis.db\t=\tdb; \t\t} \t\tApp.Truck\t=\tTruck; \t\twindow.App\t=\tApp; })(window); You\tdeclared\tparameters\tfor\tthe\ttruckId\tand\tthe\tdb,\tthen\tyou\tassigned\teach\tof\tthem\tas properties\tto\tthe\tnewly\tconstructed\tinstance. The\tTruck\tinstances\twill\tneed\tmethods\tfor\tmanaging\tcoffee\torders,\tand\tyou\twill\tadd those\tnext.\tOrder\tdata\twill\tinclude\tan\temail\taddress\tand\ta\tdrink\tspecification. Adding\torders The\tfirst\tmethod\tto\tadd\tis\tcreateOrder.\tWhen\tthis\tmethod\tis\tcalled,\tthe\tTruck instance\twill\tinteract\twith\tits\tdb\tproperty\tthrough\tthe\tDataStore\tmethods\tyou\tdeclared earlier.\tSpecifically,\tyou\twill\tcall\tDataStore\u2019s\tadd\tmethod\tto\tstore\ta\tcoffee\torder, using\tthe\temail\taddress\tassociated\twith\tthe\torder. Declare\tthis\tnew\tprototype\tmethod\tin\ttruck.js. ... \t\tfunction\tTruck(truckId,\tdb)\t{ \t\t\t\tthis.truckId\t=\ttruckId; \t\t\t\tthis.db\t=\tdb; \t\t} \t\tTruck.prototype.createOrder\t=\tfunction\t(order)\t{ \t\t\t\tconsole.log('Adding\torder\tfor\t'\t+\torder.emailAddress); \t\t\t\tthis.db.add(order.emailAddress,\torder); \t\t}; \t\tApp.Truck\t=\tTruck; \t\twindow.App\t=\tApp; })(window); You\tlog\ta\tmessage\tto\tthe\tconsole\tin\tcreateOrder,\tthen\tyou\tstore\tthe\torder\tinformation using\tdb\u2019s\tadd\tmethod. Using\tthe\tadd\tmethod\twas\tas\tsimple\tas\treferring\tto\tthe\tTruck\u2019s\tdb\tinstance\tvariable\tand calling\tadd.\tYou\tdid\tnot\tneed\tto\tspecify\tthe\tApp.DataStore\tnamespace\tor\tmention the\tDataStore\tconstructor\tanywhere\tin\tthis\tmodule.\tInstances\tof\tTruck\tare\tdesigned to\twork\twith\tanything\tthat\thas\tthe\tsame\tmethod\tnames\tas\ta\tDataStore.\tThere\tis\tno need\tfor\tTruck\tto\tknow\tany\tdetails\tbeyond\tthat. Save\tyour\tfile\tand\ttest\tcreateOrder\tin\tthe\tconsole\tusing\tthe\tfollowing\tentries:","var\tmyTruck\t=\tnew\tApp.Truck('007',\tnew\tApp.DataStore()); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'decaf'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'double\tmocha'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'earl\tgrey'}); myTruck.db; Your\tresults\tshould\tlook\tlike\tFigure\t8.12. Figure\t8.12\t\tTaking\tTruck.prototype.createOrder\tfor\ta\ttest\tdrive When\tthe\tconsole\tprints\tthe\tvalue\tof\tmyTruck.db,\tyou\twill\tneed\tto\tclick\tthe\t \ticon\tso that\tyou\tcan\tsee\tthe\tnested\tproperties\t(such\tas\tthe\[email protected]\tproperty\tinside\tthe\tdata object). Removing\torders When\tan\torder\tis\tdelivered,\tthe\tTruck\tinstance\tshould\tremove\tthe\torder\tfrom\tits database.\tAdd\ta\tnew\tdeliverOrder\tmethod\tto\tthe\tTruck.prototype\tobject\tin truck.js. ... \t\tTruck.prototype.createOrder\t=\tfunction\t(order)\t{ \t\t\t\tconsole.log('Adding\torder\tfor\t'\t+\tdata.emailAddress); \t\t\t\tthis.db.add(data.emailAddress,\torder); \t\t}; \t\tTruck.prototype.deliverOrder\t=\tfunction\t(customerId)\t{ \t\t\t\tconsole.log('Delivering\torder\tfor\t'\t+\tcustomerId); \t\t\t\tthis.db.remove(customerId); \t\t}; \t\tApp.Truck\t=\tTruck; \t\twindow.App\t=\tApp; })(window); You\tassigned\ta\tfunction\texpression\tto\tTruck.prototype.deliverOrder.\tThis function\taccepts\ta\tcustomerId\targument,\twhich\tit\tthen\tpasses\tto\tthis.db.remove.","The\tvalue\tof\tcustomerId\tshould\tbe\tthe\temail\taddress\tassociated\twith\tan\torder. Just\tlike\tcreateOrder,\tdeliverOrder\tis\tonly\tinterested\tin\tcalling\tthe\tremove method\tof\tthis.db.\tIt\tdoes\tnot\tneed\tany\tdetails\tabout\thow\tremove\tactually\tworks. Save\tand\tswitch\tto\tthe\tconsole.\tCreate\ta\tTruck\tinstance,\tadd\ta\tfew\torders\twith createOrder,\tand\tthen\tmake\tsure\tthat\tdeliverOrder\tremoves\tthem\tfrom\tthe instance\u2019s\tdb.\t(You\tcan\tpress\tReturn\tor\tShift-Return\tafter\teach\tcall\tto\tcreateOrder\tand deliverOrder,\tbut\tmake\tsure\tyou\tpress\tReturn\tafter\teach\tmyTruck.db\tentry.) var\tmyTruck\t=\tnew\tApp.Truck('007',\tnew\tApp.DataStore()); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'earl\tgrey'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'decaf'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'double\tmocha'}); myTruck.db; myTruck.deliverOrder('[email protected]'); myTruck.deliverOrder('[email protected]'); myTruck.db; As\tyou\tenter\tthese\ttest\tcommands,\tyou\twill\tsee\tthat\tthe\torder\tinformation\tin\tmyTruck.db changes\tafter\tyou\tcall\tdeliverOrder\t(Figure\t8.13). Figure\t8.13\t\tRemoving\torder\tdata\twith\tTruck.prototype.deliverOrder Note\tthat\tthe\tconsole\tshows\tyou\tthe\tstate\tof\tthe\tdata\tat\tthe\ttime\tyou\tclick\tthe\t \ticon.\tIf you\tdo\tnot\tinspect\tthe\tvalues\tin\tmyTruck.db\tuntil\tafter\tcalling\tdeliverOrder,\tit\twill seem\tas\tthough\tthe\tdata\twas\tnever\tadded\t(Figure\t8.14).","Figure\t8.14\t\tConsole\tshows\tvalues\tat\ttime\tof\tclicking\tarrow\ticon","Debugging Your\tlast\tmethod\tto\tadd\tto\tthe\tTruck.prototype\tobject\tis\tprintOrders.\tThis\tmethod will\tget\tan\tarray\tof\tall\tof\tthe\tcustomer\temail\taddresses,\titerate\tthrough\tthe\tarray,\tand console.log\tthe\torder\tinformation. The\tcode\tfor\tthis\tmethod\tis\tvery\tsimilar\tto\tother\tfunctions\tand\tmethods\tyou\thave\talready written.\tBut\tit\twill\tstart\tout\twith\ta\tbug,\twhich\tyou\twill\tfind\tusing\tChrome\u2019s\tdebugging tools. Let\u2019s\ttake\tthis\tstep\tby\tstep.\tStart\tby\tcreating\tthe\tbasic\tversion\tof\tprintOrders\tin truck.js.\tIn\tthe\tbody,\tyou\twill\tretrieve\tall\tthe\tcoffee\torders\tfrom\tthe\tdb\tobject.\tThen you\twill\tuse\tthe\tObject.keys\tmethod\tto\tget\tan\tarray\tcontaining\tthe\temail\taddresses for\tthe\torders.\tFinally,\tyou\twill\titerate\tthrough\tthe\temail\taddress\tarray\tand\trun\ta\tcallback function\tfor\teach\telement\tin\tthe\tarray. ... \t\tTruck.prototype.deliverOrder\t=\tfunction\t(customerId)\t{ \t\t\t\tconsole.log('Delivering\torder\tfor\t'\t+\tcustomerId); \t\t\t\tthis.db.remove(customerId); \t\t}; \t\tTruck.prototype.printOrders\t=\tfunction\t()\t{ \t\t\t\tvar\tcustomerIdArray\t=\tObject.keys(this.db.getAll()); \t\t\t\tconsole.log('Truck\t#'\t+\tthis.truckId\t+\t'\thas\tpending\torders:'); \t\t\t\tcustomerIdArray.forEach(function\t(id)\t{ \t\t\t\t\t\tconsole.log(this.db.get(id)); \t\t\t\t}); \t\t}; \t\tApp.Truck\t=\tTruck; \t\twindow.App\t=\tApp; })(window); Inside\tthe\tnew\tprintOrders\tmethod,\tyou\tcall\tthis.db.getAll\tto\tretrieve\tall\tthe orders\tas\tkey\/value\tpairs\tand\tpass\tthem\tto\tObject.keys,\twhich\treturns\tan\tarray containing\tonly\tthe\tkeys.\tYou\tassign\tthis\tarray\tto\tthe\tvariable\tcustomerIdArray. When\tyou\titerate\tthrough\tthis\tarray,\tyou\tpass\ta\tcallback\tto\tforEach.\tIn\tthe\tbody\tof\tthat callback,\tyou\ttry\tto\tget\tthe\torder\tassociated\twith\tan\tid\t(the\tcustomer\temail\taddress). Save\tand\treturn\tto\tthe\tconsole.\tCreate\ta\tnew\tinstance\tof\tTruck\tand\tadd\tsome\tcoffee orders.\tThen\ttry\tyour\tnew\tprintOrders\tmethod. var\tmyTruck\t=\tnew\tApp.Truck('007',\tnew\tApp.DataStore()); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'earl\tgrey'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'decaf'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'double\tmocha'}); myTruck.printOrders(); Instead\tof\ta\tlist\tof\tthe\tcoffee\torders,\tyou\twill\tsee\tthe\terror\tUncaught\tTypeError:\tCannot read\tproperty\t'db'\tof\tundefined\t(Figure\t8.15).","Figure\t8.15\t\tError\twhen\tprintOrders\tis\trun This\tis\tone\tof\tthe\tmost\tcommon\terrors\tthat\tyou\twill\tsee\twhen\twriting\tJavaScript.\tMany developers\tfind\tit\tespecially\tfrustrating\tbecause\tit\tcan\tbe\thard\tto\tpinpoint\tthe\tcause. Knowing\thow\tto\tuse\tthe\tdebugger,\tas\tyou\tare\tabout\tto\tdo,\tis\tkey\tto\tlocating\tthe\tproblem. Locating\tbugs\twith\tthe\tDevTools Debugging\trequires\tyou\tto\treproduce\tthe\terror\tas\tyou\tprogressively\tisolate\tthe\tbuggy code.\tThe\tChrome\tdebugger\tmakes\tthis\tprocess\t(almost)\tenjoyable. When\tan\terror\toccurs,\tthe\tconsole\tshows\tyou\tthe\tfilename\tand\tthe\tline\tnumber\tof\tthe\tcode that\tcaused\tthe\terror.\t(In\tFigure\t8.15,\tthe\treference\tis\tto\ttruck.js:30;\tyour\tline\tnumber might\tbe\tdifferent.)\tClick\tthat\ttext\tto\topen\tthe\toffending\tline\tof\tcode\tin\tthe\tdebugging tools\t(Figure\t8.16).","Figure\t8.16\t\tViewing\tthe\terror\tin\tthe\tdebugging\ttools You\tare\tnow\tviewing\tthe\tsources\tpanel\tof\tthe\tDevTools.\tClick\tthe\tred\ticon\tin\tthe\tproblem line\tto\tsee\tthe\terror\tinformation\t(Figure\t8.17). Figure\t8.17\t\tError\tline\tcalled\tout\tin\tthe\tsources\tpanel This\terror\tmessage\tindicates\tthat\tthe\tbrowser\tthinks\tyou\tare\ttrying\tto\tread\ta\tproperty named\tdb,\tbut\tthat\tthe\tobject\tit\tbelongs\tto\tdoes\tnot\texist. The\tnext\tstep\tis\tto\trun\tthe\tcode\tjust\tup\tto\tthe\tline\tthat\tis\tcausing\tthe\terror\tand\tthen\tcheck the\tvalue\tof\tthat\tobject.\tIn\tthe\tsources\tpanel,\tclick\tthe\tline\tnumber\tto\tthe\tleft\tof\tthe\tline with\tthe\terror\tflag.\tThis\tsets\ta\tbreakpoint\tfor\tthe\tdebugger,\ttelling\tthe\tbrowser\tto\tpause just\tbefore\tit\ttries\tto\trun\tthis\tline.\tWhen\tyou\tset\ta\tbreakpoint,\tthe\tline\tnumber\ton\tthe\tleft turns\tblue\tand\tan\tentry\tis\tadded\tto\tthe\tbreakpoints\tpanel\ton\tthe\tright\t(Figure\t8.18).","Figure\t8.18\t\tSetting\ta\tbreakpoint Press\tthe\tEscape\tkey\tto\tshow\tthe\tconsole\tat\tthe\tbottom\tof\tthe\tsources\tpanel\t(Figure\t8.19). This\tis\talso\tknown\tas\tthe\tdrawer.\tYou\twill\tneed\tto\tbe\table\tto\tsee\tthe\tcode\tin\tthe\tsources panel\tand\tinteract\twith\tthe\tconsole\tat\tthe\tsame\ttime. Figure\t8.19\t\tShowing\tthe\tconsole\tdrawer Run\tmyTruck.printOrders();\tagain\tin\tthe\tconsole.\tThe\tbrowser\twill\tactivate\tthe debugger,\tand\tyour\tcode\twill\tpause\tat\tthe\tbreakpoint\t(Figure\t8.20).","Figure\t8.20\t\tDebugger\tpaused\tat\tbreakpoint When\tthe\tdebugger\tpauses,\tyou\thave\taccess\tto\tall\tof\tthe\tvariables\tthat\tare\tavailable\tat\tthat point.\tUsing\tthe\tconsole,\tyou\tcan\tcheck\tthe\tvalues\tof\tthe\tvariables,\tlooking\tfor\tsigns\tof trouble. Try\tto\treproduce\tthe\terror\tby\tevaluating\tparts\tof\tthe\tline\tof\tcode\twith\tthe\terror\tflag.\tStart with\tthe\tcode\tthat\tis\tnested\tfurthest\tinside\tof\tany\tparentheses.\tIn\tthis\tcase,\tthat\tis\tthe\tid variable.\tWhen\tyou\tenter\tthat\ton\tthe\tconsole,\tit\treports\tthat\tthe\tvalue\tis\[email protected] (Figure\t8.21). Figure\t8.21\t\tInspecting\tthe\tinnermost\tvalue Because\tthat\tdid\tnot\treproduce\tthe\terror,\ttry\tthe\tcode\tjust\toutside\tthat\tset\tof\tparentheses, this.db.get(id).\tEvaluate\tit\ton\tthe\tconsole.\tYou\tshould\tsee\tthat\tthe\terror\tis\treported (Figure\t8.22).","Figure\t8.22\t\tReproducing\tthe\terror Now\tyou\tcan\tfurther\tisolate\tthe\tcause.\tBegin\tevaluating\tthat\tsame\tpiece\tof\tcode,\tbut remove\tparts\tof\tit,\tstarting\tfrom\tthe\tright.\tYou\twill\tdo\tthis\tuntil\tthe\terror\tis\tno\tlonger printed.\tStart\twith\tthis.db.get.\tAfter\tthat,\tenter\tthis.db.\tThe\tconsole\tcontinues\tto\treport the\terror\t(Figure\t8.23). Figure\t8.23\t\tThe\tsearch\tcontinues Finally,\tenter\tthis.\tYou\tare\tnow\tat\tthe\tpoint\twhere\tthe\terror\tis\tnot\thappening (Figure\t8.24). Figure\t8.24\t\tTrimming\tdown\tthe\tcode\tto\tfind\tthe\tcause\tof\tthe\terror Why\tdoes\tthis\thave\tthe\tvalue\tundefined\tinside\tof\tyour\tcallback?\tInside\tof\ta\tcallback function,\tthis\tis\tnot\tassigned\tto\tan\tobject.\tYou\tneed\tto\texplicitly\tassign\tone. This\tsituation\tis\tdifferent\tfrom\tyour\tTruck.prototype\tmethods,\twhere\tthis\trefers\tto the\tinstance\tof\tTruck.\tEven\tthough\tthe\tcallback\tis\tinside\tof Truck.prototype.printOrder,\tit\thas\tits\town\tthis\tvariable,\twhich\tis\tnot\tassigned to\ta\tvalue\tand\tis\ttherefore\tundefined. Before\tfixing\tyour\tcode,\tyou\tshould\tbe\tfamiliar\twith\ttwo\tother\tways\tyou\tcould\thave located\tthe\tbug.\tIf\tyou\tmouse\tover\tthe\tdifferent\tparts\tof\tthe\tcode\tin\tthe\tsources\tpanel,\tthe","debugger\twill\tshow\tyou\ttheir\tvalues.\tWith\tthe\tmouse\tover\tthis,\tit\tshows\tyou\tthat\tits value\tis\tundefined\t(Figure\t8.25). Figure\t8.25\t\tHovering\tthe\tmouse\treveals\tvalues To\tthe\tright\tof\tthe\tcode\tis\tthe\tscope\tpanel,\twhich\tcontains\ta\tlist\tof\tvariables\tavailable.\tYou can\tsee\tthat\tvalues\tfor\tid\tand\tthis\tare\tshown\t\u2013\tand,\tagain,\tthat\tthis\tis\tundefined (Figure\t8.26). Figure\t8.26\t\tVariable\tvalues\tshown\tin\tscope\tpanel Click\tthe\tblue\t \tbutton\tat\tthe\ttop\tof\tthe\tright\thand\tpanel\t(Figure\t8.27).\tThis\tunpauses your\tcode,\tallowing\tit\tto\tresume\texecution. Figure\t8.27\t\tDebugger\tcontrol\tpanel Before\tmoving\ton,\tremove\tthe\tbreakpoint\tby\tclicking\tthe\tblue\tline\tnumber\tagain.\tThe blue\tindicator\twill\tdisappear\t(Figure\t8.28).","Figure\t8.28\t\tClick\tthe\tline\tnumber\tto\ttoggle\ta\tbreakpoint Now,\tit\tis\ttime\tto\tfix\tthat\tpesky\tbug! Setting\tthe\tvalue\tof\tthis\twith\tbind In\tJavaScript,\tthe\tkeyword\tthis\tinside\tof\ta\tfunction\tis\tautomatically\tassigned\ta\tvalue when\tyou\tcall\tthat\tfunction.\tFor\tconstructor\tfunctions\tand\tfor\tprototype\tmethods,\tthe value\tof\tthis\tis\tthe\tinstance\tobject.\tThe\tinstance\tis\tcalled\tthe\towner\tof\tthe\tfunction\tcall. Using\tthe\tkeyword\tthis\tgives\tyou\taccess\tto\tthe\tproperties\tof\tthe\towner. As\twe\tsaid\tearlier,\tfor\tcallback\tfunctions\tthis\tis\tnot\tautomatically\tassigned\tto\tan\tobject. You\tcan\tmanually\tspecify\twhat\tobject\tshould\tbe\tthe\towner\tby\tusing\ta\tfunction\u2019s\tbind method.\t(Remember\tthat\tJavaScript\tfunctions\tare\tactually\tobjects\tand\tcan\thave\ttheir\town properties\tand\tmethods,\tsuch\tas\tbind.) The\tbind\tmethod\taccepts\tan\tobject\targument\tand\treturns\ta\tnew\tversion\tof\tthe\tfunction. When\tyou\tcall\tthe\tnew\tversion,\tit\twill\tuse\tthe\tobject\targument\tpassed\tin\tto\tbind\tas\tthe value\tof\tthis\tinside\tof\tthe\tfunction\u2019s\tbody. Inside\tthe\tforEach\tcallback,\tthis\tis\tundefined\tbecause\tthe\tcallback\thas\tno\towner.\tFix that\tby\tcalling\tbind\tand\tpassing\tit\ta\treference\tto\tthe\tTruck\tinstance. Add\tthe\tcall\tto\tbind\tin\ttruck.js. ... \t\tTruck.prototype.printOrders\t=\tfunction\t()\t{ \t\t\t\tvar\tcustomerIdArray\t=\tObject.keys(this.db.getAll()); \t\t\t\tconsole.log('Truck\t#'\t+\tthis.truckId\t+\t'\thas\tpending\torders:'); \t\t\t\tcustomerIdArray.forEach(function\t(id)\t{ \t\t\t\t\t\tconsole.log(this.db.get(id)); \t\t\t\t}.bind(this)); \t\t}; ... Outside\tthe\tbody\tof\tthe\tforEach\tcallback,\tthe\tkeyword\tthis\trefers\tto\tthe\tTruck instance.\tBy\tadding\t.bind(this)\timmediately\tafter\tthe\tanonymous\tfunction\t\u2013\tbut\tinside the\tparentheses\tfor\tthe\tforEach\tcall\t\u2013\tyou\tare\tpassing\tforEach\ta\tmodified\tversion\tof the\tanonymous\tfunction.\tThis\tmodified\tversion\tuses\tthe\tTruck\tinstance\tas\tits\towner. Save\tand\tconfirm\tthat\tthe\torders\tare\tprinted\tcorrectly.\tYou\twill\tneed\tto\tre-declare myTruck\tand\trun\tcreateOrder\tagain. Your\toutput\tshould\tlook\tlike\tFigure\t8.29.","Figure\t8.29\t\tprintOrders\tworks\tafter\tusing\tbind(this)","Initializing\tCoffeeRun\ton\tPage\tLoad Your\tDataStore\tand\tTruck\tmodules\twork\tcorrectly.\tYou\thave\tbeen\table\tto\tinstantiate a\tnew\tTruck\ton\tthe\tconsole,\tsupplying\tit\ta\tnew\tDataStore\tas\tpart\tof\tits\tcreation. Now\tyou\tare\tgoing\tto\tcreate\ta\tmodule\tthat\tperforms\tthese\tsame\tsteps\twhen\tthe\tpage loads.\tCreate\ta\tscripts\/main.js\tfile\tand\tadd\ta\t<script>\ttag\tto\tindex.html. <!doctype\thtml> <html> \t\t<head> \t\t\t\t<meta\tcharset=\\\"utf-8\\\"> \t\t\t\t<title>coffeerun<\/title> \t\t<\/head> \t\t<body> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script>> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script>> \t\t\t\t<script\tsrc=\\\"scripts\/main.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t<\/body> <\/html> Save\tindex.html.\tYou\tare\tgoing\tto\tadd\tan\tIIFE\tto\tmain.js,\tas\tyou\thave\tdone\twith the\tother\tmodules,\tbut\tthis\ttime\tyou\twill\tnot\tneed\tto\texport\tany\tnew\tproperties\tto window.App.\tSet\tup\tmain.js\tas\tshown: (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App; \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; })(window); The\tjob\tof\tthis\tmodule\tis\tto\treceive\tthe\twindow\tobject\tfor\tuse\tinside\tthe\tfunction\tbody.\tIt also\tretrieves\tthe\tconstructors\tyou\tdefined\tas\tpart\tof\tthe\twindow.App\tnamespace. Technically,\tyou\tcan\tjust\twrite\tall\tof\tyour\tcode\twith\tthe\tfull\tnames\t(e.g.,\tApp.Truck\tand App.DataStore),\tbut\tyour\tcode\tis\tmore\treadable\twhen\tyou\thave\tshorter\tnames. Creating\tthe\tTruck\tinstance Now,\tjust\tas\tyou\tdid\ton\tthe\tconsole,\tyou\twill\tcreate\tan\tinstance\tof\tTruck,\tproviding\tit\tan id\tand\tan\tinstance\tof\tDataStore. Call\tthe\tTruck\tconstructor\tin\tmain.js,\tpassing\tit\tan\tid\tof\tncc-1701\tand\ta\tnew instance\tof\tDataStore. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App; \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); })(window); This\tis\tnearly\tthe\tsame\tas\tthe\tcode\tyou\tentered\tin\tthe\tconsole\tearlier,\tbut\tyou\tdo\tnot\tneed to\tprefix\tTruck\tor\tDataStore\twith\tApp,\tbecause\tyou\tcreated\tlocal\tvariables\tthat\tpoint to\tApp.Truck\tand\tApp.DataStore. At\tthis\tpoint,\tyour\tapplication\tcode\tis\tnearly\tcomplete.\tHowever,\tyou\tstill\tcannot\tinteract with\tthe\tinstance\tof\tTruck.\tWhy\tnot?\tThe\tvariable\tis\tdeclared\tinside\tof\ta\tfunction,\tthe main\tmodule.\tFunctions\tprotect\ttheir\tvariables\tfrom\tbeing\taccessed\tby\tcode\toutside\tof\tthe function,\tincluding\tcode\tyou\twrite\ton\tthe\tconsole.","So\tthat\tyou\tcan\tinteract\twith\tthe\tinstance\tof\tTruck,\texport\tit\tto\tthe\tglobal\tnamespace\tin main.js. (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App; \t\tvar\tTruck\t=\tApp.Truck; \t\tvar\tDataStore\t=\tApp.DataStore; \t\tvar\tmyTruck\t=\tnew\tTruck('ncc-1701',\tnew\tDataStore()); \t\twindow.myTruck\t=\tmyTruck; })(window); Save\tyour\twork\tand\tgo\tback\tto\tthe\tconsole.\tReload\tthe\tpage\tmanually\tto\tmake\tsure\tthat any\tprior\twork\tyou\tdid\tin\tthe\tconsole\thas\tbeen\tcleared\tout. Start\ttyping\tmyTruck\tand\tyou\tshould\tsee\tthat\tthe\tconsole\tis\ttrying\tto\tautocomplete\tit (Figure\t8.30).\tThat\tmeans\tthat\tit\tfound\tthe\tmyTruck\tvariable\tthat\tyou\texported\tas\ta property\tof\tthe\twindow\tobject. Figure\t8.30\t\tThe\tconsole\tfinds\tmyTruck\tin\tthe\tglobal\tnamespace Call\tmyTruck.createOrder\ta\tfew\ttimes,\tproviding\tit\tsome\ttest\tdata.\tYou\tcan\tdo\tthis easily\tby\tletting\tthe\tconsole\tautocomplete\tyour\tprevious\tcalls\tto\tcreateOrder (Figure\t8.31). Figure\t8.31\t\tConsole\tautocompleting\tprevious\tcalls\tto\tcreateOrder Alternatively,\tenter\tthe\tfollowing\tcode\tto\tconfirm\tthat\teverything\tfunctions\tas\texpected. myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'double\tmocha'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'decaf'}); myTruck.createOrder({\temailAddress:\t'[email protected]',\tcoffee:\t'earl\tgrey'}); myTruck.printOrders(); myTruck.deliverOrder('[email protected]');","myTruck.deliverOrder('[email protected]'); myTruck.printOrders(); After\texercising\tthe\tmethods\tcreateOrder,\tprintOrders,\tand\tdeliverOrder, you\tshould\tsee\tsomething\tlike\tFigure\t8.32. Figure\t8.32\t\tOne\tbusy\tcoffee\ttruck Congratulations!\tYou\thave\tcompleted\tthe\tfoundation\tof\tCoffeeRun.\tIt\tdoes\tnot\thave\ta\tUI yet,\tbut\tyou\twill\tadd\tthat\tin\tupcoming\tchapters.\tAnd\tyou\twill\tnot\tneed\tto\tmake\tchanges\tto the\tcore,\tbecause\tthe\tUI\twill\tsimply\tcall\tthe\tTruck.prototype\tmethods\tyou\thave\talready written\tand\ttested. This\tis\tthe\tadvantage\tof\tthe\tmodular\tapproach:\tYou\tcan\twork\ton\tyour\tapplication\tin layers,\tknowing\tthat\teach\tnew\tlayer\tis\tbuilt\ton\tworking\tcode\tin\tthe\tunderlying\tmodules.","Bronze\tChallenge:\tTruck\tID\tfor\tNon-Trekkies In\tmain.js,\tpass\tin\ta\tdifferent\tstring\tfor\tthe\ttruckId. (Some\tgood\toptions\tinclude\t\u201cSerenity,\u201d\t\u201cKITT,\u201d\tor\t\u201cGalactica.\u201d\t\u201cHAL\u201d\tis\tprobably\ta\tbad idea.)","For\tthe\tMore\tCurious:\tPrivate\tModule\tData Inside\ta\tmodule,\tyour\tconstructors\tand\tprototype\tmethods\thave\taccess\tto\tany\tvariables declared\tinside\tthe\tIIFE.\tAs\tan\talternative\tto\tadding\tproperties\tto\tthe\tprototype,\tthis\tis\ta way\tto\tshare\tdata\tbetween\tinstances\tbut\tmake\tit\thidden\tfrom\tany\tcode\toutside\tthe\tmodule. It\tlooks\tlike\tthis: (function\t(window)\t{ \t\t'use\tstrict'; \t\tvar\tApp\t=\twindow.App\t||\t{}; \t\tvar\tlaunchCount\t=\t0; \t\tfunction\tSpaceship()\t{ \t\t\t\t\/\/\tInitialization\tcode\tgoes\there \t\t} \t\tSpaceship.prototype.blastoff\t=\tfunction\t()\t{ \t\t\t\t\/\/\tClosure\tscope\tallows\taccess\tto\tthe\tlaunchCount\tvariable \t\t\t\tlaunchCount++; \t\t\t\tconsole.log('Spaceship\tlaunched!') \t\t} \t\tSpaceship.prototype.reportLaunchCount\t=\tfunction\t()\t{ \t\t\t\tconsole.log('Total\tnumber\tof\tlaunches:\t'\t+\tlaunchCount); \t\t} \t\tApp.Spaceship\t=\tSpaceship \t\twindow.App\t=\tApp; })(window); Other\tlanguages\tprovide\ta\tway\tto\tdeclare\ta\tvariable\tas\tprivate,\tbut\tJavaScript\tdoes\tnot. You\tcan\ttake\tadvantage\tof\tclosure\tscope\t(a\tfunction\tusing\tvariables\tdeclared\tin\tthe\touter scope)\tto\tsimulate\tprivate\tvariables.","Silver\tChallenge:\tMaking\tdata\tPrivate Update\tyour\tDataStore\tmodule\tso\tthat\tthe\tdata\tproperty\tis\tprivate\tto\tthe\tmodule. Are\tthere\tany\treasons\tyou\twould\tnot\twant\tto\tdo\tthis?\tWhat\thappens\tif\tyou\tdeclare multiple\tinstances\tof\tDataStore?","For\tthe\tMore\tCurious:\tSetting\tthis\tin\tforEach\u2019s Callback We\ttold\ta\tsmall\tfib\tearlier.\tUsing\tbind\tis\tnot\tthe\tonly\tway\tto\tset\tthe\tvalue\tof\tthis\tfor the\tcallback\tto\tforEach. Look\tat\tthe\tdocumentation\tfor\tArray.prototype.forEach\ton\tMDN (developer.mozilla.org\/e\u200b n-US\/\u200bdocs\/W\u200b eb\/\u200bJavaScript\/R\u200b eference\/\u200b Global_Objects\/A\u200b rray\/\u200bforEach).\tYou\tcan\tsee\tthat\tforEach\ttakes\tan\toptional second\targument,\twhich\tit\twill\tuse\tas\tthe\tvalue\tof\tthis\tin\tthe\tcallback. That\tmeans\tthat\tyou\tcould\thave\talso\twritten\tthe\tprintOrders\tmethod\tlike\tso: ... Truck.prototype.printOrders\t=\tfunction\t()\t{ \t\tvar\tcustomerIdArray\t=\tObject.keys(this.db.getAll()); \t\tconsole.log('Truck\t#'\t+\tthis.truckId\t+\t'\thas\tpending\torders:'); \t\tcustomerIdArray.forEach(function\t(id)\t{ \t\t\t\tconsole.log(this.db.get(id)); \t\t},\tthis); }; ... bind,\thowever,\tis\ta\tuseful\tmethod\tthat\tyou\twill\tsee\tagain\tin\tthe\tcoming\tchapters. Truck.prototype.printOrders\tprovided\ta\tgood\topportunity\tto\tintroduce\tyou\tto the\tsyntax.","9\t Introduction\tto\tBootstrap In\tthis\tchapter,\tyou\twill\tcreate\tthe\tHTML\tmarkup\tfor\tyour\tUI.\tYou\twill\tuse\tthe\tstyles provided\tby\tthe\tpopular\tBootstrap\tCSS\tframework\tto\tgive\tyour\tUI\ta\tbit\tof\tpolish\twithout having\tto\tcreate\tthe\tCSS\tyourself.\tThis\tway,\tyou\tcan\tfocus\ton\tthe\tapplication\tlogic\tin JavaScript,\twhich\tyou\twill\tdo\tin\tChapter\t10. You\twill\tbe\tcreating\tthe\tUI\tfor\tthe\tCoffeeRun\tapp\tin\ttwo\tparts.\tThe\tfirst\tconsists\tof\ta\tform into\twhich\ta\tuser\tcan\tenter\ta\tcoffee\torder\twith\tall\tof\tits\tdetails\t(Figure\t9.1).\tIn\tthe\tsecond part,\tthe\texisting\tcoffee\torders\twill\tbe\tdisplayed\tin\ta\tchecklist.\tEach\tof\tthese\tparts\twill have\ta\tcorresponding\tJavaScript\tmodule\tto\thandle\tuser\tinteraction. Figure\t9.1\t\tCoffeeRun\tstyled\twith\tBootstrap Adding\tBootstrap","The\tBootstrap\tCSS\tlibrary\tprovides\ta\tcollection\tof\tstyles\tthat\tyou\tcan\tuse\tfor\tyour\tsites\tand applications.\tBecause\tof\tits\tpopularity,\tyou\tmay\tnot\twant\tto\tuse\tBootstrap\tfor\tyour\tuser- facing\tproduction\tsite\twithout\tmaking\tsome\tcustomizations.\tOtherwise,\tyour\tsite\tmay\tend up\tlooking\tlike\teveryone\telse\u2019s.\tHowever,\tBootstrap\tis\tgreat\tfor\tquickly\tcreating\tgood- looking\tprototypes. As\tyou\tdid\twith\tnormalize.css\tin\tOttergram,\tyou\twill\tget\tBootstrap\tby\tloading\tit\tfrom cdnjs.com.\tUse\tversion\t3.3.6\tof\tBootstrap,\twhich\tis\tat\tcdnjs.com\/\u200blibraries\/\u200b twitter-bootstrap\/3\u200b .3.6.\t(To\tfind\tthe\tmost\tcurrent\tversion\tfor\tyour\town projects,\tsearch\tcdnjs.com\tfor\t\u201ctwitter\tbootstrap.\u201d) Make\tsure\tto\tget\tthe\tlink\tfor\tbootstrap.min.css\t(Figure\t9.2),\tnot\tone\tfor\tthe\ttheme or\tfonts. Figure\t9.2\t\tcdnjs.com\tpage\tfor\ttwitter-bootstrap After\tyou\thave\tcopied\tthe\tlink,\topen\tindex.html\tand\tadd\ta\t<link>\ttag\twith\tthe\tURL. (Although\twe\thad\tto\twrap\tthe\thref\tattribute\taround\tto\ta\tsecond\tline\tto\tfit\ton\tthis\tpage, you\tshould\tenter\tit\ton\tone\tline.) ... \t\t<head> \t\t\t\t<meta\tcharset=\\\"utf-8\\\"> \t\t\t\t<title>coffeerun<\/title> \t\t\t\t<link\trel=\\\"stylesheet\\\"\thref=\\\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/twitter-bootst rap\/3.3.6\/css\/bootstrap.min.css\\\"> \t\t<\/head> ...","How\tBootstrap\tworks Bootstrap\tcan\tprovide\tout-of-the-box\tresponsive\tstyling\tfor\tyour\twebsite\tor\tweb\tapp.\tMost of\tthe\ttime,\tyou\twill\tjust\tneed\tto\tinclude\tthe\tCSS\tfile\tand\tthen\tadd\tclasses\tto\tyour\tmarkup. One\tof\tthe\tmain\tclasses\tyou\twill\tuse\tis\tthe\tcontainer\tclass. Add\tthe\tcontainer\tclass\tto\tyour\t<body>\telement\tin\tindex.html.\tWhile\tyou\tare\tthere, add\ta\theader\tto\tyour\tpage\tas\twell. ... \t\t\t\t<title>coffeerun<\/title> \t\t\t\t<link\trel=\\\"stylesheet\\\"\thref=\\\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/twitter-bootst rap\/3.3.6\/css\/bootstrap.min.css\\\"> \t\t<\/head> \t\t<body> \t\t<body\tclass=\\\"container\\\"> \t\t\t\t<header> \t\t\t\t\t\t<h1>CoffeeRun<\/h1> \t\t\t\t<\/header> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/truck.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t\t\t<script\tsrc=\\\"scripts\/main.js\\\"\tcharset=\\\"utf-8\\\"><\/script> \t\t<\/body> <\/html> The\tcontainer\tclass\tacts\tas\ta\twrapper\tfor\tall\tthe\tcontent\tthat\tneeds\tto\tadapt\tto\tthe\tsize\tof the\tviewport.\tThis\tprovides\tbasic\tresponsive\tbehavior\tto\tthe\tlayout. Save\tindex.html,\tmake\tsure\tbrowser-sync\tis\trunning,\tand\tview\tyour\tpage.\tIt\tshould resemble\tFigure\t9.3. Figure\t9.3\t\tHeader\tstyled\twith\tBootstrap Although\tthere\tis\tnot\tmuch\tto\tyour\tpage\tyet,\tnotice\tthat\tthere\tis\talready\ta\tcomfortable amount\tof\tpadding\taround\tyour\theader\tand\tthat\tit\thas\ta\tfont\tstyle\tapplied\tto\tit. Bootstrap\thas\tstyles\tfor\ta\thuge\tnumber\tof\tdifferent\tvisual\telements.\tCoffeeRun\twill\tjust scratch\tthe\tsurface,\tbut\tyou\twill\tget\ta\tchance\tto\texplore\tmore\tstyles\tin\ta\tlater\tchapter.\tFor now,\tit\tis\ttime\tto\tadd\tthe\tmarkup\tfor\tthe\torder\tform.","Creating\tthe\tOrder\tForm Add\ta\t<section>\ttag,\ttwo\t<div>s,\tand\ta\t<form>\tto\tindex.html,\tbelow\tthe\t<header> element\tyou\tjust\tcreated. ... \t\t\t\t<header> \t\t\t\t\t\t<h1>CoffeeRun<\/h1> \t\t\t\t<\/header> \t\t\t\t<section> \t\t\t\t\t\t<div\tclass=\\\"panel\tpanel-default\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"panel-body\\\"> \t\t\t\t\t\t\t\t\t\t<form\tdata-coffee-order=\\\"form\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<!--\tInput\telements\twill\tgo\there\t--> \t\t\t\t\t\t\t\t\t\t<\/form> \t\t\t\t\t\t\t\t<\/div> \t\t\t\t\t\t<\/div> \t\t\t\t<\/section> \t\t\t\t<script\tsrc=\\\"scripts\/datastore.js\\\"\tcharset=\\\"utf-8\\\"><\/script> ... The\t<form>\ttag\tis\tgoing\tto\tbe\twhere\tall\tthe\timportant\tstuff\thappens.\tYou\tgave\tit\ta\tdata- coffee-order\tattribute\twith\tthe\tvalue\tform.\tIn\tCoffeeRun,\tyou\twill\tuse\tdata\tattributes\tfor accessing\tDOM\telements\tfrom\tJavaScript,\tjust\tas\tyou\tdid\tin\tOttergram. For\tlayout,\tyou\tadded\ttwo\t<div>\ttags.\tIt\tis\tnot\timportant\tthat\tyou\tuse\t<div>\ttags, specifically.\tWhat\tis\timportant\tis\tthat\tyou\tare\tapplying\tthe\tpanel,\tpanel-default,\tand panel-body\tclasses\tto\tthem.\tThese\tare\tBootstrap\tclasses\tthat\twill\ttrigger\tstyles\tfor\tyou. Remember,\t<div>s\tare\tjust\tgeneral-purpose\tblock-level\tcontainers\tfor\tother\tmarkup.\tThey take\tup\tas\tmuch\thorizontal\tspace\tas\tprovided\tby\ttheir\tcontaining\tparent\telement.\tThey will\tbe\tused\toften\tin\tCoffeeRun,\tand\tyou\twill\tsee\tthem\tthroughout\tthe\texamples\tin\tthe Bootstrap\tdocumentation. You\tmay\tbe\twondering\twhy\tthe\t<section>\ttag\twraps\taround\tyour\t<div>\tand\t<form>\ttags. <div>s\thave\tno\tsemantic\tmeaning.\t<section>s\tdo:\tthey\tlogically\tgroup\tother\tmarkup. This\tone\twill\thouse\tthe\tUI\tfor\tthe\tform.\tYou\tcould\teasily\thave\tanother\t<section>\tof\tthe page\tthat\tis\tfor\tsome\tother\tpiece\tof\tthe\tUI. Adding\ttext\tinput\tfields The\tmain\tpiece\tof\tinformation\tthat\tyou\tcare\tabout\tis\tthe\tcoffee\torder\titself.\tIf\tyou\thave been\tin\ta\tcoffee\tshop\tin\tthe\tlast\tdecade,\tyou\tknow\thow\tcomplicated\torders\tcan\tget.\tFor now,\tyou\twill\tuse\ta\tsingle-line\ttext\tfield\tto\trepresent\tan\torder.\tLater\tyou\twill\tadd\tmore fields\tto\tcapture\tmore\tinformation\tabout\tthe\torder. When\tyou\tuse\tBootstrap\tfor\tyour\tforms,\tyou\tadd\textra\t<div>\telements\tthat\tare\tsolely\tfor applying\tstyles\tdefined\tin\tthe\tBootstrap\tlibrary. Add\tanother\t<div>\tto\tindex.html\twith\tthe\tclass\tform-group.\tThe\tform-group\tBootstrap class\tprovides\tconsistent\tvertical\tspacing\tfor\tform\telements.\tThen\tadd\t<label>\tand <input>\telements. ... \t\t\t\t\t\t<div\tclass=\\\"panel\tpanel-default\\\"> \t\t\t\t\t\t\t\t<div\tclass=\\\"panel-body\\\"> \t\t\t\t\t\t\t\t\t\t<form\tdata-coffee-order=\\\"form\\\"> \t\t\t\t\t\t\t\t\t\t\t\t<!--\tInput\telements\twill\tgo\there\t--> \t\t\t\t\t\t\t\t\t\t\t\t<div\tclass=\\\"form-group\\\"> \t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Coffee\tOrder<\/label>"]
Search
Read the Text Version
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
- 509
- 510
- 511
- 512
- 513
- 514
- 515
- 516
- 517
- 518
- 519
- 520
- 521
- 522
- 523
- 524
- 525
- 526
- 527
- 528
- 529
- 530
- 531
- 532
- 533
- 534
- 535
- 536
- 537
- 538
- 539
- 540
- 541
- 542
- 543
- 544
- 545
- 546
- 547
- 548
- 549
- 550
- 551
- 552
- 553
- 554
- 555
- 556
- 557
- 558
- 559
- 560
- 561
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576