JavaScriptforKids:APlayfulIntroductiontoProgramming
NickMorgan
PublishedbyNoStarchPress
ToPhilly(andPancake)
AbouttheAuthorNickMorganisafrontendengineeratTwitter.HelovesallprogramminglanguagesbuthasaparticularsoftspotforJavaScript.NicklivesinSanFrancisco(thefoggypart)withhisfiancéeandtheirfluffydog,Pancake.Heblogsatskilldrick.co.uk.
AbouttheIllustratorMiranLipovacaistheauthorofLearnYouaHaskellforGreatGood!.Heenjoysboxing,playingbassguitar,and,ofcourse,drawing.Hehasafascinationwithdancingskeletonsandthenumber71,andwhenhewalksthroughautomaticdoorshepretendsthathe’sactuallyopeningthemwithhismind.
AbouttheTechnicalReviewerAngusCrollistheauthorofIfHemingwayWroteJavaScript,andheisobsessedwithJavaScriptandliteratureinequalmeasure.HeworksonTwitter’sUIframeworkteam,whereheco-authoredtheFlightframework.HewritestheinfluentialJavaScript,JavaScriptblogandspeaksatconferencesworldwide.Hetweetsat@angustweets.
AcknowledgmentsSomanythankstomywonderfulfiancée,Philly,forherencouragementandsupportduringthepast18months.Itrulycouldn’thavedoneitwithouther.AndthankstoPancake,ourdog,forgraciouslyallowingmetousehiminmycodeexamples.ThankstoAngus,withoutwhomIwouldn’tbehere,inSanFrancisco,writingthisbook.AngusreferredmetoTwitterbackin2011,andthenin2013suggestedtoBillPollockthatImightbeinterestedinwritingthisbookyou’reholding.Andtotopitall,heagreedtobethetechnicalreviewer,catchingagreatnumberofJavaScriptfauxpas.ThankstoBillPollock,SephKramer,RileyHoffman,TylerOrtman,andeveryoneelseatNoStarchPress,whopatientlyguidedmethroughtheprocessofwritingthisbook.SpecialthankstoBillandSephformassagingmywritingintoitscurrentform.ThankstotheyoungreviewersRiverBradley,DamienChamp,andAlexChu,whohadsomegreatfeedbackontheearlyPDFs.Finally,thankstoMiranLipovaca.I’vebeenafanofMiranforyears—hisbookLearnYouaHaskellforGreatGoodisoneofmyfavoriteprogrammingbooks,andhisillustrationsforitareamazing.Findingouthe’dbeillustratingmybookwaslikeadreamcometrue.HispicturesforthisbookarebetterthanIcouldhaveimagined,andI’mhumbledtohavehadthechancetoworkwithhim.
IntroductionWelcometoJavaScriptforKids!Inthisbook,you’lllearntoprogramwithJavaScript,thelanguageoftheWeb.Butmorethanthat,you’llbecomeaprogrammer—someonewhonotonlyusescomputersbutalsocontrolsthem.Onceyoulearntoprogram,youcanbendcomputerstoyourwillandmakethemdowhateveryouwant!JavaScriptisagreatprogramminglanguagetolearnbecauseit’susedeverywhere.WebbrowserslikeChrome,Firefox,andInternetExploreralluseJavaScript.WiththepowerofJavaScript,webprogrammerscantransformwebpagesfromsimpledocumentsintofull-blowninteractiveapplicationsandgames.Butyou’renotlimitedtobuildingwebpages.JavaScriptcanrunonwebserverstocreatewholewebsitesandcanevenbeusedtocontrolrobotsandotherhardware!
WhoShouldReadThisBook?ThisbookisforanyonewhowantstolearnJavaScriptortostartprogrammingforthefirsttime.Thebookisdesignedtobekidfriendly,butitcanserveasafirstprogrammingbookforbeginnersofallages.Withthisbook,you’llbuildupyourknowledgeofJavaScriptgradually,startingwithJavaScript’ssimpledatatypes,beforemovingontocomplextypes,controlstructures,andfunctions.Afterthatyou’lllearnhowtowritecodethatreactswhentheusermovesthemouseorpressesakeyonthekeyboard.Finally,you’lllearnaboutthecanvaselement,whichletsyouuseJavaScripttodrawandanimateanythingyoucanimagine!Alongtheway,you’llcreateafewgamestostretchyourprogrammingskillsandputwhatyou’velearnedtogooduse.
HowtoReadThisBookFirstoff,readitinorder!Thatmightsoundlikeasillythingtosay,butlotsofpeoplewanttojumpstraightintothefunstuff,likemakinggames.Buteachchapterismeanttobuildonwhatwascoveredinearlierchapters,soifyoubeginatthebeginning,you’llhaveaneasiertimewhenyougettothegames.Programminglanguagesarelikespokenlanguages:youhavetolearnthegrammarandthevocabulary,andthistakestime.Theonlywaytoimproveisbywriting(andreading)alotofcode.AsyouwritemoreandmoreJavaScript,you’llfindcertainpartsofthelanguagebecomesecondnature,andeventuallyyou’llbecomeafluentwriterofJavaScript.Asyouread,Iencourageyoutotypeoutandtestthecodeexamplesthroughoutthebook.Ifyoudon’tfullyunderstandwhat’sgoingon,trymakingsmallchangestoseewhateffecttheyhave.Ifthechangesdon’thavetheeffectyouexpected,seeifyoucanfindoutwhy.Aboveall,workthroughthe“TryItOut”andProgrammingChallengessections.Typingoutthecodethatappearsinthebookisagoodfirststep,butyou’llunderstandprogrammingatadeeperlevelwhenyoustartwritingyourowncode.Ifyoufindachallengeinteresting,thenkeepatit!Comeupwithyourownchallengestobuildevenmoreontotheprogramsyou’vewritten.You’llfindsamplesolutionstotheprogrammingchallenges(aswellasthecodefilesforthegamesandotherexamples)athttp://nostarch.com/javascriptforkids/.Trylookingatthesolutionsafteryou’vesolvedachallenge,soyoucancompareyourapproachtomine.Or,ifyou’restuck,youcancheckthesolutionforhints.Butrememberthatthesearejustsamplesolutions.Therearemany,manydifferentwaystoaccomplishthesamegoalinJavaScript,sodon’tworryifyouendupwithacompletelydifferentsolutionfrommine!Ifyoucomeacrossawordandyoudon’tknowwhatitmeans,checktheglossaryatthebackofthebook.Theglossarycontainsdefinitionsformanyoftheprogrammingtermsyou’llencounterinthisbook.
What’sinthisBook?Chapter1givesyouaquickintroductiontoJavaScriptandgetsyoustartedwritingJavaScriptinGoogleChrome.Chapter2introducesvariablesandthebasicdatatypesusedbyJavaScript:numbers,strings,andBooleans.Chapter3isallaboutarrays,whichareusedtoholdlistsofotherpiecesofdata.Chapter4isaboutobjects,whichcontainpairsofkeysandvalues.Chapter5isanintroductiontoHTML,thelanguageusedtocreatewebpages.Chapter6showsyouhowtogainmorecontroloveryourcodeusingifstatements,forloops,andothercontrolstructures.Chapter7putstogethereverythingyou’velearnedsofartocreateasimpleHangmanword-guessinggame.Chapter8showsyouhowtowriteyourownfunctionssoyoucangrouptogetherandreuseblocksofcode.Chapter9introducesjQuery,atoolthatmakesiteasytocontrolwebpagesusingJavaScript.Chapter10showsyouhowtousetimeouts,intervals,andeventhandlerstomakeyourcodemoreinteractive.Chapter11usesfunctions,jQuery,andeventhandlerstocreateagamecalledChapter11Chapter12teachesastyleofprogrammingcalledobject-orientedprogramming.Chapter13introducesthecanvaselement,whichallowsyoutodrawgraphicsonawebpagewithJavaScript.Chapter14buildsontheanimationtechniquesyoulearnedinChapter10soyoucancreateanimationswithcanvas,andChapter15showsyouhowtocontrolthosecanvasanimationswiththekeyboard.InChapter16andChapter17,you’llprogramacompleteSnakegame,usingeverythingyoulearnedintheprevious15chapters!TheAfterwordgivesyousomeideasforhowtolearnevenmoreaboutprogramming.TheGlossarycontainsdefinitionsformanyofthenewwordsyou’llencounter.
HaveFun!Onelastthingtoremember:Havefun!Programmingcanbeaplayfulandcreativeactivity,justlikedrawingorplayingagame(infact,you’llbedrawingandplayinggameswithJavaScriptalotinthisbook).Onceyougetthehangofhowtowritecode,theonlylimitisyourimagination.Welcometotheamazingworldofcomputerprogramming—Ihopeyouhaveablast!
PartI.Fundamentals
Chapter1.WhatIsJavaScript?Computersareincrediblypowerfulmachines,capableofperformingamazingfeatslikeplayingcompetitivechess,servingthousandsofwebpages,ormakingmillionsofcomplexcalculationsinlessthanafewseconds.Butdeepdown,computersareactuallyprettydumb.Computerscanonlydoexactlywhatwehumanstellthemtodo.Wetellcomputershowtobehaveusingcomputerprograms,whicharejustsetsofinstructionsforthecomputerstofollow.Withoutprograms,computerscan’tdoanythingatall!
MeetJavaScriptEvenworse,computerscan’tunderstandEnglishoranyotherspokenlanguage.ComputerprogramsarewritteninaprogramminglanguagelikeJavaScript.YoumightnothaveheardofJavaScriptbefore,butyou’vecertainlyusedit.TheJavaScriptprogramminglanguageisusedtowriteprogramsthatruninwebpages.JavaScriptcancontrolhowawebpagelooksormakethepagerespondwhenaviewerclicksabuttonormovesthemouse.SiteslikeGmail,Facebook,andTwitteruseJavaScripttomakeiteasiertosendemail,postcomments,orbrowsewebsites.Forexample,whenyou’reonTwitterreadingtweetsfrom@nostarchandyouseemoretweetsatthebottomofthepageasyouscrolldown,that’sJavaScriptinaction.YouonlyhavetovisitacoupleofwebsitestoseewhyJavaScriptissoexciting.
JavaScriptletsyouplaymusicandcreateamazingvisualeffects.Forexample,youcanflythroughaninteractivemusicvideocreatedbyHelloEnjoyforEllieGoulding’ssong“Lights”(http://lights.helloenjoy.com/),asshowninFigure1-1.JavaScriptletsyoubuildtoolsforotherstomaketheirownart.Patatap(http://www.patatap.com/)isakindofvirtual“drummachine”thatcreatesallkindsofcoolnoises—andcoolanimationstogoalongwiththem—asshowninFigure1-2.
Figure1-1.YoucontroltheflashingcursorinHelloEnjoy’s“Lights”musicvideo.
Figure1-2.WhenyouvisitPatatap,trypressingabunchofkeystomakedifferentnoises!
JavaScriptletsyouplayfungames.CubeSlam(https://www.cubeslam.com/)isa3Dre-creationoftheclassicgamePong,whichlooksalittlelikeairhockey.Youcanplayagainstoneofyourfriendsoracomputer-generatedbear,asshowninFigure1-3.
Figure1-3.TheCubeSlamgameisprogrammedentirelyinJavaScript!
WhyLearnJavaScript?JavaScriptisn’ttheonlyprogramminglanguageoutthere—infact,thereareliterallyhundredsofprogramminglanguages.ButtherearemanyreasonstolearnJavaScript.Forone,it’saloteasier(andmorefun)tolearnthanmanyotherprogramminglanguages.Butperhapsbestofall,inordertowriteandrunJavaScriptprograms,allyouneedisawebbrowserlikeInternetExplorer,MozillaFirefox,orGoogleChrome.EverywebbrowsercomeswithaJavaScriptinterpreterthatunderstandshowtoreadJavaScriptprograms.Onceyou’vewrittenaJavaScriptprogram,youcansendpeoplealinktoit,andtheycanrunitinawebbrowserontheircomputer,too!(SeeSharingYourCodeUsingJSFiddle.)
WritingSomeJavaScriptLet’swriteabitofsimpleJavaScriptinGoogleChrome(http://www.google.com/chrome/).InstallChromeonyourcomputer(ifit’snotalreadyinstalled),andthenopenitandtypeabout:blankintheaddressbar.NowpressENTERandyou’llseeablankpage,liketheoneinFigure1-4.We’llbeginbycodinginChrome’sJavaScriptconsole,whichisasecretwayprogrammerscantestoutshortJavaScriptprograms.OnMicrosoftWindowsorLinux,holddowntheCTRLandSHIFTkeysandpressJ.OnMacOS,holddowntheCOMMANDandOPTIONkeysandpressJ.Ifyou’vedoneeverythingcorrectly,youshouldseeablankwebpageand,beneaththat,ablinkingcursor(|)nexttoarightanglebracket(>),asshowninFigure1-4.That’swhereyou’llwriteJavaScript!
NOTE
TheChromeconsolewillcoloryourcodetext;forexample,thetextyouinputwillbeblue,andoutputwillbecoloredbasedonitstype.Inthisbook,we’llusesimilarcolorsforourcodetextwhereverwe’reusingtheconsole.
Figure1-4.GoogleChrome’sJavaScriptconsole
WhenyouentercodeatthecursorandpressENTER,JavaScriptshouldrun,orexecute,yourcodeanddisplaytheresult(ifany)onthenextline.Forexample,typethisintotheconsole:
3+4;
NowpressENTER.JavaScriptshouldoutputtheanswer(7)tothissimplebitofadditiononthefollowingline:
3+4;
7
Well,that’seasyenough.Butisn’tJavaScriptmorethanaglorifiedcalculator?Let’strysomethingelse.
TheStructureofaJavaScriptProgramLet’screatesomethingabitsillier—aJavaScriptprogramtoprintaseriesofcatfacesthatlooklikethis:
=^.^=
Unlikeouradditionprogram,thisJavaScriptprogramwilltakeupmultiplelines.Totypetheprogramintotheconsole,you’llhavetoaddnewlinesbypressingSHIFT-ENTERattheendofeachline.(IfyoujustpressENTER,Chromewilltrytoexecutewhatyou’vewritten,andtheprogramwon’tworkasexpected.Iwarnedyouthatcomputersweredumb!)
Typethisintoyourbrowserconsole://Drawasmanycatsasyouwant!
vardrawCats=function(howManyTimes){
for(vari=0;i<howManyTimes;i++){
console.log(i+"=^.^=");
}
};
drawCats(10);//Youcanputanynumberhereinsteadof10.
Attheveryend,pressENTERinsteadofSHIFT-ENTER.Whenyoudothat,youshouldseethefollowingoutput:
0=^.^=
1=^.^=
2=^.^=
3=^.^=
4=^.^=
5=^.^=
6=^.^=
7=^.^=
8=^.^=
9=^.^=
Ifyoumadeanytypos,youroutputmightlookverydifferentoryoumightgetanerror.That’swhatImeanwhenIsaycomputersaredumb—evenasimplepieceofcodemustbeperfectforacomputertounderstandwhatyouwantittodo!
Iwon’tgothroughexactlyhowthiscodeworksfornow(we’llreturntothisprograminChapter8),butlet’slookatsomeofthefeaturesofthisprogramandofJavaScriptprogramsingeneral.
SyntaxOurprogramincludeslotsofsymbols,includingparentheses(),semicolons;,curlybrackets{},plussigns+,andafewwordsthatmightseemmysteriousatfirst(likevarandconsole.log).TheseareallpartofJavaScript’ssyntax—thatis,JavaScript’srulesforhowtocombinesymbolsandwordstocreateworkingprograms.Whenyou’relearninganewprogramminglanguage,oneofthetrickiestpartsisgettingusedtotherulesforhowtowritedifferentkindsofinstructionstothecomputer.Whenyou’refirststartingout,it’seasytoforgetwhentoincludeparentheses,ortomixuptheorderinwhichyouneedtoincludecertainvalues.Butasyoupractice,you’llstarttogetthehangofit.Inthisbook,we’llgoslowandsteady,introducingnewsyntaxlittlebylittlesothatyoucanbuildincreasinglypowerfulprograms.
CommentsThefirstlineinourcatsprogramisthis:
//Drawasmanycatsasyouwant!
Thisiscalledacomment.Programmersusecommentstomakeiteasierforotherprogrammerstoreadandunderstandtheircode.Thecomputerignorescommentscompletely.CommentsinJavaScriptstartwithtwoforwardslashes(//).Everythingfollowingtheslashes(onthesameline)isignoredbytheJavaScriptinterpreter,sothecommentsdon’thaveanyeffectonhowaprogramisexecuted—theyarejusttheretoprovideadescription.Inthecodeinthisbook,you’llseecommentsthatdescribewhat’shappeninginthecode.Asyouwriteyourowncode,addyourowncomments.Thenwhenyoulookatyourcodelater,yourcommentswillremindyouhowthecodeworksandwhat’shappeningineachstep.There’sanothercodecommentonthelastlineofourprogram.Remember,everythingafterthat//isn’trunbythecomputer!
drawCats(10);//Youcanputanynumberhereinsteadof10.
Codecommentscanbeontheirownline,ortheycancomeafteryourcode.Ifyouputthe//atthefront,likethis:
//drawCats(10);
...nothingwillhappen!Chromeseesthewholelineasacomment,evenifit’sJavaScript.OnceyoustartreadingJavaScriptcodeoutinthewildworld,you’llalsoseecommentsthatlooklikethis:
/*
Drawasmanycats
asyouwant!
*/
Thisisadifferentstyleofcommenting,whichistypicallyusedforcommentsthatarelongerthanoneline.Butitdoesthesamething:everythingbetweenthe/*andthe*/isacommentthatthecomputerwon’trun.
WhatYouLearnedInthischapter,youlearnedabitaboutwhatJavaScriptisandwhatitcanbeusedfor.YoualsolearnedhowtorunJavaScriptusingtheGoogleChromebrowserandtriedoutasampleprogram.Allofthecodeexamplesinthisbook,unlessIsayotherwise,can(andshould!)beusedinChrome’sJavaScriptconsole.Don’tjustreadthecode—trytypingthingsout!It’stheonlywaytolearntoprogram.Inthenextchapter,you’llstartlearningthefundamentalsofJavaScript,beginningwiththethreebasictypesofinformationyoucanworkwith:numbers,strings,andBooleans.
Chapter2.DataTypesandVariablesProgrammingisallaboutmanipulatingdata,butwhatisdata?Dataisinformationthatwestoreinourcomputerprograms.Forexample,yournameisapieceofdata,andsoisyourage.Thecolorofyourhair,howmanysiblingsyouhave,whereyoulive,whetheryou’remaleorfemale—thesethingsarealldata.InJavaScript,therearethreebasictypesofdata:numbers,strings,andBooleans.Numbersareusedforrepresenting,well,numbers!Forexample,youragecanberepresentedasanumber,andsocanyourheight.NumbersinJavaScriptlooklikethis:
5;
Stringsareusedtorepresenttext.YournamecanberepresentedasastringinJavaScript,ascanyouremailaddress.Stringslooklikethis:
"Hi,I'mastring";
Booleansarevaluesthatcanbetrueorfalse.Forexample,aBooleanvalueaboutyouwouldbewhetheryouwearglasses.Anothercouldbewhetheryoulikebroccoli.ABooleanlookslikethis:
true;
Therearedifferentwaystoworkwitheachdatatype.Forexample,youcanmultiplytwonumbers,butyoucan’tmultiplytwostrings.Withastring,youcanaskforthefirstfivecharacters.WithBooleans,youcanchecktoseewhethertwovaluesarebothtrue.Thefollowingcodeexampleillustrateseachofthesepossibleoperations.
99*123;
12177
"Thisisalongstring".slice(0,4);
"This"
true&&false;
false
AlldatainJavaScriptisjustacombinationofthesetypesofdata.Inthischapter,we’lllookateachtypeinturnandlearndifferentwaystoworkwitheachtype.
NOTE
Youmayhavenoticedthatallofthesecommandsendwithasemicolon(;).SemicolonsmarktheendofaparticularJavaScriptcommandorinstruction(alsocalledastatement),sortofliketheperiodattheendofasentence.
NumbersandOperatorsJavaScriptletsyouperformbasicmathematicaloperationslikeaddition,subtraction,multiplication,anddivision.Tomakethesecalculations,weusethesymbols+,-,*,and/,whicharecalledoperators.YoucanusetheJavaScriptconsolejustlikeacalculator.We’vealreadyseenoneexample,addingtogether3and4.Let’strysomethingharder.What’s12,345plus56,789?
12345+56789;
69134
That’snotsoeasytoworkoutinyourhead,butJavaScriptcalculateditinnotime.Youcanaddmultiplenumberswithmultipleplussigns:
22+33+44;
99
JavaScriptcanalsodosubtraction...1000-17;
983
andmultiplication,usinganasterisk...123*456;
56088
anddivision,usingaforwardslash...12345/250;
49.38
Youcanalsocombinethesesimpleoperationstomakesomethingmorecomplex,likethis:1234+57*3-31/4;
1397.25
Hereitgetsabittricky,becausetheresultofthiscalculation(theanswer)willdependontheorderthatJavaScriptdoeseachoperation.Inmath,theruleisthatmultiplicationanddivisionalwaystakeplacebeforeadditionandsubtraction,andJavaScriptfollowsthisruleaswell.
Figure2-1.Theorderofoperations:multiplication,division,addition,subtraction
Figure2-1showstheorderJavaScriptwouldfollow.First,JavaScriptmultiplies57*3andgets171(showninred).Thenitdivides31/4toget7.75(showninblue).Nextitadds1234+171toget1405(showningreen).Finallyitsubtracts1405-7.75toget1397.25,whichisthefinalresult.Whatifyouwantedtodotheadditionandthesubtractionfirst,beforedoingthemultiplicationanddivision?Forexample,sayyouhave1brotherand3sistersand8candies,andyouwanttosplitthe
candiesequallyamongyour4siblings?(You’vealreadytakenyourshare!)Youwouldhavetodivide8byyournumberofsiblings.Here’sanattempt:
8/1+3;
11
Thatcan’tberight!Youcan’tgiveeachsibling11candieswhenyou’veonlygot8!TheproblemisthatJavaScriptdoesdivisionbeforeaddition,soitdivides8by1(whichequals8)andthenadds3tothat,givingyou11.TofixthisandmakeJavaScriptdotheadditionfirst,wecanuseparentheses:
8/(1+3);
2
That’smorelikeit!Twocandiestoeachofyoursiblings.TheparenthesesforceJavaScripttoadd1and3beforedividing8by4.
TRYITOUT!
Let’ssayyourfriendistryingtouseJavaScripttoworkouthowmanyballoonstobuy.She’sthrowingapartyandwantseveryonetohave2balloonstoblowup.Therewereoriginally15peoplecoming,butthensheinvited9more.Shetriesthefollowingcode:
15+9*2;
33
Butthatdoesn’tseemright.
Theproblemisthatthemultiplicationishappeningbeforetheaddition.HowwouldyouaddparenthesestomakesurethatJavaScriptdoestheadditionfirst?Howmanyballoonsdoesyourfriendreallyneed?
VariablesJavaScriptletsyougivenamestovaluesusingvariables.Youcanthinkofavariableasaboxthatyoucanfitonethingin.Ifyouputsomethingelseinit,thefirstthinggoesaway.Tocreateanewvariable,usethekeywordvar,followedbythenameofthevariable.AkeywordisawordthathasspecialmeaninginJavaScript.Inthiscase,whenwetypevar,JavaScriptknowsthatweareabouttoenterthenameofanewvariable.Forexample,here’showyou’dmakeanewvariablecallednick:
varnick;
undefined
We’vecreatedanewvariablecallednick.Theconsolespitsoutundefinedinresponse.Butthisisn’tanerror!That’sjustwhatJavaScriptdoeswheneveracommanddoesn’treturnavalue.What’sareturnvalue?Well,forexample,whenyoutyped12345+56789;,theconsolereturnedthevalue69134.CreatingavariableinJavaScriptdoesn’treturnavalue,sotheinterpreterprintsundefined.Togivethevariableavalue,usetheequalsign:
varage=12;
undefined
Settingavalueiscalledassignment(weareassigningthevalue12tothevariableage).Again,undefinedisprinted,becausewe’recreatinganothernewvariable.(Intherestofmyexamples,Iwon’tshowtheoutputwhenit’sundefined.)Thevariableageisnowinourinterpreterandsettothevalue12.Thatmeansthatifyoutypeageonitsown,theinterpreterwillshowyouitsvalue:
age;
12
Cool!Thevalueofthevariableisn’tsetinstone,though(they’recalledvariablesbecausetheycanvary),andifyouwanttoupdateit,justuse=again:
age=13;
13
ThistimeIdidn’tusethevarkeyword,becausethevariableagealreadyexists.Youneedtousevaronlywhenyouwanttocreateavariable,notwhenyouwanttochangethevalueofavariable.Noticealso,becausewe’renotcreatinganewvariable,thevalue13isreturnedfromtheassignmentandprintedonthenextline.Thisslightlymorecomplexexamplesolvesthecandiesproblemfromearlier,withoutparentheses:
varnumberOfSiblings=1+3;
varnumberOfCandies=8;
numberOfCandies/numberOfSiblings;
2
FirstwecreateavariablecallednumberOfSiblingsandassignitthevalueof1+3(whichJavaScriptworksouttobe4).ThenwecreatethevariablenumberOfCandiesandassign8toit.Finally,wewritenumberOfCandies/numberOfSiblings.BecausenumberOfCandiesis8andnumberOfSiblingsis4,JavaScriptworksout8/4andgivesus2.
NamingVariablesBecarefulwithyourvariablenames,becauseit’seasytomisspellthem.Evenifyoujustgetthecapitalizationwrong,theJavaScriptinterpreterwon’tknowwhatyoumean!Forexample,ifyouaccidentallyusedalowercasecinnumberOfCandies,you’dgetanerror:
numberOfcandies/numberOfSiblings;
ReferenceError:numberOfcandiesisnotdefined
Unfortunately,JavaScriptwillonlydoexactlywhatyouaskittodo.Ifyoumisspellavariablename,JavaScripthasnoideawhatyoumean,anditwilldisplayanerrormessage.AnothertrickythingaboutvariablenamesinJavaScriptisthattheycan’tcontainspaces,whichmeanstheycanbedifficulttoread.Icouldhavenamedmyvariablenumberofcandieswithnocapitalletters,whichmakesitevenhardertoreadbecauseit’snotclearwherethewordsend.Isthisvariable“numberofcandies”or“numberofcandies”?Withoutthecapitalletters,it’shardtotell.OnecommonwaytogetaroundthisistostarteachwordwithacapitalletterasinNumberOfCandies.(Thisconventioniscalledcamelcasebecauseitsupposedlylookslikethehumpsonacamel.)
Thestandardpracticeistohavevariablesstartwithalowercaseletter,soit’scommontocapitalizeeachwordexceptforthefirstone,likethis:numberOfCandies.(I’llfollowthisversionofthecamelcaseconventionthroughoutthisbook,butyou’refreetodowhateveryouwant!)
CreatingNewVariablesUsingMathYoucancreatenewvariablesbydoingsomemathonolderones.Forexample,youcanusevariablestofindouthowmanysecondsthereareinayear—andhowmanysecondsoldyouare!Let’sstartbyfindingthenumberofsecondsinanhour.
SecondsinanHourFirstwecreatetwonewvariablescalledsecondsInAMinuteandminutesInAnHourandmakethemboth60(because,asweknow,thereare60secondsinaminuteand60minutesinanhour).ThenwecreateavariablecalledsecondsInAnHourandsetitsvaluetotheresultofmultiplyingsecondsInAMinuteandminutesInAnHour.At➊,weentersecondsInAnHour,whichislikesaying,“TellmethevalueofsecondsInAnHourrightnow!”JavaScriptthengivesyoutheanswer:it’s3600.
varsecondsInAMinute=60;
varminutesInAnHour=60;
varsecondsInAnHour=secondsInAMinute*minutesInAnHour;
➊secondsInAnHour;
3600
SecondsinaDayNowwecreateavariablecalledhoursInADayandsetitto24.NextwecreatethevariablesecondsInADayandsetitequaltosecondsInAnHourmultipliedbyhoursInADay.WhenweaskforthevaluesecondsInADayat➊,weget86400,whichisthenumberofsecondsinaday.
varhoursInADay=24;
varsecondsInADay=secondsInAnHour*hoursInADay;
➊secondsInADay;
86400
SecondsinaYearFinally,wecreatethevariablesdaysInAYearandsecondsInAYear.ThedaysInAYearvariableisassignedthevalue365,andthevariablesecondsInAYearisassignedthevalueofsecondsInADaymultipliedbydaysInAYear.Finally,weaskforthevalueofsecondsInAYear,whichis31536000(morethan31million)!
vardaysInAYear=365;
varsecondsInAYear=secondsInADay*daysInAYear;
secondsInAYear;
31536000
AgeinSecondsNowthatyouknowthenumberofsecondsinayear,youcaneasilyfigureouthowoldyouarein
seconds(tothenearestyear).Forexample,asI’mwritingthis,I’m29:varage=29;
age*secondsInAYear;
914544000
Tofigureoutyourageinseconds,enterthesamecode,butchangethevalueinagetoyourage.Orjustleaveouttheagevariablealtogetheranduseanumberforyourage,likethis:
29*secondsInAYear;
914544000
I’mmorethan900millionsecondsold!Howmanysecondsoldareyou?
IncrementingandDecrementingAsaprogrammer,you’lloftenneedtoincreaseordecreasethevalueofavariablecontaininganumberby1.Forexample,youmighthaveavariablethatcountsthenumberofhigh-fivesyoureceivedtoday.Eachtimesomeonehigh-fivesyou,you’dwanttoincreasethatvariableby1.Increasingby1iscalledincrementing,anddecreasingby1iscalleddecrementing.Youincrementanddecrementusingtheoperators++and--.
varhighFives=0;
++highFives;
1
++highFives;
2
--highFives;
1
Whenweusethe++operator,thevalueofhighFivesgoesupby1,andwhenweusethe--operator,itgoesdownby1.Youcanalsoputtheseoperatorsafterthevariable.Thisdoesthesamething,butthevaluethatgetsreturnedisthevaluebeforetheincrementordecrement.
highFives=0;
highFives++;
0
highFives++;
1
highFives;
2
Inthisexample,wesethighFivesto0again.WhenwecallhighFives++,thevariableisincremented,butthevaluethatgetsprintedisthevaluebeforetheincrementhappened.Youcanseeattheend(aftertwoincrements)thatifweaskforthevalueofhighFives,weget2.
+=(plus-equals)and–=(minus-equals)Toincreasethevalueofavariablebyacertainamount,youcouldusethiscode:
varx=10;
x=x+5;
x;
15
Here,westartoutwithavariablecalledx,setto10.Then,weassignx+5tox.Becausexwas10,x+5willbe15.Whatwe’redoinghereisusingtheoldvalueofxtoworkoutanewvalueforx.Therefore,x=x+5reallymeans“add5tox.”JavaScriptgivesyouaneasierwayofincreasingordecreasingavariablebyacertainamount,withthe+=and-=operators.Forexample,ifwehaveavariablex,thenx+=5isthesameassayingx=x+5.The-=operatorworksinthesameway,sox-=9wouldbethesameasx=x-9(“subtract9fromx”).Here’sanexampleusingbothoftheseoperatorstokeeptrackofascoreinavideogame:
varscore=10;
score+=7;
17
score-=3;
14
Inthisexample,westartwithascoreof10byassigningthevalue10tothevariablescore.Thenwebeatamonster,whichincreasesscoreby7usingthe+=operator.(score+=7isthesameasscore=score+7.)Beforewebeatthemonster,scorewas10,and10+7is17,sothisoperationsetsscoreto17.Afterourvictoryoverthemonster,wecrashintoameteorandscoreisreducedby3.Again,score-=3isthesameasscore=score-3.Becausescoreis17atthispoint,score-3is14,andthatvaluegetsreassignedtoscore.
TRYITOUT!
Therearesomeotheroperatorsthataresimilarto+=and-=.Forexample,thereare*=and/=.Whatdoyouthinkthesedo?Givethematry:
varballoons=100;
balloons*=2;
???
Whatdoesballoons*=2do?Nowtrythis:varballoons=100;
balloons/=4;
???
Whatdoesballoons/=4do?
StringsSofar,we’vejustbeenworkingwithnumbers.Nowlet’slookatanothertypeofdata:strings.StringsinJavaScript(asinmostprogramminglanguages)arejustsequencesofcharacters,whichcanincludeletters,numbers,punctuation,andspaces.WeputstringsbetweenquotessoJavaScriptknowswheretheystartandend.Forexample,here’saclassic:
"Helloworld!";
"Helloworld!"
Toenterastring,justtypeadoublequotationmark(")followedbythetextyouwantinthestring,andthenclosethestringwithanotherdoublequote.Youcanalsousesinglequotes('),buttokeepthingssimple,we’lljustbeusingdoublequotesinthisbook.Youcansavestringsintovariables,justlikenumbers:
varmyAwesomeString="SomethingREALLYawesome!!!";
There’salsonothingstoppingyoufromassigningastringtoavariablethatpreviouslycontainedanumber:
varmyThing=5;
myThing="thisisastring";
"thisisastring"
Whatifyouputanumberbetweenquotes?Isthatastringoranumber?InJavaScript,astringisastring(evenifithappenstohavesomecharactersthatarenumbers).Forexample:
varnumberNine=9;
varstringNine="9";
numberNineisanumber,andstringNineisastring.Toseehowthesearedifferent,let’stryaddingthemtogether:
numberNine+numberNine;
18
stringNine+stringNine;
"99"
Whenweaddthenumbervalues9and9,weget18.Butwhenweusethe+operatoron"9"and"9",thestringsaresimplyjoinedtogethertoform"99".
JoiningStringsAsyoujustsaw,youcanusethe+operatorwithstrings,buttheresultisverydifferentfromusingthe+operatorwithnumbers.Whenyouuse+tojointwostrings,youmakeanewstringwiththesecondstringattachedtotheendofthefirststring,likethis:
vargreeting="Hello";
varmyName="Nick";
greeting+myName;
"HelloNick"
Here,wecreatetwovariables(greetingandmyName)andassigneachastringvalue("Hello"and"Nick",respectively).Whenweaddthesetwovariablestogether,thestringsarecombinedtomakeanewstring,"HelloNick".Thatdoesn’tlookright,though—thereshouldbeaspacebetweenHelloandNick.ButJavaScriptwon’tputaspacethereunlesswespecificallytellittobyaddingaspaceinoneoftheoriginalstrings:
➊vargreeting="Hello";
varmyName="Nick";
greeting+myName;
"HelloNick"
Theextraspaceinsidethequotesat➊putsaspaceinthefinalstringaswell.Youcandoalotmorewithstringsotherthanjustaddingthemtogether.Herearesomeexamples.
FindingtheLengthofaStringTogetthelengthofastring,justadd.lengthtotheendofit.
"Supercalifragilisticexpialidocious".length;
34
Youcanadd.lengthtotheendoftheactualstringortoavariablethatcontainsastring:varjava="Java";
java.length;
4
varscript="Script";
script.length;
6
varjavascript=java+script;
javascript.length;
10
Hereweassignthestring"Java"tothevariablejavaandthestring"Script"tothevariablescript.Thenweadd.lengthtotheendofeachvariabletodeterminethelengthofeachstring,aswellasthelengthofthecombinedstrings.NoticethatIsaidyoucanadd.lengthto“theactualstringortoavariablethatcontainsastring.”Thisillustratessomethingveryimportantaboutvariables:anywhereyoucanuseanumberorastring,youcanalsouseavariablecontaininganumberorastring.
GettingaSingleCharacterfromaStringSometimesyouwanttogetasinglecharacterfromastring.Forexample,youmighthaveasecretcodewherethemessageismadeupofthesecondcharacterofeachwordinalistofwords.You’dneedtobeabletogetjustthesecondcharactersandjointhemalltogethertocreateanewword.Togetacharacterfromaparticularpositioninastring,usesquarebrackets,[].Justtakethestring,orthevariablecontainingthestring,andputthenumberofthecharacteryouwantinapairofsquarebracketsattheend.Forexample,togetthefirstcharacterofmyName,usemyName[0],likethis:
varmyName="Nick";
myName[0];
"N"
myName[1];
"i"
myName[2];
"c"
Noticethattogetthefirstcharacterofthestring,weuse0ratherthan1.That’sbecauseJavaScript(likemanyotherprogramminglanguages)startscountingatzero.Thatmeanswhenyouwantthefirstcharacterofastring,youuse0;whenyouwantthesecondone,youuse1;andsoon.Let’stryoutoursecretcode,wherewehideamessageinsomewords’secondcharacters.Here’showtofindthesecretmessageinasequenceofwords:
varcodeWord1="are";
varcodeWord2="tubas";
varcodeWord3="unsafe";
varcodeWord4="?!";
codeWord1[1]+codeWord2[1]+codeWord3[1]+codeWord4[1];
"run!"
Again,noticethattogetthesecondcharacterofeachstring,weuse1.
CuttingUpStringsTo“cutoff”apieceofabigstring,youcanuseslice.Forexample,youmightwanttograbthefirstbitofalongmoviereviewtoshowasateaseronyourwebsite.Touseslice,putaperiodafterastring(oravariablecontainingastring),followedbythewordsliceandopeningandclosingparentheses.Insidetheparentheses,enterthestartandendpositionsofthesliceofthestringyouwant,separatedbyacomma.Figure2-2showshowtouseslice.
Figure2-2.Howtouseslicetogetcharactersfromastring
Forexample:varlongString="Mylongstringislong";
longString.slice(3,14);
"longstring"
Thefirstnumberinparenthesesisthenumberofthecharacterthatbeginstheslice,andthesecondnumberisthenumberofthecharacterafterthelastcharacterintheslice.Figure2-3showswhichcharactersthisretrieves,withthestartvalue(3)andstopvalue(14)highlightedinblue.
Figure2-3.Intheexampleabove,slicegrabsthecharactersshowninthegraybox.
HerewebasicallytellJavaScript,“Pullasliceoutofthislongerstringstartingatthecharacteratplace3andkeepgoinguntilyouhitplace14.”Ifyouincludeonlyonenumberintheparenthesesafterslice,thestringthatitsliceswillstartfromthatnumberandcontinueallthewaytotheendofthestring,likethis:
varlongString="Mylongstringislong";
longString.slice(3);
"longstringislong"
ChangingStringstoAllCapitalorAllLowercaseLettersIfyouhavesometextthatyoujustwanttoshout,tryusingtoUpperCasetoturnitallintocapitalletters.
"Hellothere,howareyoudoing?".toUpperCase();
"HELLOTHERE,HOWAREYOUDOING?"
Whenyouuse.toUpperCase()onastring,itmakesanewstringwhereallthelettersareturnedintouppercase.Youcangotheotherwayaround,too:
"hELloTHERE,hOWAREyOudoINg?".toLowerCase();
"hellothere,howareyoudoing?"
Asthenamesuggests,.toLowerCase()makesallofthecharacterslowercase.Butshouldn’tsentencesalwaysstartwithacapitalletter?Howcanwetakeastringandmakethefirstletteruppercasebutturntherestintolowercase?
NOTE
Seeifyoucanfigureouthowtoturn"hELloTHERE,hOWAREyOudoINg?"into"Hellothere,howareyoudoing?"usingthetoolsyoujustlearned.Ifyougetstuck,reviewthesectionsongettingasinglecharacterandusingslice.Onceyou’redone,comebackandhavealookathowIdidit.
Here’soneapproach:➊varsillyString="hELloTHERE,hOWAREyOudoINg?";
➋varlowerString=sillyString.toLowerCase();
➌varfirstCharacter=lowerString[0];
➍varfirstCharacterUpper=firstCharacter.toUpperCase();
➎varrestOfString=lowerString.slice(1);
➏firstCharacterUpper+restOfString;
"Hellothere,howareyoudoing?"
Let’sgothroughthislinebyline.At➊,wecreateanewvariablecalledsillyStringandsavethestringwewanttomodifytothatvariable.At➋,wegetthelowercaseversionofsillyString("hellotherehowareyoudoing?")with.toLowerCase()andsavethatinanewvariablecalledlowerString.
At➌,weuse[0]togetthefirstcharacteroflowerString("h")andsaveitinfirstCharacter(0is
usedtograbthefirstcharacter).Then,at➍,wecreateanuppercaseversionoffirstCharacter("H")andcallthatfirstCharacterUpper.At➎,weuseslicetogetallthecharactersinlowerString,startingfromthesecondcharacter("ellotherehowareyoudoing?")andsavethatinrestOfString.Finally,at➏,weaddfirstCharacterUpper("H")torestOfStringtoget"Hellothere,howareyoudoing?".Becausevaluesandvariablescanbesubstitutedforeachother,wecouldturnlines➋through➏intojustoneline,likethis:
varsillyString="hELloTHERE,hOWAREyOudoINg?";
sillyString[0].toUpperCase()+sillyString.slice(1).toLowerCase();
"Hellothere,howareyoudoing?"
Itcanbeconfusingtofollowalongwithcodewrittenthisway,though,soit’sagoodideatousevariablesforeachstepofacomplicatedtasklikethis—atleastuntilyougetmorecomfortablereadingthiskindofcomplexcode.
BooleansNowforBooleans.ABooleanvalueissimplyavaluethat’seithertrueorfalse.Forexample,here’sasimpleBooleanexpression.
varjavascriptIsCool=true;
javascriptIsCool;
true
Inthisexample,wecreatedanewvariablecalledjavascriptIsCoolandassignedtheBooleanvaluetruetoit.Onthesecondline,wegetthevalueofjavascriptIsCool,which,ofcourse,istrue!
LogicalOperatorsJustasyoucancombinenumberswithmathematicaloperators(+,-,*,/,andsoon),youcancombineBooleanvalueswithBooleanoperators.WhenyoucombineBooleanvalueswithBooleanoperators,theresultwillalwaysbeanotherBooleanvalue(eithertrueorfalse).ThethreemainBooleanoperatorsinJavaScriptare&&,||,and!.Theymaylookabitweird,butwithalittlepractice,they’renothardtouse.Let’strythemout.
&&(and)&&means“and.”Whenreadingaloud,peoplecallit“and,”“andand,”or“ampersand-ampersand.”(Ampersandisthenameofthecharacter&.)Usethe&&operatorwithtwoBooleanvaluestoseeifthey’rebothtrue.Forexample,beforeyougotoschool,youwanttomakesurethatyou’vehadashowerandyouhaveyourbackpack.Ifbotharetrue,youcangotoschool,butifoneorbotharefalse,youcan’tleaveyet.
varhadShower=true;
varhasBackpack=false;
hadShower&&hasBackpack;
false
HerewesetthevariablehadShowertotrueandthevariablehasBackpacktofalse.WhenweenterhadShower&&hasBackpack,wearebasicallyaskingJavaScript,“Arebothofthesevaluestrue?”Sincetheyaren’tbothtrue(youdon’thaveyourbackpack),JavaScriptreturnsfalse(you’renotreadyforschool).
Let’strythisagain,withbothvaluessettotrue:varhadShower=true;
varhasBackpack=true;
hadShower&&hasBackpack;
true
NowJavaScripttellsusthathadShower&&hasBackpackistrue.You’rereadyforschool!
||(or)TheBooleanoperator||means“or.”Itcanbepronounced“or,”oreven“or-or,”butsomepeoplecallit“pipes,”becauseprogrammerscallthe|characterapipe.YoucanusethisoperatorwithtwoBooleanvaluestofindoutwhethereitheroneistrue.Forexample,sayyou’restillgettingreadytogotoschoolandyouneedtotakeapieceoffruitforlunch,butitdoesn’tmatterwhetheryoutakeanappleoranorangeorboth.YoucanuseJavaScripttoseewhetheryouhaveatleastone,likethis:
varhasApple=true;
varhasOrange=false;
hasApple||hasOrange;
true
hasApple||hasOrangewillbetrueifeitherhasAppleorhasOrangeistrue,orifbotharetrue.Butifbotharefalse,theresultwillbefalse(youdon’thaveanyfruit).
!(not)!justmeans“not.”Youcancallit“not,”butlotsofpeoplecallit“bang.”(Anexclamationpointissometimescalledabang.)Useittoturnfalseintotrueortrueintofalse.Thisisusefulforworkingwithvaluesthatareopposites.Forexample:
varisWeekend=true;
varneedToShowerToday=!isWeekend;
needToShowerToday;
false
Inthisexample,wesetthevariableisWeekendtotrue.ThenwesetthevariableneedToShowerTodayto!isWeekend.Thebangconvertsthevaluetoitsopposite—soifisWeekendistrue,then!isWeekendisnottrue(it’sfalse).SowhenweaskforthevalueofneedToShowerToday,wegetfalse(youdon’tneedtoshowertoday,becauseit’stheweekend).BecauseneedToShowerTodayisfalse,!needToShowerTodaywillbetrue:
needToShowerToday;
false
!needToShowerToday;
true
Inotherwords,it’struethatyoudonotneedtoshowertoday.
CombininglogicaloperatorsOperatorsgetinterestingwhenyoustartcombiningthem.Forexample,sayyoushouldgotoschoolifit’snottheweekendandyou’veshoweredandyouhaveanappleoryouhaveanorange.WecouldcheckwhetherallofthisistruewithJavaScript,likethis:
varisWeekend=false;
varhadShower=true;
varhasApple=false;
varhasOrange=true;
varshouldGoToSchool=!isWeekend&&hadShower&&(hasApple||hasOrange);
shouldGoToSchool;
true
Inthiscase,it’snottheweekend,youhaveshowered,andyoudon’thaveanapplebutyoudohaveanorange—soyoushouldgotoschool.hasApple||hasOrangeisinparenthesesbecausewewanttomakesureJavaScriptworksoutthatbitfirst.JustasJavaScriptcalculates*before+withnumbers,italsocalculates&&before||inlogical
statements.
ComparingNumberswithBooleansBooleanvaluescanbeusedtoanswerquestionsaboutnumbersthathaveasimpleyesornoanswer.Forexample,imagineyou’rerunningathemeparkandoneoftherideshasaheightrestriction:ridersmustbeatleast60inchestall,ortheymightfallout!Whensomeonewantstogoontherideandtellsyoutheirheight,youneedtoknowifit’sgreaterthanthisheightrestriction.
GreaterThanWecanusethegreater-thanoperator(>)toseeifonenumberisgreaterthananother.Forexample,toseeiftherider’sheight(65inches)isgreaterthantheheightrestriction(60inches),wecouldsetthevariableheightequalto65andthevariableheightRestrictionequalto60,andthenuse>tocomparethetwo:
varheight=65;
varheightRestriction=60;
height>heightRestriction;
true
Withheight>heightRestriction,we’reaskingJavaScripttotelluswhetherthefirstvalueisgreaterthanthesecond.Inthiscase,therideristallenough!Whatifariderwereexactly60inchestall,though?
varheight=60;
varheightRestriction=60;
height>heightRestriction;
false
Ohno!Theriderisn’ttallenough!Butiftheheightrestrictionis60,thenshouldn’tpeoplewhoareexactly60inchesbeallowedin?Weneedtofixthat.Luckily,JavaScripthasanotheroperator,>=,whichmeans“greaterthanorequalto”:
varheight=60;
varheightRestriction=60;
height>=heightRestriction;
true
Good,that’sbetter—60isgreaterthanorequalto60.
LessThanTheoppositeofthegreater-thanoperator(>)istheless-thanoperator(<).Thisoperatormightcomeinhandyifarideweredesignedonlyforsmallchildren.Forexample,saytherider’sheightis60inches,butridersmustbenomorethan48inchestall:
varheight=60;
varheightRestriction=48;
height<heightRestriction;
false
Wewanttoknowiftherider’sheightislessthantherestriction,soweuse<.Because60isnotlessthan48,wegetfalse(someonewhoseheightis60inchesistootallforthisride).And,asyoumayhaveguessed,wecanalsousetheoperator<=,whichmeans“lessthanorequalto”:
varheight=48;
varheightRestriction=48;
height<=heightRestriction;
true
Someonewhois48inchestallisstillallowedtogoontheride.
EqualToTofindoutiftwonumbersareexactlythesame,usethetripleequalsign(===),whichmeansEqualTo.Butbecarefulnottoconfuse===withasingleequalsign(=),because===means“arethesetwonumbersequal?”and=means“savethevalueontherightinthevariableontheleft.”Inotherwords,===asksaquestion,while=assignsavaluetoavariable.
Whenyouuse=,avariablenamehastobeontheleftandthevalueyouwanttosavetothatvariablemustbeontheright.Ontheotherhand,===isjustusedforcomparingtwovaluestoseeifthey’rethesame,soitdoesn’tmatterwhichvalueisonwhichside.Forexample,sayyou’rerunningacompetitionwithyourfriendsChico,Harpo,andGrouchotoseewhocanguessyoursecretnumber,whichis5.Youmakeiteasyonyourfriendsbysayingthatthenumberisbetween1and9,andtheystarttoguess.FirstyousetmySecretNumberequalto5.Yourfirstfriend,Chico,guessesthatit’s3(chicoGuess).Let’sseewhathappensnext:
varmySecretNumber=5;
varchicoGuess=3;
mySecretNumber===chicoGuess;
false
varharpoGuess=7;
mySecretNumber===harpoGuess;
false
vargrouchoGuess=5;
mySecretNumber===grouchoGuess;
true
ThevariablemySecretNumberstoresyoursecretnumber.ThevariableschicoGuess,harpoGuess,andgrouchoGuessrepresentyourfriends’guesses,andweuse===toseewhethereachguessisthesameasyoursecretnumber.Yourthirdfriend,Groucho,winsbyguessing5.Whenyoucomparetwonumberswith===,yougettrueonlywhenbothnumbersarethesame.BecausegrouchoGuessis5andmySecretNumberis5,mySecretNumber===grouchoGuessreturnstrue.Theotherguessesdidn’tmatchmySecretNumber,sotheyreturnedfalse.Youcanalsouse===tocomparetwostringsortwoBooleans.Ifyouuse===tocomparetwodifferenttypes—forexample,astringandanumber—itwillalwaysreturnfalse.
DoubleEqualsNowtoconfusethingsabit:there’sanotherJavaScriptoperator(doubleequals,or==)thatmeans“equal-ish.”Usethistoseewhethertwovaluesarethesame,evenifoneisastringandtheotherisanumber.Allvalueshavesomekindoftype.Sothenumber5isdifferentfromthestring"5",eventhoughtheybasicallylooklikethesamething.Ifyouuse===tocomparethenumber5andthestring"5",JavaScriptwilltellyouthey’renotequal.Butifyouuse==tocomparethem,itwilltellyouthey’rethesame:
varstringNumber="5";
varactualNumber=5;
stringNumber===actualNumber;
false
stringNumber==actualNumber;
true
Atthispoint,youmightbethinkingtoyourself,“Hmm,itseemsmucheasiertousedoubleequalsthantripleequals!”Youhavetobeverycareful,though,becausedoubleequalscanbeveryconfusing.Forexample,doyouthink0isequaltofalse?Whataboutthestring"false"?Whenyouusedoubleequals,0isequaltofalse,butthestring"false"isnot:
0==false;
true
"false"==false;
false
ThisisbecausewhenJavaScripttriestocomparetwovalueswithdoubleequals,itfirsttriestomakethemthesametype.Inthiscase,itconvertstheBooleanintoanumber.IfyouconvertBooleanstonumbers,falsebecomes0,andtruebecomes1.Sowhenyoutype0==false,yougettrue!Becauseofthisweirdness,it’sprobablysafesttojuststickwith===fornow.
TRYITOUT!
You’vebeenaskedbythelocalmovietheatermanagerstoimplementsomeJavaScriptforanewautomatedsystemthey’rebuilding.TheywanttobeabletoworkoutwhethersomeoneisallowedintoaPG-13movieornot.
Therulesare,ifsomeoneis13orover,they’reallowedin.Ifthey’renotover13,buttheyareaccompaniedbyanadult,they’realsoallowedin.Otherwise,theycan’tseethemovie.
varage=12;
varaccompanied=true;
???
Finishthisexampleusingtheageandaccompaniedvariablestoworkoutwhetherthis12-year-oldisallowedtoseethemovie.Trychangingthevalues(forexample,setageto13andaccompaniedtofalse)andseeifyourcodestillworksouttherightanswer.
undefinedandnullFinally,wehavetwovaluesthatdon’tfitanyparticularmold.They’recalledundefinedandnull.They’rebothusedtomean“nothing,”butinslightlydifferentways.undefinedisthevalueJavaScriptuseswhenitdoesn’thaveavalueforsomething.Forexample,whenyoucreateanewvariable,ifyoudon’tsetitsvaluetoanythingusingthe=operator,itsvaluewillbesettoundefined:
varmyVariable;
myVariable;
undefined
Thenullvalueisusuallyusedwhenyouwanttodeliberatelysay“Thisisempty.”varmyNullVariable=null;
myNullVariable;
null
Atthispoint,youwon’tbeusingundefinedornullveryoften.You’llseeundefinedifyoucreateavariableanddon’tsetitsvalue,becauseundefinediswhatJavaScriptwillalwaysgiveyouwhenitdoesn’thaveavalue.It’snotverycommontosetsomethingtoundefined;ifyoufeeltheneedtosetavariableto“nothing,”youshouldusenullinstead.nullisusedonlywhenyouactuallywanttosaysomething’snotthere,whichisveryoccasionallyhelpful.Forexample,sayyou’reusingavariabletotrackwhatyourfavoritevegetableis.Ifyouhateallvegetablesanddon’thaveafavorite,youmightsetthefavoritevegetablevariabletonull.Settingthevariabletonullwouldmakeitobvioustoanyonereadingthecodethatyoudon’thaveafavoritevegetable.Ifitwereundefined,however,someonemightjustthinkyouhadn’tgottenaroundtosettingavalueyet.
WhatYouLearnedNowyouknowallthebasicdatatypesinJavaScript—numbers,strings,andBooleans—aswellasthespecialvaluesnullandundefined.Numbersareusedformath-typethings,stringsareusedfortext,andBooleansareusedforyesornoquestions.Thevaluesnullandundefinedaretheretogiveusawaytotalkaboutthingsthatdon’texist.Inthenexttwochapters,we’lllookatarraysandobjects,whicharebothwaysofjoiningbasictypestocreatemorecomplexcollectionsofvalues.
Chapter3.ArraysSofarwe’velearnedaboutnumbersandstrings,whicharetypesofdatathatyoucanstoreanduseinyourprograms.Butnumbersandstringsarekindofboring.There’snotalotthatyoucandowithastringonitsown.JavaScriptletsyoucreateandgrouptogetherdatainmoreinterestingwayswitharrays.AnarrayisjustalistofotherJavaScriptdatavalues.Forexample,ifyourfriendaskedyouwhatyourthreefavoritedinosaurswere,youcouldcreateanarraywiththenamesofthosedinosaurs,inorder:
varmyTopThreeDinosaurs=["T-Rex","Velociraptor","Stegosaurus"];
Soinsteadofgivingyourfriendthreeseparatestrings,youcanjustusethesinglearraymyTopThreeDinosaurs.
WhyShouldYouCareAboutArrays?Let’slookatdinosaursagain.Sayyouwanttouseaprogramtokeeptrackofthemanykindsofdinosaursyouknowabout.Youcouldcreateavariableforeachdinosaur,likethis:
vardinosaur1="T-Rex";
vardinosaur2="Velociraptor";
vardinosaur3="Stegosaurus";
vardinosaur4="Triceratops";
vardinosaur5="Brachiosaurus";
vardinosaur6="Pteranodon";
vardinosaur7="Apatosaurus";
vardinosaur8="Diplodocus";
vardinosaur9="Compsognathus";
Thislistisprettyawkwardtouse,though,becauseyouhaveninedifferentvariableswhenyoucouldhavejustone.Imagineifyouwerekeepingtrackof1000dinosaurs!You’dneedtocreate1000separatevariables,whichwouldbealmostimpossibletoworkwith.
It’slikeifyouhadashoppinglist,buteveryitemwasonadifferentpieceofpaper.You’dhaveonepieceofpaperthatsaid“eggs,”anotherpiecethatsaid“bread,”andanotherpiecethatsaid“oranges.”Mostpeoplewouldwritethefulllistofthingstheywanttobuyonasinglepieceofpaper.Wouldn’titbemucheasierifyoucouldgroupallninedinosaurstogetherinjustoneplace?Youcan,andthat’swherearrayscomein.
CreatinganArrayTocreateanarray,youjustusesquarebrackets,[].Infact,anemptyarrayissimplyapairofsquarebrackets,likethis:
[];
[]
Butwhocaresaboutanemptyarray?Let’sfillitwithourdinosaurs!Tocreateanarraywithvaluesinit,enterthevalues,separatedbycommas,betweenthesquarebrackets.Wecancalltheindividualvaluesinanarrayitemsorelements.Inthisexample,ourelementswillbestrings(thenamesofourfavoritedinosaurs),sowe’llwritethemwithquotemarks.We’llstorethearrayinavariablecalleddinosaurs:
vardinosaurs=["T-Rex","Velociraptor","Stegosaurus",
"Triceratops","Brachiosaurus","Pteranodon","Apatosaurus",
"Diplodocus","Compsognathus"];
NOTE
Becausethisisabookandthepageisonlysowide,wecan’tactuallyfitthewholearrayononeline.The istoshowwherewe’veputthecodeontoanextralinebecausethepageistoonarrow.Whenyoutypethisintoyourcomputer,youcantypeitallononeline.
Longlistscanbehardtoreadononeline,butluckilythat’snottheonlywaytoformat(orlayout)anarray.Youcanalsoformatanarraywithanopeningsquarebracketononeline,thelistofitemsinthearrayeachonanewline,andaclosingsquarebracket,likethis:
vardinosaurs=[
"T-Rex",
"Velociraptor",
"Stegosaurus",
"Triceratops",
"Brachiosaurus",
"Pteranodon",
"Apatosaurus",
"Diplodocus",
"Compsognathus"
];
Ifyouwanttotypethisintoyourbrowserconsole,you’llneedtoholddowntheSHIFTkeywhenyoupresstheENTERkeyforeachnewline.OtherwisetheJavaScriptinterpreterwillthinkyou’retryingtoexecutethecurrent,incomplete,line.Whilewe’reworkingintheinterpreter,it’seasiertowritearraysononeline.Whetheryouchoosetoformattheitemsinanarrayononelineoronseparatelines,it’sallthesametoJavaScript.Howevermanylinebreaksyouuse,JavaScriptjustseesanarray—inthisexample,anarraycontainingninestrings.
AccessinganArray’sElementsWhenit’stimetoaccesselementsinanarray,youusesquarebracketswiththeindexoftheelementyouwant,asyoucanseeinthefollowingexample:
dinosaurs[0];
"T-Rex"
dinosaurs[3];
"Triceratops"
Anindexisthenumberthatcorrespondsto(ormatches)thespotinthearraywhereavalueisstored.Justaswithstrings,thefirstelementinanarrayisatindex0,thesecondisatindex1,thethirdatindex2,andsoon.That’swhyaskingforindex0fromthedinosaursarrayreturns"T-Rex"(whichisfirstinthelist),andindex3returns"Triceratops"(whichisfourthinthelist).It’susefultobeabletoaccessindividualelementsfromanarray.Forexample,ifyoujustwantedtoshowsomeoneyourabsolutefavoritedinosaur,youwouldn’tneedthewholedinosaursarray.Insteadyouwouldjustwantthefirstelement:
dinosaurs[0];
"T-Rex"
SettingorChangingElementsinanArrayYoucanuseindexesinsquarebracketstoset,change,orevenaddelementstoanarray.Forexample,toreplacethefirstelementinthedinosaursarray("T-Rex")with"TyrannosaurusRex",youcoulddothis:
dinosaurs[0]="TyrannosaurusRex";
Afteryou’vedonethat,thedinosaursarraywouldlooklikethis:["TyrannosaurusRex","Velociraptor","Stegosaurus","Triceratops",
"Brachiosaurus","Pteranodon","Apatosaurus","Diplodocus",
"Compsognathus"]
Youcanalsousesquarebracketswithindexestoaddnewelementstoanarray.Forexample,here’showyoucouldcreatethedinosaursarraybysettingeachelementindividuallywithsquarebrackets:
vardinosaurs=[];
dinosaurs[0]="T-Rex";
dinosaurs[1]="Velociraptor";
dinosaurs[2]="Stegosaurus";
dinosaurs[3]="Triceratops";
dinosaurs[4]="Brachiosaurus";
dinosaurs[5]="Pteranodon";
dinosaurs[6]="Apatosaurus";
dinosaurs[7]="Diplodocus";
dinosaurs[8]="Compsognathus";
dinosaurs;
["T-Rex","Velociraptor","Stegosaurus","Triceratops",
"Brachiosaurus","Pteranodon","Apatosaurus","Diplodocus",
"Compsognathus"]
Firstwecreateanemptyarraywithvardinosaurs=[].Then,witheachfollowinglineweaddavaluetothelistwithaseriesofdinosaurs[]entries,fromindex0toindex8.Oncewefinishthelist,wecanviewthearray(bytypingdinosaurs;).WeseethatJavaScripthasstoredallthenamesorderedaccordingtotheindexes.Youcanactuallyaddanelementatanyindexyouwant.Forexample,toaddanew(made-up)dinosauratindex33,youcouldwritethefollowing:
dinosaurs[33]="Philosoraptor";
dinosaurs;
["T-Rex","Velociraptor","Stegosaurus","Triceratops",
"Brachiosaurus","Pteranodon","Apatosaurus","Diplodocus",
"Compsognathus",undefined×24"Philosoraptor"]
Theelementsbetweenindexes8and33willbeundefined.Whenyououtputthearray,Chromehelpfullytellsyouhowmanyelementswereundefined,ratherthanlistingthemallindividually.
MixingDataTypesinanArrayArrayelementsdon’tallhavetobethesametype.Forexample,thenextarraycontainsanumber(3),astring("dinosaurs"),anarray(["triceratops","stegosaurus",3627.5]),andanothernumber(10):
vardinosaursAndNumbers=[3,"dinosaurs",["triceratops",
"stegosaurus",3627.5],10];
Toaccessanindividualelementinthisarray’sinnerarray,youwouldjustuseasecondsetofsquarebrackets.Forexample,whiledinosaursAndNumbers[2];returnstheentireinnerarray,dinosaursAndNumbers[2][0];returnsonlythefirstelementofthatinnerarray,whichis"triceratops".
dinosaursAndNumbers[2];
["triceratops","stegosaurus",3627.5]
dinosaursAndNumbers[2][0];
"triceratops"
WhenwetypedinosaursAndNumbers[2][0];,wetellJavaScripttolookatindex2ofthearraydinosaursAndNumbers,whichcontainsthearray["triceratops","stegosaurus",3627.5],andtoreturnthevalueatindex0ofthatsecondarray.Index0isthefirstvalueofthesecondarray,whichis"triceratops".Figure3-1showstheindexpositionsforthisarray.
Figure3-1.Theindexpositionsofthemainarrayarelabeledinred,andtheindexesoftheinnerarrayarelabeledinblue.
WorkingwithArraysPropertiesandmethodshelpyouworkwitharrays.Propertiesgenerallytellyousomethingaboutthearray,andmethodsusuallydosomethingtochangethearrayorreturnanewarray.Let’shavealook.
FindingtheLengthofanArraySometimesit’susefultoknowhowmanyelementsthereareinanarray.Forexample,ifyoukeptaddingdinosaurstoyourdinosaursarray,youmightforgethowmanydinosaursyouhave.Thelengthpropertyofanarraytellsyouhowmanyelementsthereareinthearray.Tofindthelengthofanarray,justadd.lengthtotheendofitsname.Let’stryitout.Firstwe’llmakeanewarraywiththreeelements:
varmaniacs=["Yakko","Wakko","Dot"];
maniacs[0];
"Yakko"
maniacs[1];
"Wakko"
maniacs[2];
"Dot"
Tofindthelengthofthearray,add.lengthtomaniacs:maniacs.length;
3
JavaScripttellsusthatthereare3elementsinthearray,andwealreadyknowtheyhavetheindexpositions0,1,and2.Thisgivesusausefulpieceofinformation:thelastindexinanarrayisalwaysthesamenumberasthelengthofthearrayminus1.Thismeansthatthereisaneasywaytoaccessthelastelementinanarray,howeverlongthatarrayis:
maniacs[maniacs.length-1];
"Dot"
Here,we’reaskingJavaScriptforanelementfromourarray.Butinsteadofenteringanindexnumberinthesquarebrackets,weusealittlebitofmath:thelengthofthearrayminus1.JavaScriptfindsmaniacs.length,gets3,andthensubtracts1toget2.Thenitreturnstheelementfromindex2—thelastmaniacinthearray,"Dot".
AddingElementstoanArrayToaddanelementtotheendofanarray,youcanusethepushmethod.Add.pushtothearrayname,followedbytheelementyouwanttoaddinsideparentheses,likethis:
varanimals=[];
animals.push("Cat");
1
animals.push("Dog");
2
animals.push("Llama");
3
animals;
["Cat","Dog","Llama"]
animals.length;
3
Herewecreateanemptyarraywithvaranimals=[];,andthenusethepushmethodtoadd"Cat"tothearray.Then,weusepushagaintoaddon"Dog"andthen"Llama".Whenwedisplayanimals;,weseethat"Cat","Dog",and"Llama"wereaddedtothearray,inthesameorderweenteredthem.
Theactofrunningamethodincomputer-speakisknownascallingthemethod.Whenyoucallthepushmethod,twothingshappen.First,theelementinparenthesesisaddedtothearray.Second,thenewlengthofthearrayisreturned.That’swhyyouseethosenumbersprintedouteverytimeyoucallpush.Toaddanelementtothebeginningofanarray,youcanuse.unshift(element),likethis:
animals;
["Cat","Dog","Llama"]
➊animals[0];
"Cat"
animals.unshift("Monkey");
4
animals;
["Monkey","Cat","Dog","Llama"]
animals.unshift("PolarBear");
5
animals;
["PolarBear","Monkey","Cat","Dog","Llama"]
animals[0];
"PolarBear"
➋animals[2];
"Cat"
Herewestartedwiththearraythatwe’vebeenusing,["Cat","Dog","Llama"].Then,asweaddtheelements"Monkey"and"PolarBear"tothebeginningofthearraywithunshift,theoldvaluesgetpushedalongbyoneindexeachtime.So"Cat",whichwasoriginallyatindex0➊,isnowatindex2➋.
Again,unshiftreturnsthenewlengthofthearrayeachtimeitiscalled,justlikepush.
RemovingElementsfromanArrayToremovethelastelementfromanarray,youcanpopitoffbyadding.pop()totheendofthearrayname.Thepopmethodcanbeparticularlyhandybecauseitdoestwothings:itremovesthelastelement,anditreturnsthatlastelementasavalue.Forexample,let’sstartwithouranimalsarray,["PolarBear","Monkey","Cat","Dog","Llama"].Thenwe’llcreateanewvariablecalledlastAnimalandsavethelastanimalintoitbycallinganimals.pop().
animals;
["PolarBear","Monkey","Cat","Dog","Llama"]
➊varlastAnimal=animals.pop();lastAnimal;
"Llama"
animals;
["PolarBear","Monkey","Cat","Dog"]
➋animals.pop();
"Dog"
animals;
["PolarBear","Monkey","Cat"]
➌animals.unshift(lastAnimal);
4
animals;
["Llama","PolarBear","Monkey","Cat"]
Whenwecallanimals.pop()at➊,thelastitemintheanimalsarray,"Llama",isreturnedandsavedinthevariablelastAnimal."Llama"isalsoremovedfromthearray,whichleavesuswithfouranimals.Whenwecallanimals.pop()againat➋,"Dog"isremovedfromthearrayandreturned,leavingonlythreeanimalsinthearray.Whenweusedanimal.pop()on"Dog",wedidn’tsaveitintoavariable,sothatvalueisn’tsavedanywhereanymore.The"Llama",ontheotherhand,wassavedtothevariablelastAnimal,sowecanuseitagainwheneverweneedit.At➌,weuseunshift(lastAnimal)toadd"Llama"backontothefrontofthearray.Thisgivesusafinalarrayof["Llama","PolarBear","Monkey","Cat"].Pushingandpoppingareausefulpairbecausesometimesyoucareaboutonlytheendofanarray.Youcanpushanewitemontothearrayandthenpopitoffwhenyou’rereadytouseit.We’lllookatsomewaystousepushingandpoppinglaterinthischapter.
Toremoveandreturnthefirstelementofanarray,use.shift():animals;
["Llama","PolarBear","Monkey","Cat"]
varfirstAnimal=animals.shift();
firstAnimal;
"Llama"
animals;
["PolarBear","Monkey","Cat"]
animals.shift()doesthesamethingasanimals.pop(),buttheelementcomesoffthebeginninginstead.Atthestartofthisexample,animalsis["Llama","PolarBear","Monkey","Cat"].
Whenwecall.shift()onthearray,thefirstelement,"Llama",isreturnedandsavedinfirstAnimal.Because.shift()removesthefirstelementaswellasreturningit,attheendanimalsisjust["PolarBear","Monkey","Cat"].Youcanuseunshiftandshifttoaddandremoveitemsfromthebeginningofanarrayjustasyou’dusepushandpoptoaddandremoveitemsfromtheendofanarray.
AddingArraysToaddtwoarraystogethertomakeanew,singlearray,youcanusefirstArray.concat(otherArray).Thetermconcatisshortforconcatenate,afancycomputersciencewordforjoiningtwovaluestogether.Theconcatmethodwillcombinebotharraysintoanewarray,withthevaluesfromfirstArrayaddedinfrontofthosefromotherArray.Forexample,saywehavealistofsomefurryanimalsandanotherlistofsomescalyanimals,andwewanttocombinethem.IfweputallofourfurryanimalsinanarraycalledfurryAnimalsandallofourscalyanimalsinanarraycalledscalyAnimals,enteringfurryAnimals.concat(scalyAnimals)willcreateanewarraythathasthevaluesfromthefirstarrayatthebeginningandthevaluesfromthesecondarrayattheend.
varfurryAnimals=["Alpaca","Ring-tailedLemur","Yeti"];
varscalyAnimals=["BoaConstrictor","Godzilla"];
varfurryAndScalyAnimals=furryAnimals.concat(scalyAnimals);
furryAndScalyAnimals;
["Alpaca","Ring-tailedLemur","Yeti","BoaConstrictor","Godzilla"]
furryAnimals;
["Alpaca","Ring-tailedLemur","Yeti"]
scalyAnimals;
["BoaConstrictor","Godzilla"]
EventhoughfirstArray.concat(otherArray)returnsanarraycontainingalltheelementsfromfirstArrayandsecondArray,neitheroftheoriginalarraysischanged.WhenwelookatfurryAnimalsandscalyAnimals,they’rethesameaswhenwecreatedthem.
JoiningMultipleArraysYoucanuseconcattojoinmorethantwoarraystogether.Justputtheextraarraysinsidetheparentheses,separatedbycommas:
varfurryAnimals=["Alpaca","Ring-tailedLemur","Yeti"];
varscalyAnimals=["BoaConstrictor","Godzilla"];
varfeatheredAnimals=["Macaw","Dodo"];
varallAnimals=furryAnimals.concat(scalyAnimals,featheredAnimals);
allAnimals;
["Alpaca","Ring-tailedLemur","Yeti","BoaConstrictor","Godzilla",
"Macaw","Dodo"]
HerethevaluesfromfeatheredAnimalsgetaddedtotheveryendofthenewarray,sincetheyarelistedlastintheparenthesesaftertheconcatmethod.concatisusefulwhenyouhavemultiplearraysthatyouwanttocombineintoone.Forexample,sayyouhavealistofyourfavoritebooks,andyourfriendalsohasalistoffavoritebooks,andyouwanttogoseeifthebooksareavailabletobuyallatonceatthebookstore.Itwouldbeeasierifyouhadonly
onelistofbooks.Allyou’dhavetodoisconcatyourlistwithyourfriend’s,andvoilà!Onelistofbooks.
FindingtheIndexofanElementinanArrayTofindtheindexofanelementinanarray,use.indexOf(element).Herewedefinethearraycolorsandthenaskfortheindexpositionsof"blue"and"green"withcolors.indexOf("blue")andcolors.indexOf("green").Becausetheindexof"blue"inthearrayis2,colors.indexOf("blue")returns2.Theindexof"green"inthearrayis1,socolors.indexOf("green")returns1.
varcolors=["red","green","blue"];
colors.indexOf("blue");
2
colors.indexOf("green");
1
indexOfislikethereverseofusingsquarebracketstogetavalueataparticularindex;colors[2]is"blue",socolors.indexOf("blue")is2:
colors[2];
"blue"
colors.indexOf("blue");
2
Eventhough"blue"appearsthirdinthearray,itsindexpositionis2becausewealwaysstartcountingfrom0.Andthesamegoesfor"green",ofcourse,atindex1.Iftheelementwhosepositionyouaskforisnotinthearray,JavaScriptreturns-1.
colors.indexOf("purple");
-1
ThisisJavaScript’swayofsaying“Thatdoesn’texisthere,”whilestillreturninganumber.Iftheelementappearsmorethanonceinthearray,theindexOfmethodwillreturnthefirstindexofthatelementinthearray.
varinsects=["Bee","Ant","Bee","Bee","Ant"];
insects.indexOf("Bee");
0
TurninganArrayintoaStringYoucanuse.join()tojoinalltheelementsinanarraytogetherintoonebigstring.
varboringAnimals=["Monkey","Cat","Fish","Lizard"];
boringAnimals.join();
"Monkey,Cat,Fish,Lizard"
Whenyoucallthejoinmethodonanarray,itreturnsastringcontainingalltheelements,separatedbycommas.Butwhatifyoudon’twanttousecommasastheseparator?
Youcanuse.join(separator)todothesamething,butwithyourownchosenseparatorbetweeneachvalue.Theseparatoriswhateverstringyouputinsidetheparentheses.Forexample,wecanusethreedifferentseparators:ahyphenwithspacesoneitherside,anasterisk,andthewordseeswithspacesoneitherside.Noticethatyouneedquotemarksaroundtheseparator,becausetheseparatorisastring.
varboringAnimals=["Monkey","Cat","Fish","Lizard"];
boringAnimals.join("-");
"Monkey-Cat-Fish-Lizard"
boringAnimals.join("*")
"Monkey*Cat*Fish*Lizard"
boringAnimals.join("sees")
"MonkeyseesCatseesFishseesLizard"
Thisisusefulifyouhaveanarraythatyouwanttoturnintoastring.Sayyouhavelotsofmiddlenamesandyou’vegotthemstoredinanarray,alongwithyourfirstandlastname.Youmightbeaskedtogiveyourfullnameasastring.Usingjoin,withasinglespaceastheseparator,willjoinallyournamestogetherintoasinglestring:
varmyNames=["Nicholas","Andrew","Maxwell","Morgan"];
myNames.join("");
"NicholasAndrewMaxwellMorgan"
Ifyoudidn’thavejoin,you’dhavetodosomethinglikethis,whichwouldbereallyannoyingtotypeout:
myNames[0]+""+myNames[1]+""+myNames[2]+""+myNames[3];
"NicholasAndrewMaxwellMorgan"
Also,thiscodewouldworkonlyifyouhadexactlytwomiddlenames.Ifyouhadoneorthreemiddlenames,you’dhavetochangethecode.Withjoin,youdon’thavetochangeanything—itprintsoutastringwithalloftheelementsofthearray,nomatterhowlongthearrayis.Ifthevaluesinthearrayaren’tstrings,JavaScriptwillconvertthemtostringsbeforejoiningthemtogether:
varages=[11,14,79];
ages.join("");
"111479"
UsefulThingstoDowithArraysNowyouknowlotsofdifferentwaystocreatearraysandplayaroundwiththem.Butwhatcanyouactuallydowithallthesepropertiesandmethods?Inthissection,we’llwriteafewshortprogramsthatshowoffsomeusefulthingstodowitharrays.
FindingYourWayHomePicturethis:yourfriendhascomeovertoyourhouse.Nowshewantstoshowyouherhouse.Theonlyproblemisthatyou’veneverbeentoherhousebefore,andlateryou’llhavetofindyourwaybackhomeonyourown.Luckily,youhaveacleverideatohelpyouwithyourproblem:onthewaytoyourfriend’shouse,you’llkeepalistofallthelandmarksyousee.Onthewayback,you’llgothroughthelistinreverseandcheckitemsofftheendofthelisteverytimeyoupassalandmarksoyouknowwheretogonext.
BuildingtheArraywithPushLet’swritesomecodethatwoulddoexactlythat.Westartoffbycreatinganemptyarray.Thearraystartsoffemptybecauseyoudon’tknowwhatlandmarksyou’llseeuntilyouactuallystartwalkingtoyourfriend’shouse.Then,foreachlandmarkonthewaytoyourfriend’shouse,we’llpushadescriptionofthatlandmarkontotheendofthearray.Then,whenit’stimetogohome,we’llpopeachlandmarkoffthearray.
varlandmarks=[];
landmarks.push("Myhouse");
landmarks.push("Frontpath");
landmarks.push("Flickeringstreetlamp");
landmarks.push("Leakyfirehydrant");
landmarks.push("Firestation");
landmarks.push("Catrescuecenter");
landmarks.push("Myoldschool");
landmarks.push("Myfriend'shouse");
Herewecreateanemptyarraynamedlandmarksandthenusepushtostoreallthelandmarksyoupassonthewaytoyourfriend’shouse.
GoinginReversewithpopOnceyouarriveatyourfriend’shouse,youcaninspectyourarrayoflandmarks.Sureenough,thefirstitemis"Myhouse",followedby"Frontpath",andsoonthroughtheendofthearray,withthefinalitem"Myfriend'shouse".Whenit’stimetogohome,allyouneedtodoispopofftheitemsonebyone,andyou’llknowwheretogonext.
landmarks.pop();
"Myfriend'shouse"
landmarks.pop();
"Myoldschool"
landmarks.pop();
"Catrescuecenter"
landmarks.pop();
"Firestation"
landmarks.pop();
"Leakyfirehydrant"
landmarks.pop();
"Flickeringstreetlamp"
landmarks.pop();
"Frontpath"
landmarks.pop();
"Myhouse"
Phew,youmadeithome!Didyounoticehowthefirstlandmarkyouputinthearraywasalsothelastoneyougotoutofit?Andthelastlandmarkyouputinthearraywasthefirstonethatcameout?Youmighthavethoughtthatyou’dalwayswantthefirstitemyouputintobethefirstitemyougetout,butyoucanseethatit’ssometimeshelpfultogobackthroughanarrayinreverse.
It’sactuallyverycommontouseaprocesslikethisinlargerprograms,whichiswhyJavaScriptmakespushingandpoppingsoeasy.
NOTE
Thistechniqueisknownasastackincomputer-speak.Thinkofitlikeastackofpancakes.Everytimeyoucookanewpancake,itgoesontop(likepush),andeverytimeyoueatone,itcomesoffthetop(likepop).Poppingastackislikegoingbackintime:thelastitemyoupopisthefirstoneyoupushed.It’sthesamewithpancakes:thelastpancakeyoueatisthefirstonethatwascooked.Inprogrammingjargon,thisisalsocalledLastIn,FirstOut(LIFO).ThealternativetoLIFOisFirstIn,FirstOut(FIFO).Thisisalsoknownasaqueue,becauseitactslikeaqueue(orline)ofpeople.Thefirstpersontojointhequeueisthefirstpersontobeserved.
DecisionMakerWecanusearraysinJavaScripttobuildaprogramtomakedecisionsforus(likeaMagic8-Ball).First,though,weneedtofindouthowtogetrandomnumbers.
UsingMath.random()WecanproducerandomnumbersusingaspecialmethodcalledMath.random(),whichreturnsarandomnumberbetween0and1eachtimeit’scalled.Here’sanexample:
Math.random();
0.8945409457664937
Math.random();
0.3697543195448816
Math.random();
0.48314980138093233
It’simportanttonotethatMath.random()alwaysreturnsanumberlessthan1andwillneverreturn1itself.Ifyouwantabiggernumber,justmultiplytheresultofcallingMath.random().Forexample,ifyouwantednumbersbetween0and10,youwouldmultiplyMath.random()by10:
Math.random()*10;
7.648027329705656
Math.random()*10;
9.7565904534421861
Math.random()*10;
0.21483442978933454
RoundingDownwithMath.floor()Wecan’tusethesenumbersasarrayindexes,though,becauseindexeshavetobewholenumberswithnothingafterthedecimalpoint.Tofixthat,weneedanothermethodcalledMath.floor().Thistakesanumberandroundsitdowntothewholenumberbelowit(basicallygettingridofeverythingafterthedecimalpoint).
Math.floor(3.7463463);
3
Math.floor(9.9999);
9
Math.floor(0.793423451963426);
0
Wecancombinethesetwotechniquestocreatearandomindex.AllweneedtodoismultiplyMath.random()bythelengthofthearrayandthencallMath.floor()onthatvalue.Forexample,ifthelengthofthearraywere4,wewoulddothis:
Math.floor(Math.random()*4);
2//couldbe0,1,2,or3
Everytimeyoucallthecodeabove,itreturnsarandomnumberfrom0to3(including0and3).BecauseMath.random()alwaysreturnsavaluelessthan1,Math.random()*4willneverreturn4oranythinghigherthan4.Now,ifweusethatrandomnumberasanindex,wecanselectarandomelementfromanarray:
varrandomWords=["Explosion","Cave","Princess","Pen"];
varrandomIndex=Math.floor(Math.random()*4);
randomWords[randomIndex];
"Cave"
HereweuseMath.floor(Math.random()*4);topickarandomnumberfrom0to3.Oncethat
randomnumberissavedtothevariablerandomIndex,weuseitasanindextoaskforastringfromthearrayrandomWords.Infact,wecouldshortenthisbydoingawaywiththerandomIndexvariablealtogetherandjustsay:
randomWords[Math.floor(Math.random()*4)];
"Princess"
TheCompleteDecisionMakerNowlet’screateourarrayofphrases,andwecanusethiscodetopickarandomone.Thisisourdecisionmaker!I’musingcommentsheretoshowsomequestionsyoumightwanttoaskyourcomputer.
varphrases=[
"Thatsoundsgood",
"Yes,youshoulddefinitelydothat",
"I'mnotsurethat'sagreatidea",
"Maybenottoday?",
"Computersaysno."
];
//ShouldIhaveanothermilkshake?
phrases[Math.floor(Math.random()*5)];
"I'mnotsurethat'sagreatidea"
//ShouldIdomyhomework?
phrases[Math.floor(Math.random()*5)];
"Maybenottoday?"
Herewecreatedanarraycalledphrasesthatstoresdifferentpiecesofadvice.Now,everytimewehaveaquestion,wecanaskforarandomvaluefromthephrasesarray,anditwillhelpusmakeadecision!Noticethatbecauseourarrayofdecisionshasfiveitems,wemultiplyMath.random()by5.Thiswillalwaysreturnoneoffiveindexpositions:0,1,2,3,or4.
CreatingaRandomInsultGeneratorWecanextendthedecisionmakerexampletocreateaprogramthatgeneratesarandominsulteverytimeyourunit!
varrandomBodyParts=["Face","Nose","Hair"];
varrandomAdjectives=["Smelly","Boring","Stupid"];
varrandomWords=["Fly","Marmot","Stick","Monkey","Rat"];
//PickarandombodypartfromtherandomBodyPartsarray:
➊varrandomBodyPart=randomBodyParts[Math.floor(Math.random()*3)];
//PickarandomadjectivefromtherandomAdjectivesarray:
➋varrandomAdjective=randomAdjectives[Math.floor(Math.random()*3)];
//PickarandomwordfromtherandomWordsarray:
➌varrandomWord=randomWords[Math.floor(Math.random()*5)];
//Joinalltherandomstringsintoasentence:
varrandomInsult="Your"+randomBodyPart+"islikea"+
randomAdjective+""+randomWord+"!!!";
randomInsult;
"YourNoseislikeaStupidMarmot!!!"
Herewehavethreearrays,andinlines➊,➋,and➌,weusethreeindexestopullarandomwordfromeacharray.Then,wecombinethemallinthevariablerandomInsulttocreateacompleteinsult.At➊and➋we’remultiplyingby3becauserandomAdjectivesandrandomBodyPartsbothcontainthreeelements.Likewise,we’remultiplyingby5at➌becauserandomWordsisfiveelementslong.NoticethatweaddastringwithasinglespacebetweenrandomAdjectiveandrandomWord.Tryrunningthiscodeafewtimes—youshouldgetadifferentrandominsulteachtime!
TRYITOUT!
Ifyouwantedtobereallyclever,youcouldreplaceline➌withthis:
varrandomWord=randomWords[Math.floor(Math.random()*
randomWords.length)];
WeknowthatwealwaysneedtomultiplyMath.random()bythelengthofthearray,sousingrandomWords.lengthmeanswedon’thavetochangeourcodeifthelengthofthearraychanges.
Here’sanotherwaytobuildupourrandominsult:varrandomInsult=["Your",randomBodyPart,"is","like","a",
randomAdjective,randomWord+"!!!"].join("");
"YourHairislikeaSmellyFly!!!"
Inthisexample,eachwordofthesentenceisaseparatestringinanarray,whichwejoinwiththespacecharacter.There’sonlyoneplacewherewedon’twantaspace,whichisinbetweenrandomWordand"!!!".Inthiscase,weusethe+operatortojointhosetwostringswithoutthespace.
WhatYouLearnedAsyou’veseen,JavaScriptarraysareawaytostorealistofvalues.Nowyouknowhowtocreateandworkwitharrays,andyouhavemanywaysofaccessingtheirelements.ArraysareoneofthewaysJavaScriptgivesyoutobringmultiplevaluestogetherintooneplace.Inthenextchapter,we’lllookatobjects,whichareanotherwayofstoringmultiplevaluesasasingleunit.Objectsusestringkeystoaccesstheelements,ratherthannumberindexes.
ProgrammingChallengesTryoutthesechallengestopracticetheskillsyoulearnedinthischapter.#1:NEWINSULTSMakeyourownrandominsultgeneratorwithyourownsetofwords.#2:MORESOPHISTICATEDINSULTSExtendtherandominsultgeneratorsoitgeneratesinsultslike“Your[bodypart]ismore[adjective]thana[animal]’s[animalbodypart].”(Hint:You’llneedtocreateanotherarray.)#3:USE+ORJOIN?Maketwoversionsofyourrandominsultgenerator:onethatusesthe+operatortocreatethestring,andonethatcreatesanarrayandjoinsitwith"".Whichdoyouprefer,andwhy?#4:JOININGNUMBERSHowcouldyouturnthearray[3,2,1]intothestring"3isbiggerthan2isbiggerthan1"usingthejoinmethod?
Chapter4.ObjectsObjectsinJavaScriptareverysimilartoarrays,butobjectsusestringsinsteadofnumberstoaccessthedifferentelements.Thestringsarecalledkeysorproperties,andtheelementstheypointtoarecalledvalues.Togetherthesepiecesofinformationarecalledkey-valuepairs.Whilearraysaremostlyusedtorepresentlistsofmultiplethings,objectsareoftenusedtorepresentsinglethingswithmultiplecharacteristics,orattributes.Forexample,inChapter3wemadeseveralarraysthatlisteddifferentanimalnames.Butwhatifwewantedtostoredifferentpiecesofinformationaboutoneanimal?
CreatingObjectsWecouldstorelotsofinformationaboutasingleanimalbycreatingaJavaScriptobject.Here’sanobjectthatstoresinformationaboutathree-leggedcatnamedHarmony.
varcat={
"legs":3,
"name":"Harmony",
"color":"Tortoiseshell"
};
Herewecreateavariablecalledcatandassignanobjecttoitwiththreekey-valuepairs.Tocreateanobject,weusecurlybrackets,{},insteadofthestraightbracketsweusedtomakearrays.Inbetweenthecurlybrackets,weenterkey-valuepairs.Thecurlybracketsandeverythinginbetweenthemarecalledanobjectliteral.Anobjectliteralisawayofcreatinganobjectbywritingouttheentireobjectatonce.
NOTE
We’vealsoseenarrayliterals(forexample,["a","b","c"]),numberliterals(forexample,37),stringliterals(forexample,"moose"),andBooleanliterals(trueandfalse).Literaljustmeansthatthewholevalueiswrittenoutatonce,notbuiltupinmultiplesteps.
Forexample,ifyouwantedtomakeanarraywiththenumbers1through3init,youcouldusethearrayliteral[1,2,3].Oryoucouldcreateanemptyarrayandthenusethepushmethodtoadd1,2,and3tothearray.Youdon’talwaysknowatfirstwhat’sgoingtobeinyourarrayorobject,whichiswhyyoucan’talwaysuseliteralstobuildarraysandobjects.
Figure4-1showsthebasicsyntaxforcreatinganobject.
Figure4-1.Thegeneralsyntaxforcreatinganobject
Whenyoucreateanobject,thekeygoesbeforethecolon(:),andthevaluegoesafter.Thecolonactsabitlikeanequalsign—thevaluesontherightgetassignedtothenamesontheleft,justlikewhenyoucreatevariables.Inbetweeneachkey-valuepair,youhavetoputacomma.Inourexample,thecommasareattheendsofthelines—butnoticethatyoudon’tneedacommaafterthelastkey-valuepair(color:"Tortoiseshell").Becauseit’sthelastkey-valuepair,theclosingcurlybracketcomesnext,insteadofacomma.
KeysWithoutQuotesInourfirstobject,weputeachkeyinquotationmarks,butyoudon’tnecessarilyneedquotesaroundthekeys—thisisavalidcatobjectliteralaswell:
varcat={
legs:3,
name:"Harmony",
color:"Tortoiseshell"
};
JavaScriptknowsthatthekeyswillalwaysbestrings,whichiswhyyoucanleaveoutthequotes.Ifyoudon’tputquotesaroundthekeys,theunquotedkeyshavetofollowthesamerulesasvariablenames:spacesaren’tallowedinanunquotedkey,forexample.Ifyouputthekeyinquotes,thenspacesareallowed:
varcat={
legs:3,
"fullname":"HarmonyPhilomenaSnuggly-PantsMorgan",
color:"Tortoiseshell"
};
Notethat,whileakeyisalwaysastring(withorwithoutquotes),thevalueforthatkeycanbeanykindofvalue,orevenavariablecontainingavalue.
Youcanalsoputthewholeobjectononeline,butitcanbehardertoreadlikethat:varcat={legs:3,name:"Harmony",color:"Tortoiseshell"};
AccessingValuesinObjectsYoucanaccessvaluesinobjectsusingsquarebrackets,justlikewitharrays.Theonlydifferenceisthatinsteadoftheindex(anumber),youusethekey(astring).
cat["name"];
"Harmony"
Justasthequotesaroundkeysareoptionalwhenyoucreateanobjectliteral,thequotesarealsooptionalwhenyouareaccessingkeysinobjects.Ifyou’renotgoingtousequotes,however,thecodelooksabitdifferent:
cat.name;
"Harmony"
Thisstyleiscalleddotnotation.Insteadoftypingthekeynameinquotesinsidesquarebracketsaftertheobjectname,wejustuseaperiod,followedbythekey,withoutanyquotes.Aswithunquotedkeysinobjectliterals,thiswillworkonlyifthekeydoesn’tcontainanyspecialcharacters,suchasspaces.Insteadoflookingupavaluebytypingitskey,sayyouwantedtogetalistofallthekeysinanobject.JavaScriptgivesyouaneasywaytodothat,usingObject.keys():
vardog={name:"Pancake",age:6,color:"white",bark:"Yipyap
yip!"};
varcat={name:"Harmony",age:8,color:"tortoiseshell"};
Object.keys(dog);
["name","age","color","bark"]
Object.keys(cat);
["name","age","color"]
Object.keys(anyObject)returnsanarraycontainingallthekeysofanyObject.
AddingValuestoObjectsAnemptyobjectisjustlikeanemptyarray,butitusescurlybrackets,{},insteadofsquarebrackets:
varobject={};
Youcanadditemstoanobjectjustasyou’dadditemstoanarray,butyouusestringsinsteadofnumbers:
varcat={};
cat["legs"]=3;
cat["name"]="Harmony";
cat["color"]="Tortoiseshell";
cat;
{color:"Tortoiseshell",legs:3,name:"Harmony"}
Here,westartedwithanemptyobjectnamedcat.Thenweaddedthreekey-valuepairs,onebyone.Then,wetypecat;,andthebrowsershowsthecontentsoftheobject.Differentbrowsersmayoutputobjectsdifferently,though.Forexample,Chrome(atthetimeI’mwritingthis)outputsthecatobjectlikethis:
Object{Legs:3,name:"Harmony",Color:"TortoisesheLL"}
WhileChromeprintsoutthekeysinthatorder(legs,name,color),otherbrowsersmayprintthemoutdifferently.ThisisbecauseJavaScriptdoesn’tstoreobjectswiththeirkeysinanyparticularorder.Arraysobviouslyhaveacertainorder:index0isbeforeindex1,andindex3isafterindex2.Butwithobjects,there’snoobviouswaytoordereachitem.Shouldcolorgobeforelegsorafter?There’sno“correct”answertothisquestion,soobjectssimplystorekeyswithoutassigningthemanyparticularorder,andasaresultdifferentbrowserswillprintthekeysindifferentorders.Forthisreason,youshouldneverwriteaprogramthatreliesonobjectkeysbeinginapreciseorder.
AddingKeyswithDotNotationYoucanalsousedotnotationwhenaddingnewkeys.Let’strythepreviousexample,wherewestartedwithanemptyobjectandaddedkeystoit,butthistimewe’llusedotnotation:
varcat={};
cat.legs=3;
cat.name="Harmony";
cat.color="Tortoiseshell";
IfyouaskforapropertythatJavaScriptdoesn’tknowabout,itreturnsthespecialvalueundefined.undefinedjustmeans“There’snothinghere!”Forexample:
vardog={
name:"Pancake",
legs:4,
isAwesome:true
};
dog.isBrown;
undefined
Herewedefinethreepropertiesfordog:name,legs,andisAwesome.Wedidn’tdefineisBrown,sodog.isBrownreturnsundefined.
CombiningArraysandObjectsSofar,we’velookedonlyatarraysandobjectsthatcontainsimpletypeslikenumbersandstrings.Butthere’snothingstoppingyoufromusinganotherarrayorobjectasavalueinanarrayorobject.Forexample,anarrayofdinosaurobjectsmightlooklikethis:
vardinosaurs=[
{name:"TyrannosaurusRex",period:"LateCretaceous"},
{name:"Stegosaurus",period:"LateJurassic"},
{name:"Plateosaurus",period:"Triassic"}
];
Togetalltheinformationaboutthefirstdinosaur,youcanusethesametechniqueweusedbefore,enteringtheindexinsquarebrackets:
dinosaurs[0];
{name:"TyrannosaurusRex",period:"LateCretaceous"}
Ifyouwanttogetonlythenameofthefirstdinosaur,youcanjustaddtheobjectkeyinsquarebracketsafterthearrayindex:
dinosaurs[0]["name"];
"TyrannosaurusRex"
Or,youcanusedotnotation,likethis:dinosaurs[1].period;
"LateJurassic"
NOTE
Youcanusedotnotationonlywithobjects,notwitharrays.
AnArrayofFriendsLet’slookatamorecomplexexamplenow.We’llcreateanarrayoffriendobjects,whereeachobjectalsocontainsanarray.First,we’llmaketheobjects,andthenwecanputthemallintoanarray.
varanna={name:"Anna",age:11,luckyNumbers:[2,4,8,16]};
vardave={name:"Dave",age:5,luckyNumbers:[3,9,40]};
varkate={name:"Kate",age:9,luckyNumbers:[1,2,3]};
First,wemakethreeobjectsandsavethemintovariablescalledanna,dave,andkate.Eachobjecthasthreekeys:name,age,andluckyNumbers.Eachnamekeyhasastringvalueassignedtoit,eachagekeyhasasinglenumbervalueassignedtoit,andeachluckyNumberskeyhasanarrayassignedtoit,containingafewdifferentnumbers.Nextwe’llmakeanarrayofourfriends:
varfriends=[anna,dave,kate];
Nowwehaveanarraysavedtothevariablefriendswiththreeelements:anna,dave,andkate(whicheachrefertoobjects).Youcanretrieveoneoftheseobjectsusingitsindexinthearray:
friends[1];
{name:"Dave",age:5,luckyNumbers:Array[3]}
Thisretrievesthesecondobjectinthearray,dave(atindex1).ChromeprintsoutArray[3]fortheluckyNumbersarray,whichisjustitswayofsaying,“Thisisathree-elementarray.”(YoucanuseChrometoseewhat’sinthatarray;seeExploringObjectsintheConsole.)Wecanalsoretrieveavaluewithinanobjectbyenteringtheindexoftheobjectinsquarebracketsfollowedbythekeywewant:
friends[2].name
"Kate"
Thiscodeasksfortheelementatindex2,whichisthevariablenamedkate,andthenasksforthepropertyinthatobjectunderthekey"name",whichis"Kate".Wecouldevenretrieveavaluefromanarraythat’sinsideoneoftheobjectsinsidethefriendsarray,likeso:
friends[0].luckyNumbers[1];
4
Figure4-2showseachindex.friends[0]istheelementatindex0inthefriendsarray,whichistheobjectanna.friends[0].luckyNumbersisthearray[2,4,8,16]fromtheobjectcalledanna.Finally,friends[0].luckyNumbers[1]isindex1inthatarray,whichisthenumbervalue4.
Figure4-2.Accessingnestedvalues
ExploringObjectsintheConsoleChromewillletyoudigintoobjectsthatyouprintoutintheconsole.Forexample,ifyoutype...
friends[1];
ChromewilldisplaytheoutputshowninFigure4-3.
Figure4-3.HowanobjectisdisplayedintheChromeinterpreter
Thetriangleontheleftmeansthatthisobjectcanbeexpanded.Clicktheobjecttoexpandit,andyou’llseewhat’sshowninFigure4-4.
Figure4-4.Expandingtheobject
YoucanexpandluckyNumbers,too,byclickingit(seeFigure4-5).
Figure4-5.Expandinganarraywithintheobject
Don’tworryaboutthose__proto__properties—theyhavetodowiththeobject’sprototype.We’lllookatprototypeslater,inChapter12.Also,you’llnoticethattheinterpretershowsthevalueofthearray’slengthproperty.Youcanalsoviewtheentirefriendsarrayandexpandeachelementinthearray,asshowninFigure4-6.
Figure4-6.Allthreeobjectsfromthefriendsarray,asshownintheChromeinterpreter
UsefulThingstoDowithObjectsNowthatyouknowafewdifferentwaystocreateobjectsandaddpropertiestothem,let’sputwhatwe’velearnedtousebytryingoutsomesimpleprograms.
KeepingTrackofOwedMoneyLet’ssayyou’vedecidedtostartabank.Youlendyourfriendsmoney,andyouwanttohaveawaytokeeptrackofhowmuchmoneyeachofthemowesyou.Youcanuseanobjectasawayoflinkingastringandavaluetogether.Inthiscase,thestringwouldbeyourfriend’sname,andthevaluewouldbetheamountofmoneyheorsheowesyou.Let’shavealook.
➊varowedMoney={};
➋owedMoney["Jimmy"]=5;
➌owedMoney["Anna"]=7;
➍owedMoney["Jimmy"];
5
➎owedMoney["Jinen"];
undefined
At➊,wecreateanewemptyobjectcalledowedMoney.At➋,weassignthevalue5tothekey"Jimmy".Wedothesamethingat➌,assigningthevalue7tothekey"Anna".At➍,weaskforthevalueassociatedwiththekey"Jimmy",whichis5.Thenat➎,weaskforthevalueassociatedwiththekey"Jinen",whichisundefinedbecausewedidn’tsetit.
Nowlet’simaginethatJimmyborrowssomemoremoney(say,$3).Wecanupdateourobjectandadd3totheamountJimmyoweswiththeplus-equalsoperator(+=)thatyousawinChapter2.
owedMoney["Jimmy"]+=3;
owedMoney["Jimmy"];
8
ThisislikesayingowedMoney["Jimmy"]=owedMoney["Jimmy"]+3.Wecanalsolookattheentireobjecttoseehowmuchmoneyeachfriendowesus:
owedMoney;
{Jimmy:8,Anna:7}
StoringInformationAboutYourMoviesLet’ssayyouhavealargecollectionofmoviesonDVDandBlu-ray.Wouldn’titbegreattohavetheinformationaboutthosemoviesonyourcomputersoyoucanfindoutabouteachmovieeasily?Youcancreateanobjecttostoreinformationaboutyourmovies,whereeverykeyisamovietitle,andeveryvalueisanotherobjectcontaininginformationaboutthemovie.Valuesinobjectscanbeobjectsthemselves!
varmovies={
"FindingNemo":{
releaseDate:2003,
duration:100,
actors:["AlbertBrooks","EllenDeGeneres","AlexanderGould"],
format:"DVD"
},
"StarWars:EpisodeVI-ReturnoftheJedi":{
releaseDate:1983,
duration:134,
actors:["MarkHamill","HarrisonFord","CarrieFisher"],
format:"DVD"
},
"HarryPotterandtheGobletofFire":{
releaseDate:2005,
duration:157,
actors:["DanielRadcliffe","EmmaWatson","RupertGrint"],
format:"Blu-ray"
}
};
YoumighthavenoticedthatIusedquotesforthemovietitles(thekeysintheouterobject)butnotforthekeysintheinnerobjects.That’sbecausethemovietitlesneedtohavespaces—otherwise,I’dhavetotypeeachtitlelikeStarWarsEpisodeVIReturnOfTheJedi,andthat’sjustsilly!Ididn’tneedquotesforthekeysintheinnerobjects,soIleftthemoff.Itcanmakecodelookabitcleanerwhentherearen’tunnecessarypunctuationmarksinit.
Now,whenyouwantinformationaboutamovie,it’seasytofind:varfindingNemo=movies["FindingNemo"];
findingNemo.duration;
100
findingNemo.format;
"DVD"
HerewesavethemovieinformationaboutFindingNemointoavariablecalledfindingNemo.Wecanthenlookatthepropertiesofthisobject(likedurationandformat)tofindoutaboutthemovie.Youcanalsoeasilyaddnewmoviestoyourcollection:
varcars={
releaseDate:2006,
duration:117,
actors:["OwenWilson","BonnieHunt","PaulNewman"],
format:"Blu-ray"
};
movies["Cars"]=cars;
HerewecreateanewobjectofmovieinformationaboutCars.Wetheninsertthisintothemoviesobject,underthekey"Cars".Nowthatyou’rebuildingupyourcollection,youmightwanttofindaneasywaytolistthenamesofallyourmovies.That’swhereObject.keyscomesin:
Object.keys(movies);
["FindingNemo","StarWars:EpisodeVI-ReturnoftheJedi","Harry
PotterandtheGobletofFire","Cars"]
WhatYouLearnedNowyou’veseenhowobjectsworkinJavaScript.They’realotlikearrays,becauseyoucanusethemtoholdlotsofpiecesofinformationtogetherinoneunit.Onemajordifferenceisthatyouusestringstoaccesselementsinanobjectandyouusenumberstoaccesselementsinanarray.Forthisreason,arraysareordered,whileobjectsarenot.We’llbedoingalotmorewithobjectsinlaterchapters,oncewe’velearnedaboutmoreofJavaScript’sfeatures.Inthenextchapter,we’lllookatconditionalsandloops,whicharebothwaysofaddingstructuretoourprogramstomakethemmorepowerful.
ProgrammingChallengesTryoutthesechallengestopracticeworkingwithobjects.#1:SCOREKEEPERImagineyou’replayingagamewithsomefriendsandyouwanttokeeptrackofthescore.Createanobjectcalledscores.Thekeyswillbethenamesofyourfriends,andthevalueswillbethescores(whichwillallstartat0).Astheplayersearnpoints,youmustincreasetheirscores.Howwouldyouincreaseaplayer’sscoreinthescoresobject?#2:DIGGINGINTOOBJECTSANDARRAYSSayyouhadthefollowingobject:
varmyCrazyObject={
"name":"Aridiculousobject",
"somearray":[7,9,{purpose:"confusion",number:123},3.3],
"randomanimal":"BananaShark"
};
Howwouldyougetthenumber123outofthisobjectusingonelineofJavaScript?Tryitoutintheconsoletoseeifyou’reright.
Chapter5.TheBasicsofHTMLThebrowser-basedJavaScriptconsolethatwe’vebeenusingsofarisgreatfortryingoutsmallsnippetsofcode,butinordertocreateactualprograms,we’llneedsomethingabitmoreflexible,likeawebpagewithsomeJavaScriptinit.Inthischapter,we’lllearnhowtocreateabasicHTMLwebpage.HTML(HyperTextMarkupLanguage)isthelanguageusedtomakewebpages.ThewordHyperTextreferstotextthatisconnectedbyhyperlinks,thelinksonawebpage.Amarkuplanguageisusedtoannotatedocumentssothatthey’renotjustplaintext.Themarkuptellssoftware(likeawebbrowser)howtodisplaythetextandwhattodowithit.Inthischapter,I’llshowyouhowtowriteHTMLdocumentsinatexteditor,asimpleprogramdesignedforwritingplaintextfileswithouttheformattingyoufindinwordprocessorslikeMicrosoftWord.Word-processeddocumentscontainformattedtext(withdifferentfonts,typecolors,fontsizes,etc.),andwordprocessorsaredesignedtomakeiteasytochangetheformattingofthetext.Wordprocessorsusuallyallowyoutoinsertimagesandgraphicsaswell.Plaintextfilescontainjusttext,withoutanyinformationaboutthefont,color,size,andsoon.Youcan’tputanimageinatextfileunlessyoumakeitoutoftext—likethiscat,forexample.
/\_/\
=(°w°)=
)(//
(____)//
TextEditorsWe’llwriteourHTMLinthecross-platform(compatiblewithWindows,MacOS,andLinux)SublimeTexteditor.YoucandownloadanduseSublimeTextforfree,butafterawhileyou’llbeaskedtopayforalicense.Ifyoudon’tlikethatidea,I’velistedsomecompletelyfreealternativesbelow.MyinstructionsinthischapteraregearedtowardSublimeText,butsincetexteditorsarerelativelysimple,theinstructionsshouldworkprettymuchthesameforanyeditor.
Geditisacross-platformtexteditorfromtheGNOMEproject(https://wiki.gnome.org/Apps/Gedit/).ForMicrosoftWindows,Notepad++(http://notepad-plus-plus.org/)isanothergoodalternative.OnMacOS,TextWrangler(http://www.barebones.com/products/textwrangler/)isagoodoption.
ToinstallSublimeText,visithttp://www.sublimetext.com/.Installationinstructionsdifferforeachoperatingsystem,butyoushouldfindthemprettyclear.Ifyourunintoanyproblems,trytheSupportsectionattheSublimeTexthomepage.
SYNTAXHIGHLIGHTING
SublimeTextwillcolor-codeyourprogramswithsyntaxhighlighting.Thisisdesignedtomakeprogramseasierforprogrammerstoreadbyassigningdifferentcolorstodifferenttypesofcode.Forexample,stringsmightbegreen,whilekeywordslikevarmightbeorange.
SublimeTexthaslotsofcolorschemestochoosefrom.Inthisbook,we’reusingtheIDLEcolorscheme,whichyoucanmatchonyourscreenbygoingtoPreferences▸ColorSchemeandselectingIDLE.
OurFirstHTMLDocumentOnceyou’veinstalledSublimeText,starttheprogramandcreateanewfilewithFile▸NewFile.Next,chooseFile▸Savetosaveyournew,blankfile;nameitpage.htmlandsaveittoyourdesktop.Nowit’stimetowritesomeHTML.Enterthefollowingtextintoyourpage.htmlfile:
<h1>Helloworld!</h1>
<p>Myfirstwebpage.</p>
Saveyourupdatedversionofpage.htmlwithFile▸Save.Nowlet’sseewhatthatpagewouldlooklikeinawebbrowser.OpenChrome,chooseFile▸OpenFile,andselectpage.htmlfromyourdesktop.YoushouldseesomethinglikeFigure5-1.
Figure5-1.YourfirstHTMLpageinChrome
You’vejustcreatedyourfirstHTMLdocument!Althoughyou’reviewingitinyourwebbrowser,it’snotactuallyontheInternet.Chromeisopeningyourpagelocallyandjustreadingyourmarkuptagstofigureoutwhattodowithitstext.
TagsandElementsHTMLdocumentsaremadeupofelements.Anelementstartswithastarttagandendswithanendtag.Forexample,inourdocumentsofarwehavetwoelements:h1andp.Theh1elementstartswiththestarttag<h1>andendswiththeendtag</h1>.Thepelementstartswiththestarttag<p>andendswiththeendtag</p>.Anythingbetweentheopeningandclosingtagsisthecontentoftheelement.Starttagsconsistoftheelementnamesurroundedbyanglebrackets:<and>.Endtagsarethesame,buttheyhaveaforwardslash(/)beforetheelementname.
HeadingElementsEachelementhasaspecialmeaninganduse.Forexample,theh1elementmeans“Thisisatop-levelheading.”Thecontentyouputinbetweentheopeningandclosing<h1>tagsisdisplayedbythebrowseronitsownline,inalarge,boldfont.TherearesixlevelsofheadingelementsinHTML:h1,h2,h3,h4,h5,andh6.Theylooklikethis:
<h1>First-levelheading</h1>
<h2>Second-levelheading</h2>
<h3>Third-levelheading</h3>
<h4>Fourth-levelheading</h4>
<h5>Fifth-levelheading</h5>
<h6>Sixth-levelheading</h6>
Figure5-2showshowtheheadingslookonawebpage.
Figure5-2.Thedifferentheadingelements
ThepElementThepelementisusedtodefineseparateparagraphsoftext.Anytextyouputbetween<p>tagswilldisplayinaseparateparagraph,withsomespaceaboveandbelowtheparagraph.Let’strycreatingmultiplepelements.Addthisnewlinetoyourpage.htmldocument(theoldlinesareshowningray):
<h1>Helloworld!</h1>
<p>Myfirstwebpage.</p>
<p>Let'saddanotherparagraph.</p>
Figure5-3showsthewebpagewiththenewparagraph.
Figure5-3.Thesamepagebutwithanextraparagraph
Noticethattheparagraphsappearondifferentlinesandareseparatedbyabitofspace.Thisisallbecauseofthe<p>tags.
WhitespaceinHTMLandBlock-LevelElementsWhatwouldourpagelooklikewithoutthetags?Let’stakealook:
Helloworld!
Myfirstwebpage.
Let'saddanotherparagraph.
Figure5-4showsourpagewithoutanytags.
Figure5-4.ThesamepagebutwithnoHTMLtags
Ohno!Notonlyhavewelosttheformatting,buteverything’sononelongline!ThereasonisthatinHTML,allwhitespaceiscollapsedintoasinglespace.Whitespacemeansanycharacterthatresultsinblankspaceonthepage—forexample,thespacecharacter,thetabcharacter,andthenewlinecharacter(thecharacterthatisinsertedwhenyoupressENTERorRETURN).AnyblanklinesyouinsertbetweentwopiecesoftextinanHTMLdocumentwillgetcollapsedintoasinglespace.
Thepandh1elementsarecalledblock-levelelementsbecausetheydisplaytheircontentinaseparateblock,startingonanewline,andwithanyfollowingcontentonanewline.
InlineElementsLet’saddtwomoreelementstoourdocument,emandstrong:
<h1>Helloworld!</h1>
<p>My<em>first</em><strong>webpage</strong>.</p>
<p>Let'saddanother<strong><em>paragraph</em></strong>.</p>
Figure5-5showswhatthepagelookslikewiththenewtags.
Figure5-5.Theemandstrongelements
Theemelementmakesitscontentitalic.Thestrongelementmakesitscontentbold.Theemandstrongelementsarebothinlineelements,whichmeansthattheydon’tputtheircontentontoanewline,asblock-levelelementsdo.Tomakecontentboldanditalic,putitinsidebothtags.Noticeinthepreviousexamplethatthebolditalictexthasthetagsinthisorder:<strong><em>paragraph</em></strong>.It’simportanttoproperlynestelements.Nestingmeansthatifanelementisinsideanotherelement,itsopeningandclosingtagsshouldbothbeinsidetheparentelement.Forexample,thisisnotallowed:
<strong><em>paragraph</strong></em>
Inthiscase,theclosing</strong>tagcomesbeforetheclosing</em>tag.Browsersgenerallywon’ttellyouwhenyou’vemadeamistakelikethis,butgettingnestingwrongcancauseyourpagestobreakinstrangeways.
AFullHTMLDocumentWhatwe’velookedatsofarisreallyjustasnippetofHTML.AfullHTMLdocumentrequiressomeextraelements.Let’stakealookatanexampleofacompleteHTMLdocumentandwhateachpartmeans.Updateyourpage.htmlfilewiththesenewelements:
<!DOCTYPEhtml>
<html>
<head>
<title>MyfirstproperHTMLpage</title>
</head>
<body>
<h1>Helloworld!</h1>
<p>My<em>first</em><strong>webpage</strong>.</p>
<p>Let'saddanother<strong><em>paragraph</em></strong>.</p>
</body>
</html>
NOTE
SublimeTextshouldautomaticallyindentcertainlinesforyou,asshowninthisexample.It’sactuallyidentifyinglinesbasedontheirtags(like<html>,<h1>,andsoon)andindentingthemaccordingtotheirnesting.SublimeTextdoesn’tindentthe<head>and<body>tags,thoughsomeeditorsdo.
Figure5-6showsthecompleteHTMLdocument.
Figure5-6.ThecompleteHTMLdocument
Let’stakeawalkthroughtheelementsinourpage.htmlfile.The<!DOCTYPEhtml>tagisjustadeclaration.Itsimplysays,“ThisisanHTMLdocument.”Nextcomestheopening<html>tag(theclosing</html>tagisattheveryend).AllHTMLdocumentsmusthaveanhtmlelementastheiroutermostelement.Therearetwoelementsinsidethehtmlelement:headandbody.TheheadelementcontainscertaininformationaboutyourHTMLdocument,suchasthetitleelement,whichcontainsthedocument’stitle.Forexample,noticethatinFigure5-6,thetitleinthebrowsertab—“MyfirstproperHTMLpage”—matcheswhatweenteredinthetitleelement.Thetitleelementiscontainedinsidetheheadelement,whichiscontainedinsidethehtmlelement.Thebodyelementcontainsthecontentthatwillbedisplayedinthebrowser.Here,we’vejustcopiedtheHTMLfromearlierinthechapter.
HTMLHierarchyHTMLelementshaveaclearhierarchy,ororder,andcanbethoughtofasakindofupside-downtree.YoucanseehowourdocumentwouldlookasatreeinFigure5-7.
Figure5-7.TheelementsfromFigure5-6,shownasatree
Thetopelementisthehtmlelement.Itcontainstheheadandbodyelements.Theheadcontainsthetitleelement,andthebodycontainstheh1andpelements.ThebrowserinterpretsyourHTMLaccordingtothishierarchy.We’lllookathowtochangethedocumentstructurelater,inChapter9.Figure5-8showsanotherwayofvisualizingtheHTMLhierarchy,asasetofnestedboxes.
Figure5-8.TheHTMLhierarchy,shownasnestedboxes
AddingLinkstoYourHTMLEarlierinthischapter,welearnedthattheHTinHTMLstandsforHyperText,orlinkedtext.HTMLdocumentscancontainhyperlinks(linksforshort)thattakeyoutootherwebpages.Theaelement(foranchor)createsalinkelement.ModifyyourHTMLdocumenttomatchthefollowingexample:deletethesecondpelementandthe<em>and<strong>tags,andthenaddthenewcoloredcodetocreatealinktohttp://xkcd.com/:
<!DOCTYPEhtml>
<html>
<head>
<title>MyfirstproperHTMLpage</title>
</head>
<body>
<h1>Helloworld!</h1>
<p>Myfirstwebpage.</p>
<p><ahref="http://xkcd.com">Clickhere</a>toreadsomeexcellent
comics.</p>
</body>
</html>
Nowsaveandopenyourpageinyourbrowser,anditshouldlooklikeFigure5-9.
Figure5-9.Awebpagecontainingalinktohttp://xkcd.com/
Ifyouclickthatlink,yourbrowsershouldgotothexkcdwebsite,http://xkcd.com/.Onceyou’vehadyourfillofgeekycomics,clickthebackbuttontoreturntoyourpage.
LinkAttributesLet’stakeacloserlookathowwecreatedthatHTMLlink.Totellthebrowserwheretogowhenyouclicktheaelement,weaddedsomethingcalledanattributetotheanchorelement.AttributesinHTMLelementsaresimilartokey-valuepairsinJavaScriptobjects.Everyattributehasanameandavalue.Here’sthexkcdlinkwecreatedagain:
<ahref="http://xkcd.com">Clickhere</a>
Inthiscase,theattributenameishrefandtheattributevalueis"http://xkcd.com".Thenamehrefstandsforhypertextreference,whichisafancywayofsaying“webaddress.”Figure5-10showsallthepartsofthelink.
Figure5-10.Thebasicsyntaxforcreatingahyperlink
Thelinkwilltakeyoutowhateverwebaddressisenteredasthevalueofthehrefattribute.
TitleAttributesAnotherattributewecanaddtolinksisthetitleattribute.Thisattributesetsthetextyouseewhenyouhoveryourmouseoveralink.Forexample,changetheopening<a>tagsoitlookslikethis:
<ahref="http://xkcd.com"title="xkcd:Landofgeekycomics!">Clickhere</a>
Nowreloadthepage.Whenyouhoveryourcursoroverthelink,youshouldseethetext“xkcd:Landofgeekycomics!”floatingabovethepage,asshowninFigure5-11.
Figure5-11.Awebpagecontainingalinktohttp://xkcd.com/withatitleattribute
TRYITOUT!
Makeanewfilecalledlinks.html.ItshouldcontainthesameHTMLstructureasourpage.html,butwithanewtitleandheadingandthreeparagraph(p)elements.Ineachparagraph,includealinktooneofyourfavoritewebsites.Makesurealltheaelementshavehrefandtitleattributes.
WhatYouLearnedInthischapter,youlearnedthebasicsofHTML,thelanguageusedtocreatewebpages.Wecreatedasimplepagecontainingalinktoanotherpage.Inthenextchapter,we’lllookathowtoembedJavaScriptinourwebpage.ThiswillmakeitmucheasiertocreatelargerprogramsasweexploremorefeaturesofJavaScriptinthenextfewchapters.ThisisabookonJavaScript,notHTML,soI’veintroducedonlytheverybasicsofcreatingHTMLdocuments.HerearesomeresourceswhereyoucanlearnmoreaboutHTML:
TheMozillaDeveloperNetwork’sIntroductiontoHTML:https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Introduction/Codecademy’sHTMLandCSScourse:http://www.codecademy.com/tracks/web/MozillaWebmaker:https://webmaker.org/
Chapter6.ConditionalsandLoopsConditionalsandloopsaretwoofthemostimportantconceptsinJavaScript.Aconditionalsays,“Ifsomethingistrue,dothis.Otherwise,dothat.”Forexample,ifyoudoyourhomework,youcanhaveicecream,butifyoudon’tdoyourhomework,youdon’tgettheicecream.Aloopsays,“Aslongassomethingistrue,keepdoingthis.”Forexample,aslongasyouarethirsty,keepdrinkingwater.Conditionalsandloopsarepowerfulconceptsthatarekeytoanysophisticatedprogram.Theyarecalledcontrolstructuresbecausetheyallowyoutocontrolwhichpartsofyourcodeareexecutedwhenandhowoftenthey’reexecuted,basedoncertainconditionsyoudefine.WefirstneedtogooverhowtoembedJavaScriptinourHTMLfilesowecanstartcreatinglongerprogramsthanwe’velookedatsofar.
EmbeddingJavaScriptinHTMLHereistheHTMLfilewecreatedinChapter5,withadditionsincolorandtheexistingtextingray.(Tomakethisexamplealittlesimpler,I’vealsodeletedthelinktoxkcd.)
<!DOCTYPEhtml>
<html>
<head>
<title>MyfirstproperHTMLpage</title>
</head>
<body>
<h1>Helloworld!</h1>
<p>Myfirstwebpage.</p>
<script>
varmessage="Helloworld!";
console.log(message);
</script>
</body>
</html>
Herewe’veaddedanewelement,calledscript.ThisisaspecialelementinHTML.WithmostHTMLelements,thecontentbetweentheopeningandclosingtagsisdisplayedonthepage.Withscript,ontheotherhand,everythingbetweenthetagsistreatedasJavaScriptandrunbytheJavaScriptinterpreter.Nowlet’slookatthecodeinsidethescriptelement:
varmessage="Helloworld!";
➊console.log(message);
RunningJavaScriptinanHTMLfileisquitedifferentfromrunningitintheconsole.Whenyou’reusingtheJavaScriptconsole,eachlineyoutypeisrunassoonasyoupressENTER,andthevalueofthatlineisprintedouttotheconsole.Inawebpage,theJavaScriptisallrunfromtoptobottomatonetime,andnothingisautomaticallyprintedtotheconsole,unlesswetellthebrowserotherwise.Wecanuseconsole.logtoprintthingsout,whichwillmakeiteasiertoseewhat’sgoingonaswerunourprograms.Theconsole.logmethodtakesanyvalueandprintsout,orlogs,thatvaluetotheconsole.Forexample,ifyouloadtheHTMLfilefromthebeginningofthissectionwiththeJavaScriptconsoleopen,you’llseethis:
Helloworld!
Callingconsole.log(message)at➊causedthestring"Helloworld!"tobeprintedtotheconsole.NowthatyouknowhowtowritelongerprogramswithJavaScript,youcanstartlearningaboutconditionals.
ConditionalsTherearetwoformsofconditionalstatementsinJavaScript:ifstatementsandif...elsestatements.Anifstatementisusedtoexecuteapieceofcodeifsomethingistrue.Forexample,ifyou’vebeengood,yougetatreat.Anif...elsestatementexecutesonepieceofcodeifsomethingistrueandanotherifnot.Forexample,ifyou’vebeengood,yougetatreat;else,yougetgrounded.
ifStatementsTheifstatementisthesimplestofJavaScript’scontrolstructures.It’susedtoruncodeonlyifaconditionistrue.ReturntoyourHTMLfileandreplacethetwolinesinsidethescriptelementwiththis:
➊varname="Nicholas";
➋console.log("Hello"+name);
➌if(name.length>7){
➍console.log("Wow,youhaveaREALLYlongname!");
}
First,at➊wecreateavariablecallednameandsetitsvaluetothestring"Nicholas".Thenweuseconsole.logtologthestring"HelloNicholas"at➋.At➌weuseanifstatementtocheckwhetherthelengthofnameisgreaterthan7.Ifitis,theconsolewilldisplay"Wow,youhaveaREALLYlongname!",usingconsole.logat➍.AsFigure6-1shows,anifstatementhastwomainparts:theconditionandthebody.TheconditionshouldbeaBooleanvalue.ThebodyisoneormorelinesofJavaScriptcode,whichareexecutediftheconditionistrue.
Figure6-1.Thegeneralstructureofanifstatement
WhenyouloadyourHTMLpagewiththisJavaScriptinit,youshouldseethefollowingintheconsole:HelloNicholas
Wow,youhaveaREALLYlongname!
BecausethenameNicholashaseightcharacters,name.lengthreturns8.Therefore,theconditionname.length>7istrue,whichcausesthebodyoftheifstatementtoberun,resultinginthissomewhatstartlingmessagebeinglogged.Toavoidtriggeringtheifcondition,changethenameNicholastoNick(leavingtherestofthecodeasis):
varname="Nick";
Nowsavethefileandreloadthepage.Thistime,theconditionname.length>7isnottrue,becausename.lengthis4.Thatmeansthatthebodyoftheifstatementisnotrunandallthatgetsprintedtotheconsoleisthis:
HelloNick
Thebodyofanifstatementisexecutedonlyiftheconditionistrue.Whentheconditionisfalse,theinterpretersimplyskipsovertheifstatementandmovesontothenextline.
if...elseStatementsAsIsaidbefore,anifstatementwillexecuteitsbodyonlyiftheconditionistrue.Ifyouwantsomethingelsetohappenwhentheconditionisfalse,youneedtouseanif...elsestatement.Let’sextendtheexamplefromearlier:
varname="Nicholas";
console.log("Hello"+name);
if(name.length>7){
console.log("Wow,youhaveaREALLYlongname!");}
else{
console.log("Yournameisn'tverylong.");
}
Thisdoesthesamethingasbefore,exceptthatifthenameisn’tlongerthansevencharacters,itprintsoutanalternativemessage.
AsFigure6-2shows,if...elsestatementslooklikeifstatements,butwithtwobodies.Thekeywordelseisplacedbetweenthetwobodies.Inanif...elsestatement,thefirstbodyisruniftheconditionistrue;otherwise,thesecondbodyisrun.
Figure6-2.Thegeneralstructureofanif...elsestatement
Chainingif...elseStatementsOftenweneedtocheckasequenceofconditionsanddosomethingwhenoneofthemistrue.Forexample,sayyou’reorderingChinesefoodandyou’rechoosingwhattoeat.YourfavoriteChinesedishislemonchicken,soyou’llhavethatifit’sonthemenu.Ifit’snot,you’llhavebeefwithblackbeansauce.Ifthat’snotonthemenu,you’llhavesweetandsourpork.Intherarecasethatnoneofthoseoptionsisavailable,you’llhaveeggfriedrice,becauseyouknowalltheChineserestaurantsyougotowillhavethat.
varlemonChicken=false;
varbeefWithBlackBean=true;
varsweetAndSourPork=true;
if(lemonChicken){
console.log("Great!I'mhavinglemonchicken!");
}elseif(beefWithBlackBean){
console.log("I'mhavingthebeef.");
}elseif(sweetAndSourPork){
console.log("OK,I'llhavethepork.");
}else{
console.log("Well,IguessI'llhavericethen.");
}
Tocreateachainofif...elsestatements,startwithanormalifstatementand,aftertheclosingbraceofitsbody,enterthekeywordselseif,followedbyanotherconditionandanotherbody.Youcankeepdoingthisuntilyourunoutofconditions;there’snolimittothenumberofconditions.Thefinalelsesectionwillrunifnoneoftheconditionsistrue.Figure6-3showsagenericchainofif...elsestatements.
Figure6-3.Chainingmultipleif...elsestatements
Youcanreadthisasfollows:1. Ifthefirstconditionistrue,executethefirstbody.2. Otherwise,ifthesecondconditionistrue,executethesecondbody.3. Otherwise,ifthethirdconditionistrue,executethethirdbody.4. Otherwise,executetheelsebody.
Whenyouhaveachainofif...elsestatementslikethiswithafinalelsesection,youcanbesurethatone(andonlyone)ofthebodieswillberun.Assoonasatrueconditionisfound,itsassociatedbodyisrun,andnoneoftheotherconditionsischecked.Ifwerunthecodeinthepreviousexample,I'm
havingthebeefwillbeprintedtotheconsole,becausebeefWithBlackBeanisthefirstconditionthat’sfoundtobetrueintheif...elsechain.Ifnoneoftheconditionsistrue,theelsebodyisrun.
There’soneotherthingtonote:youdon’tnecessarilyhavetoincludethefinalelse.Ifyoudon’t,though,andnoneoftheconditionsistrue,thennothinginsidetheif...elsechainwillbeexecuted.
varlemonChicken=false;
varbeefWithBlackBean=false;
varsweetAndSourPork=false;
if(lemonChicken){
console.log("Great!I'mhavinglemonchicken!");
}elseif(beefWithBlackBean){
console.log("I'mhavingthebeef.");
}elseif(sweetAndSourPork){
console.log("OK,I'llhavethepork.");
}
Inthisexample,we’veleftoutthefinalelsesection.Becausenoneofyourfavoritefoodsisavailable,nothinggetsprintedout(anditlookslikeyou’renotgoingtohaveanythingtoeat!).
TRYITOUT!
Writeaprogramwithanamevariable.Ifnameisyourname,printoutHellome!;otherwise,printHellostranger!.(Hint:Use===tocomparenametoyourname.)
Next,rewritetheprogramsoit’llsayhitoyourdadifnameissettoyourdad’snameorhitoyourmomifnameisyourmom’sname.Ifit’sneitherofthem,sayHellostranger!asbefore.
LoopsAswe’veseen,conditionalsallowyoutorunapieceofcodeonceifaconditionistrue.Loops,ontheotherhand,allowyoutorunapieceofcodemultipletimes,dependingonwhetheraconditionremainstrue.Forexample,whilethere’sfoodonyourplate,youshouldkeepeating;or,whileyoustillhavedirtonyourface,youshouldkeepwashing.
whileLoopsThesimplestkindofloopisawhileloop.Awhilelooprepeatedlyexecutesitsbodyuntilaparticularconditionstopsbeingtrue.Bywritingawhileloop,youaresaying,“Keepdoingthiswhilethisconditionistrue.Stopwhentheconditionbecomesfalse.”AsFigure6-4shows,whileloopsstartwiththewhilekeyword,followedbyaconditioninparenthesesandthenabodyinbraces.
Figure6-4.Thegeneralstructureofawhileloop
Likeanifstatement,thebodyofawhileloopisexecutediftheconditionistrue.Unlikeanifstatement,afterthebodyisexecuted,theconditionischeckedagain,andifit’sstilltrue,thebodyrunsagain.Thiscyclegoesonuntiltheconditionisfalse.
CountingSheepwithawhileloopSayyou’rehavingtroublesleepingandyouwanttocountsheep.Butyou’reaprogrammer,sowhynotwriteaprogramtocountsheepforyou?
varsheepCounted=0;
➊while(sheepCounted<10){
➋console.log("Ihavecounted"+sheepCounted+"sheep!");
sheepCounted++;
}
console.log("Zzzzzzzzzzz");
WecreateavariablecalledsheepCountedandsetitsvalueto0.Whenwereachthewhileloop➊,wechecktoseewhethersheepCountedislessthan10.Because0islessthan10,thecodeinsidethebraces(thebodyoftheloop)➋runs,and"Ihavecounted"+sheepCounted+"sheep!"isloggedas“Ihavecounted0sheep!”Next,sheepCounted++adds1tothevalueofsheepCounted,andwegobacktothestartoftheloop,overandover:
Ihavecounted0sheep!
Ihavecounted1sheep!
Ihavecounted2sheep!
Ihavecounted3sheep!
Ihavecounted4sheep!
Ihavecounted5sheep!
Ihavecounted6sheep!
Ihavecounted7sheep!
Ihavecounted8sheep!
Ihavecounted9sheep!
Zzzzzzzzzzz
ThisrepeatsuntilsheepCountedbecomes10,atwhichpointtheconditionbecomesfalse(10isnotlessthan10),andtheprogrammovesontowhatevercomesaftertheloop.Inthiscase,itprintsZzzzzzzzzzz.
PreventingInfiniteLoopsKeepthisinmindwhenyou’reusingloops:iftheconditionyousetneverbecomesfalse,yourloopwillloopforever(oratleastuntilyouquityourbrowser).Forexample,ifyouleftoutthelinesheepCounted++;,thensheepCountedwouldremain0,andtheoutputwouldlooklikethis:
Ihavecounted0sheep!
Ihavecounted0sheep!
Ihavecounted0sheep!
Ihavecounted0sheep!
...
Becausethere’snothingtostopit,theprogramwouldkeepdoingthisforever!Thisiscalledaninfiniteloop.
forLoopsforloopsmakeiteasiertowriteloopsthatcreateavariable,loopuntilaconditionistrue,andupdatethevariableattheendofeachturnaroundtheloop.Whensettingupaforloop,youcreateavariable,specifythecondition,andsayhowthevariableshouldchangeaftereachcycle—allbeforeyoureachthebodyoftheloop.Forexample,here’showwecoulduseaforlooptocountsheep:
for(varsheepCounted=0;sheepCounted<10;sheepCounted++){
console.log("Ihavecounted"+sheepCounted+"sheep!");
}
console.log("Zzzzzzzzzzz");
AsFigure6-5shows,therearethreepartstothisforloop,separatedbysemicolons:thesetup,condition,andincrement.
Figure6-5.Thegeneralstructureofaforloop
Thesetup(varsheepCounted=0)isrunbeforetheloopstarts.It’sgenerallyusedtocreateavariabletotrackthenumberoftimestheloophasrun.HerewecreatethevariablesheepCountedwithaninitialvalueof0.Thecondition(sheepCounted<10)ischeckedbeforeeachrunoftheloopbody.Iftheconditionistrue,thebodyisexecuted;ifit’sfalse,theloopstops.Inthiscase,theloopwillstoponcesheepCountedisnolongerlessthan10.Theincrement(sheepCounted++)isrunaftereveryexecutionoftheloopbody.It’sgenerallyusedtoupdatetheloopingvariable.Here,weuseittoadd1tosheepCountedeachtimetheloopruns.forloopsareoftenusedtodosomethingasetnumberoftimes.Forexample,thisprogramwillsayHello!threetimes.
vartimesToSayHello=3;
for(vari=0;i<timesToSayHello;i++){
console.log("Hello!");
}
Hereistheoutput:Hello!
Hello!
Hello!
IfweweretheJavaScriptinterpreterrunningthiscode,wewouldfirstcreateavariablecalledtimesToSayHelloandsetitto3.Whenwereachtheforloop,werunthesetup,whichcreatesavariableiandsetsitto0.Next,wecheckthecondition.Becauseiisequalto0andtimesToSayHellois3,theconditionistrue,soweentertheloopbody,whichsimplyoutputsthestring"Hello!".Wethenruntheincrement,whichincreasesito1.
Nowwechecktheconditionagain.It’sstilltrue,sowerunthebodyandincrementagain.Thishappensrepeatedlyuntiliisequalto3.Atthispoint,theconditionisfalse(3isnotlessthan3),soweexittheloop.
UsingforLoopswithArraysandStringsOneverycommonuseofforloopsistodosomethingwitheveryelementinanarrayoreverycharacterinastring.Forexample,hereisaforloopthatprintsouttheanimalsinazoo:
varanimals=["Lion","Flamingo","PolarBear","BoaConstrictor"];
for(vari=0;i<animals.length;i++){
console.log("Thiszoocontainsa"+animals[i]+".");
}
Inthisloop,istartsat0andgoesuptoonelessthananimals.length,whichinthiscaseis3.Thenumbers0,1,2,and3aretheindexesoftheanimalsintheanimalsarray.Thismeansthateverytimearoundtheloop,iisadifferentindex,andanimals[i]isanotheranimalfromtheanimalsarray.Wheniis0,animals[i]is"Lion".Wheniis1,animals[i]is"Flamingo",andsoon.Runningthiswouldoutput:
ThiszoocontainsaLion.
ThiszoocontainsaFlamingo.
ThiszoocontainsaPolarBear.
ThiszoocontainsaBoaConstrictor.
AsyousawinChapter2,youcanaccessindividualcharactersinastringinthesamewayyoucanaccessindividualelementsinanarray,usingsquarebrackets.Thisnextexampleusesaforlooptoprintoutthecharactersinaname:
varname="Nick";
for(vari=0;i<name.length;i++){
console.log("Mynamecontainstheletter"+name[i]+".");
}
Thiswouldoutput:MynamecontainstheletterN.
Mynamecontainstheletteri.
Mynamecontainstheletterc.
Mynamecontainstheletterk.
OtherWaystouseforLoopsAsyoumightimagine,youdon’talwayshavetostarttheloopingvariableat0andincrementitby1.Forexample,here’sawaytoprintallthepowersof2belowthenumber10,000:
for(varx=2;x<10000;x=x*2){
console.log(x);
}
Wesetxto2andincrementthevalueofxusingx=x*2;,whichwilldoublethevalueofxeachtimetheloopruns.Theresultgetsbigveryquickly,asyoucansee:
2
4
8
16
32
64
128
256
512
1024
2048
4096
8192
Andvoilà!Thisshortforloopprintsoutallthepowersof2below10,000.
TRYITOUT!
Writealooptoprintthepowersof3under10,000(itshouldprint3,9,27,etc.).
Rewritethisloopwithawhileloop.(Hint:Providethesetupbeforetheloop.)
WhatYouLearnedInthischapter,youlearnedaboutconditionalsandloops.Conditionalsareusedtoruncodeonlywhenacertainconditionistrue.Loopsareusedtoruncodemultipletimesandtokeeprunningthatcodeaslongasacertainconditionistrue.Youcanuseconditionalstomakesurethattherightcodeisrunattherighttime,andyoucanuseloopstokeepyourprogramrunningaslongasnecessary.Havingtheabilitytodothesetwothingsopensupawholenewworldofprogrammingpossibilities.Inthenextchapter,we’llusethepowerofconditionalsandloopstomakeourfirstrealgame!
ProgrammingChallengesTryoutthesechallengestopracticeworkingwithconditionalsandloops.#1:AWESOMEANIMALSWriteaforloopthatmodifiesanarrayofanimals,makingthemawesome!Forexample,ifyourstartingarrayis...
varanimals=["Cat","Fish",
"Lemur","KomodoDragon"];
thenafteryourunyourloop,itshouldlooklikethis:["AwesomeCat","AwesomeFish","AwesomeLemur","Awesome
KomodoDragon"]
Hint:You’llneedtoreassignvaluestothearrayateachindex.Thisjustmeansassigninganewvalueatanexistingpositioninthearray.Forexample,tomakethefirstanimalawesome,youcouldsay:
animals[0]="Awesome"+animals[0];
#2:RANDOMSTRINGGENERATORMakearandomstringgenerator.You’llneedtostartwithastringcontainingallthelettersinthealphabet:
varalphabet="abcdefghijklmnopqrstuvwxyz";
Topickarandomletterfromthisstring,youcanupdatethecodeweusedfortherandominsultgeneratorinChapter3:Math.floor(Math.random()*alphabet.length).Thiswillcreatearandomindexintothestring.Youcanthenusesquarebracketstogetthecharacteratthatindex.Tocreatetherandomstring,startwithanemptystring(varrandomString="").Then,createawhileloopthatwillcontinuallyaddnewrandomletterstothisstring,aslongasthestringlengthislessthan6(oranylengthyouchoose).Youcouldusethe+=operatortoaddanewlettertotheendofthestring.Aftertheloophasfinished,logittotheconsoletoseeyourcreation!#3:H4CK3RSP34KTurntextintoh4ck3rsp34k!AlotofpeopleontheInternetliketoreplacecertainletterswithnumbersthatlooklikethoseletters.Somenumbersthatlooklikelettersare4forA,3forE,1forI,and0forO.Eventhoughthenumberslookmorelikecapitalletters,we’llbereplacingthelowercaseversionsofthoseletters.Tochangenormaltexttoh4ck3rsp34k,we’llneedaninputstringandanewemptystring:
varinput="javascriptisawesome";
varoutput="";
You’llthenneedtouseaforlooptogothroughallthelettersoftheinputstring.Iftheletteris"a",adda"4"totheoutputstring.Ifit’s"e",adda"3".Ifit’s"i",adda"1",andifit’s"o",adda"0".Otherwise,justaddtheoriginallettertothenewstring.Asbefore,youcanuse+=toaddeachnewlettertotheoutputstring.Aftertheloop,logtheoutputstringtotheconsole.Ifitworkscorrectly,youshouldseeitlog"j4v4scr1pt1s4w3s0m3".
Chapter7.CreatingaHangmanGameInthischapterwe’llbuildaHangmangame!We’lllearnhowtousedialogstomakethegameinteractiveandtakeinputfromsomeoneplayingthegame.Hangmanisaword-guessinggame.Oneplayerpicksasecretword,andtheotherplayertriestoguessit.Forexample,ifthewordwereTEACHER,thefirstplayerwouldwrite:
Theguessingplayertriestoguessthelettersintheword.Eachtimetheyguessalettercorrectly,thefirstplayerfillsintheblanksforeachoccurrenceofthatletter.Forexample,iftheguessingplayerguessedtheletterE,thefirstplayerwouldfillintheEsinthewordTEACHERlikeso:
Whentheguessingplayerguessesaletterthatisn’tintheword,theyloseapointandthefirstplayerdrawspartofastick-manforeachwrongguess.Ifthefirstplayercompletesthestickmanbeforetheguessingplayerguessestheword,theguessingplayerloses.InourversionofHangman,theJavaScriptprogramwillchoosethewordandthehumanplayerwillguessletters.Wewon’tbedrawingthestickman,becausewehaven’tyetlearnedhowtodrawinJavaScript(we’lllearnhowtodothatinChapter13).
InteractingwithaPlayerTocreatethisgame,wehavetohavesomewayfortheguessingplayer(human)toentertheirchoices.Onewayistoopenapop-upwindow(whichJavaScriptcallsaprompt)thattheplayercantypeinto.
CreatingaPromptFirst,let’screateanewHTMLdocument.UsingFile▸SaveAs,saveyourpage.htmlfilefromChapter5asprompt.html.Tocreateaprompt,enterthiscodebetweenthe<script>tagsofprompt.htmlandrefreshthebrowser:
varname=prompt("What'syourname?");
console.log("Hello"+name);
Herewecreateanewvariable,calledname,andassigntoitthevaluereturnedfromcallingprompt("What'syourname?").Whenpromptiscalled,asmallwindow(ordialog)isopened,whichshouldlooklikeFigure7-1.
Figure7-1.Apromptdialog
Callingprompt("What'syourname?")popsupawindowwiththetext“What’syourname?”alongwithatextboxforinput.Atthebottomofthedialogaretwobuttons,CancelandOK.InChrome,thedialoghastheheadingJavaScript,toinformyouthatJavaScriptopenedtheprompt.WhenyouentertextintheboxandclickOK,thattextbecomesthevaluethatisreturnedbyprompt.Forexample,ifIweretoentermynameintothetextboxandclickOK,JavaScriptwouldprintthisintheconsole:
HelloNick
BecauseIenteredNickinthetextboxandclickedOK,thestring"Nick"issavedinthevariablenameandconsole.logprints"Hello"+"Nick",whichgivesus"HelloNick".
NOTE
ThesecondtimeyouopenanykindofdialoginChrome,itaddsanextralinetothedialogwithacheckboxsaying,“Preventthispagefromcreatingadditionaldialogs.”ThisisChrome’swayofprotectingusersfromwebpageswithlotsofannoyingpop-ups.Justleavetheboxuncheckedfortheexercisesinthischapter.
WHATHAPPENSIFYOUCLICKCANCEL?
IfyouclicktheCancelbutton,promptreturnsthevaluenull.InChapter2,welearnedthatyoucanusenulltoindicatewhensomethingisintentionallyempty.
ClickCancelatthedialog,andyoushouldseethis:Hellonull
Here,nullisprintedasastringbyconsole.log.Normally,nullisn’tastring,butsinceonlystringscanbeprintedtotheconsoleandyoutoldJavaScripttoprint"Hello"+null,JavaScriptturnsthevaluenullintothestring"null"soitcanbeprinted.WhenJavaScriptconvertsavalueintoanothertype,it’scalledcoercion.
CoercionisanexampleofJavaScripttryingtobeclever.Thereisn’tanywaytocombineastringandnullusingthe+operator,soJavaScriptdoesitsbestwiththesituation.Inthiscase,itknowsitneedstwostrings.Thestringversionofnullis"null",whichiswhyyouseethestring"Hellonull"printed.
UsingconfirmtoAskaYesorNoQuestionTheconfirmfunctionisawaytotakeuserinputwithoutatextboxbyaskingforayesorno(Boolean)answer.Forexample,hereweuseconfirmtoasktheuseriftheylikecats(seeFigure7-2).Ifso,thevariablelikesCatsissettotrue,andwerespondwith“You’reacoolcat!”Iftheydon’tlikecats,likesCatsissettofalse,sowerespondwith“Yeah,that’sfine.You’restillcool!”
varlikesCats=confirm("Doyoulikecats?");
if(likesCats){
console.log("You'reacoolcat!");
}else{
console.log("Yeah,that'sfine.You'restillcool!");
}
Figure7-2.Aconfirmdialog
TheanswertotheconfirmpromptisreturnedasaBooleanvalue.IftheuserclicksOKintheconfirmdialogshowninFigure7-2,trueisreturned.IftheyclickCancel,falseisreturned.
UsingAlertstoGiveaPlayerInformationIfyouwanttojustgivetheplayersomeinformation,youcanuseanalertdialogtodisplayamessagewithanOKbutton.Forexample,ifyouthinkthatJavaScriptisawesome,youmightusethisalertfunction:
alert("JavaScriptisawesome!");
Figure7-3showswhatthissimplealertdialogwouldlooklike.
Figure7-3.Analertdialog
AlertdialogsjustdisplayamessageandwaituntiltheuserclicksOK.
WhyUsealertInsteadofconsole.log?Whyuseanalertdialoginagameinsteadofusingconsole.log?First,becauseifallyouwanttodoistelltheplayersomething,usingalertmeanstheplayerdoesn’thavetointerruptgameplaytoopentheconsoletoseeastatusmessage.Second,callingalert(aswellaspromptandconfirm)pausestheJavaScriptinterpreteruntiltheuserclicksOK(orCancel,inthecaseofpromptandconfirm).Thatmeanstheplayerhastimetoreadthealert.Ontheotherhand,whenyouuseconsole.log,thetextisdisplayedimmediatelyandtheinterpretermovesontothenextlineinyourprogram.
DesigningYourGameBeforewestartwritingtheHangmangame,let’sthinkaboutitsstructure.Thereareafewthingsweneedourprogramtodo:1. Pickarandomword.2. Taketheplayer’sguess.3. Quitthegameiftheplayerwantsto.4. Checkthattheplayer’sguessisavalidletter.5. Keeptrackofletterstheplayerhasguessed.6. Showtheplayertheirprogress.7. Finishwhentheplayerhasguessedtheword.
Apartfromthefirstandlasttasks(pickingawordfortheplayertoguessandfinishingthegame),thesestepsallneedtohappenmultipletimes,andwedon’tknowhowmanytimes(itdependsonhowwelltheplayerguesses).Whenyouneedtodothesamethingmultipletimes,youknowyou’llneedaloop.Butthissimplelistoftasksdoesn’treallygiveusanyideaofwhatneedstohappenwhen.Togetabetterideaofthestructureofthecode,wecanusepseudocode.
UsingPseudocodetoDesigntheGamePseudocodeisahandytoolthatprogrammersoftenusetodesignprograms.Itmeans“fakecode,”andit’sawayofdescribinghowaprogramwillworkthatlookslikeacrossbetweenwrittenEnglishandcode.Pseudocodehasloopsandconditionals,butotherthanthat,everythingisjustplainEnglish.Let’slookatapseudocodeversionofourgametogetanidea:
Pickarandomword
Whilethewordhasnotbeenguessed{
Showtheplayertheircurrentprogress
Getaguessfromtheplayer
Iftheplayerwantstoquitthegame{
Quitthegame
}
ElseIftheguessisnotasingleletter{
Telltheplayertopickasingleletter
}
Else{
Iftheguessisintheword{
Updatetheplayer'sprogresswiththeguess
}
}
}
Congratulatetheplayeronguessingtheword
Asyoucansee,noneofthisisrealcode,andnocomputercouldunderstandit.Butitgivesusanideaofhowourprogramwillbestructured,beforewegettoactuallywritingthecodeandhavingtodealwiththemessydetails,likehowwe’regoingtopickarandomword.
TrackingtheStateoftheWordInthepreviouspseudocode,oneofthefirstlinessays,“Showtheplayertheircurrentprogress.”FortheHangmangame,thismeansfillinginthelettersthattheplayerhasguessedcorrectlyandshowingwhichlettersinthesecretwordarestillblank.Howarewegoingtodothis?Wecanactuallykeeptrackoftheplayer’sprogressinasimilarwaytohowtraditionalHangmanworks:bykeepingacollectionofblankspacesandfillingtheminastheplayerguessescorrectletters.Inourgame,we’lldothisusinganarrayofblanksforeachletterintheword.We’llcallthistheanswerarray,andwe’llfillitwiththeplayer’scorrectguessesasthey’remade.We’llrepresenteachblankwiththestring"_".Theanswerarraywillstartoutasagroupoftheseemptyentriesequalinnumbertothelettersinthesecretword.Forexample,ifthesecretwordisfish,thearraywouldlooklikethis:
["_","_","_","_"]
Iftheplayercorrectlyguessedtheletteri,we’dchangethesecondblanktoani:["_","i","_","_"]
Oncetheplayerguessesallthecorrectletters,thecompletedarraywouldlooklikethis:["f","i","s","h"]
We’llalsouseavariabletokeeptrackofthenumberofremainingletterstheplayerhastoguess.Foreveryoccurrenceofacorrectlyguessedletter,thisvariablewilldecreaseby1.Onceithits0,weknowtheplayerhaswon.
DesigningtheGameLoopThemaingametakesplaceinsideawhileloop(inourpseudocode,thisloopbeginswiththeline“Whilethewordhasnotbeenguessed”).Inthisloopwedisplaythecurrentstateofthewordbeingguessed(beginningwithallblanks);asktheplayerforaguess(andmakesureit’savalid,single-letterguess);andupdatetheanswerarraywiththechosenletter,ifthatletterappearsintheword.Almostallcomputergamesarebuiltaroundaloopofsomekind,oftenwiththesamebasicstructureastheloopinourHangmangame.Agameloopgenerallydoesthefollowing:1. Takesinputfromtheplayer2. Updatesthegamestate3. Displaysthecurrentstateofthegametotheplayer
Evengamesthatareconstantlychangingfollowthissamekindofloop—theyjustdoitreallyfast.InthecaseofourHangmangame,theprogramtakesaguessfromtheplayer,updatestheanswerarrayiftheguessiscorrect,anddisplaysthenewstateoftheanswerarray.Oncetheplayerguessesalllettersintheword,weshowthecompletedwordandacongratulatorymessagetellingthemthattheywon.
CodingtheGameNowthatweknowthegeneralstructureofourgame,wecanstarttogooverhowthecodewilllook.Thefollowingsectionswillwalkyouthroughallthecodeinthegame.Afterthat,you’llseethewholegamecodeinonelistingsoyoucantypeitupandplayityourself.
ChoosingaRandomWordThefirstthingwehavetodoistochoosearandomword.Here’showthatwilllook:
➊varwords=[
"javascript",
"monkey",
"amazing",
"pancake"
];
➋varword=words[Math.floor(Math.random()*words.length)];
Webeginourgameat➊bycreatinganarrayofwords(javascript,monkey,amazing,andpancake)tobeusedasthesourceofoursecretword,andwesavethearrayinthewordsvariable.Thewordsshouldbealllowercase.At➋weuseMath.randomandMath.floortopickarandomwordfromthearray,aswedidwiththerandominsultgeneratorinChapter3.
CreatingtheAnswerArrayNextwecreateanemptyarraycalledanswerArrayandfillitwithunderscores(_)tomatchthenumberoflettersintheword.
varanswerArray=[];
➊for(vari=0;i<word.length;i++){
answerArray[i]="_";
}
varremainingLetters=word.length;
Theforloopat➊createsaloopingvariableithatstartsat0andgoesupto(butdoesnotinclude)word.length.Eachtimearoundtheloop,weaddanewelementtoanswerArray,atanswerArray[i].Whentheloopfinishes,answerArraywillbethesamelengthasword.Forexample,ifwordis"monkey"(whichhassixletters),answerArraywillbe["_","_","_","_","_","_"](sixunderscores).Finally,wecreatethevariableremainingLettersandsetittothelengthofthesecretword.We’llusethisvariabletokeeptrackofhowmanylettersarelefttobeguessed.Everytimetheplayerguessesacorrectletter,thisvaluewillbedecremented(reduced)by1foreachinstanceofthatletterintheword.
CodingtheGameLoopTheskeletonofthegamelooplookslikethis:
while(remainingLetters>0){
//Gamecodegoeshere
//Showtheplayertheirprogress
//Takeinputfromtheplayer
//UpdateanswerArrayandremainingLettersforeverycorrectguess
}
Weuseawhileloop,whichwillkeeploopingaslongasremainingLetters>0remainstrue.ThebodyoftheloopwillhavetoupdateremainingLettersforeverycorrectguesstheplayermakes.Oncetheplayerhasguessedalltheletters,remainingLetterswillbe0andtheloopwillend.
Thefollowingsectionsexplainthecodethatwillmakeupthebodyofthegameloop.
ShowingthePlayer’sProgressThefirstthingweneedtodoinsidethegameloopistoshowtheplayertheircurrentprogress:
alert(answerArray.join(""));
WedothatbyjoiningtheelementsofanswerArrayintoastring,usingthespacecharacterastheseparator,andthenusingalerttoshowthatstringtotheplayer.Forexample,let’ssaythewordismonkeyandtheplayerhasguessedm,o,andesofar.Theanswerarraywouldlooklikethis["m","o","_","_","e","_"],andanswerArray.join("")wouldbe"mo__e_".ThealertdialogwouldthenlooklikeFigure7-4.
Figure7-4.Showingtheplayer’sprogressusingalert
HandlingthePlayer’sInputNowwehavetogetaguessfromtheplayerandensurethatit’sasinglecharacter.
➊varguess=prompt("Guessaletter,orclickCanceltostopplaying.");
➋if(guess===null){
break;
➌}elseif(guess.length!==1){
alert("Pleaseenterasingleletter.");
}else{
➍//Updatethegamestatewiththeguess
}
At➊,prompttakesaguessfromtheplayerandsavesittothevariableguess.Oneoffourthingswillhappenatthispoint.First,iftheplayerclickstheCancelbutton,thenguesswillbenull.Wecheckforthisconditionat➋withif(guess===null).Ifthisconditionistrue,weusebreaktoexittheloop.
NOTE
Youcanusethebreakkeywordinanylooptoimmediatelystoplooping,nomatterwheretheprogramisinthelooporwhetherthewhileconditioniscurrentlytrue.
Thesecondandthirdpossibilitiesarethattheplayerenterseithernothingortoomanyletters.IftheyenternothingbutclickOK,guesswillbetheemptystring"".Inthiscase,guess.lengthwillbe0.Iftheyenteranythingmorethanoneletter,guess.lengthwillbegreaterthan1.At➌,weuseelseif(guess.length!==1)tocheckfortheseconditions,ensuringthatguessisexactlyoneletter.Ifit’snot,wedisplayanalertsaying,“Pleaseenterasingleletter.”Thefourthpossibilityisthattheplayerentersavalidguessofoneletter.Thenwehavetoupdatethegamestatewiththeirguessusingtheelsestatementat➍,whichwe’lldointhenextsection.
UpdatingtheGameStateOncetheplayerhasenteredavalidguess,wemustupdatethegame’sanswerArrayaccordingtotheguess.Todothat,weaddthefollowingcodetotheelsestatement:
➊for(varj=0;j<word.length;j++){
➋if(word[j]===guess){
answerArray[j]=guess;
➌remainingLetters--;
}
}
At➊,wecreateaforloopwithanewloopingvariablecalledj,whichrunsfrom0uptoword.length.(We’reusingjasthevariableinthisloopbecausewealreadyusediinthepreviousforloop.)Weusethislooptostepthrougheachletterofword.Forexample,let’ssaywordispancake.Thefirsttimearoundthisloop,whenjis0,word[j]willbe"p".Thenexttime,word[j]willbe"a",then"n","c","a","k",andfinally"e".At➋,weuseif(word[j]===guess)tocheckwhetherthecurrentletterwe’relookingatmatchestheplayer’sguess.Ifitdoes,weuseanswerArray[j]=guesstoupdatetheanswerarraywiththecurrentguess.Foreachletterinthewordthatmatchesguess,weupdatetheanswerarrayatthecorrespondingpoint.ThisworksbecausetheloopingvariablejcanbeusedasanindexforanswerArrayjustasitcanbeusedasanindexforword,asyoucanseeinFigure7-5.
Figure7-5.ThesameindexcanbeusedforbothwordandanswerArray.
Forexample,imaginewe’vejuststartedplayingthegameandwereachtheforloopat➊.Let’ssaywordis"pancake",guessis"a",andanswerArraycurrentlylookslikethis:
["_","_","_","_","_","_","_"]
Thefirsttimearoundtheforloopat➊,jis0,soword[j]is"p".Ourguessis"a",soweskiptheifstatementat➋(because"p"==="a"isfalse).Thesecondtimearound,jis1,soword[j]is"a".Thisisequaltoguess,soweentertheifpartofthestatement.ThelineanswerArray[j]=guess;setstheelementatindex1(thesecondelement)ofanswerArraytoguess,soanswerArraynowlookslikethis:
["_","a","_","_","_","_","_"]
Thenexttwotimesaroundtheloop,word[j]is"n"andthen"c",whichdon’tmatchguess.However,whenjreaches4,word[j]is"a"again.WeupdateanswerArrayagain,thistimesettingtheelementatindex4(thefifthelement)toguess.NowanswerArraylookslikethis:
["_","a","_","_","a","_","_"]
Theremaininglettersdon’tmatch"a",sonothinghappensthelasttwotimesaroundtheloop.Attheendofthisloop,answerArraywillbeupdatedwithalltheoccurrencesofguessinword.Foreverycorrectguess,inadditiontoupdatinganswerArray,wealsoneedtodecrementremainingLettersby1.Wedothisat➌usingremainingLetters--;.Everytimeguessmatchesaletterinword,remainingLettersdecreasesby1.Oncetheplayerhasguessedalltheletterscorrectly,remainingLetterswillbe0.
EndingtheGameAswe’vealreadyseen,themaingameloopconditionisremainingLetters>0,soaslongastherearestillletterstoguess,theloopwillkeeplooping.OnceremainingLettersreaches0,weleavetheloop.Weendwiththefollowingcode:
alert(answerArray.join(""));
alert("Goodjob!Theanswerwas"+word);
Thefirstlineusesalerttoshowtheanswerarrayonelasttime.Thesecondlineusesalertagaintocongratulatethewinningplayer.
TheGameCodeNowwe’veseenallthecodeforthegame,andwejustneedtoputittogether.WhatfollowsisthefulllistingforourHangmangame.I’veaddedcommentsthroughouttomakeiteasierforyoutoseewhat’shappeningateachpoint.It’squiteabitlongerthananyofthecodewe’vewrittensofar,buttypingitoutwillhelpyoutobecomemorefamiliarwithwritingJavaScript.CreateanewHTMLfilecalledhangman.htmlandtypethefollowingintoit:
<!DOCTYPEhtml>
<html>
<head>
<title>Hangman!</title>
</head>
<body>
<h1>Hangman!</h1>
<script>
//Createanarrayofwords
varwords=[
"javascript",
"monkey",
"amazing",
"pancake"
];
//Pickarandomword
varword=words[Math.floor(Math.random()*words.length)];
//Setuptheanswerarray
varanswerArray=[];
for(vari=0;i<word.length;i++){
answerArray[i]="_";
}
varremainingLetters=word.length;
//Thegameloop
while(remainingLetters>0){
//Showtheplayertheirprogress
alert(answerArray.join(""));
//Getaguessfromtheplayer
varguess=prompt("Guessaletter,orclickCanceltostop
playing.");
if(guess===null){
//Exitthegameloop
break;
}elseif(guess.length!==1){
alert("Pleaseenterasingleletter.");
}else{
//Updatethegamestatewiththeguess
for(varj=0;j<word.length;j++){
if(word[j]===guess){
answerArray[j]=guess;
remainingLetters--;
}
}
}
//Theendofthegameloop
}
//Showtheanswerandcongratulatetheplayer
alert(answerArray.join(""));
alert("Goodjob!Theanswerwas"+word);
</script>
</body>
</html>
Ifthegamedoesn’trun,makesurethatyoutypedineverythingcorrectly.Ifyoumakeamistake,theJavaScriptconsolecanhelpyoufindit.Forexample,ifyoumisspellavariablename,you’llseesomethinglikeFigure7-6withapointertowhereyoumadeyourmistake.
Figure7-6.AJavaScripterrorintheChromeconsole
Ifyouclickhangman.html:30,you’llseetheexactlinewheretheerroris.Inthiscase,it’sshowingusthatwemisspelledremainingLettersasremainingLetteratthestartofthewhileloop.Tryplayingthegameafewtimes.Doesitworkthewayyouexpectedittowork?Canyouimaginethecodeyouwroterunninginthebackgroundasyouplayit?
WhatYouLearnedInjustafewpages,you’vecreatedyourfirstJavaScriptgame!Asyoucansee,loopsandconditionalsareessentialforcreatinggamesoranyotherinteractivecomputerprogram.Withoutthesecontrolstructures,aprogramjustbeginsandends.InChapter8,we’llusefunctionstopackageupcodesoyoucanrunitfromdifferentpartsofyourprograms.
ProgrammingChallengesHerearesomechallengestobuildonandimprovetheHangmangameyoucreatedinthischapter.#1:MOREWORDSAddyourownwordstothewordsarray.Remembertoenterwordsinalllowercase.#2:CAPITALLETTERSIfaplayerguessesacapitalletter,itwon’tmatchalowercaseletterinthesecretword.Toaddressthispotentialproblem,converttheplayer’sguesstolowercase.(Hint:YoucanusethetoLowerCasemethodtoconvertastringtolowercase.)#3:LIMITINGGUESSESOurHangmangamegivesaplayerunlimitedguesses.Addavariabletotrackthenumberofguessesandendthegameiftheplayerrunsoutofguesses.(Hint:CheckthisvariableinthesamewhileloopthatcheckswhetherremainingLetters>0.AswedidinChapter2,youcanuse&&tocheckwhethertwoBooleanconditionsaretrue.)#4:FIXINGABUGThere’sabuginthegame:ifyoukeepguessingthesamecorrectletter,remainingLetterswillkeepdecrementing.Canyoufixit?(Hint:YoucouldaddanotherconditiontocheckwhetheravalueinanswerArrayisstillanunderscore.Ifit’snotanunderscore,thenthatlettermusthavebeenguessedalready.)
Chapter8.FunctionsAfunctionisawaytobundlecodesothatitcanbereused.Functionsallowustorunthesamepieceofcodefrommultipleplacesinaprogramwithouthavingtocopyandpastethecoderepeatedly.Also,byhidinglongbitsofcodeinafunctionandgivingitaneasy-to-understandname,you’llbebetterabletoplanoutyourcodebecauseyoucanfocusonorganizingyourfunctionsratherthanallofthelittlecodedetailsthatmakethemup.Splittingupyourcodeintosmaller,moremanageablepiecesallowsyoutoseethebiggerpictureandthinkabouthowyourprogramsarestructuredatahigherlevel.You’llfindfunctionsreallyusefulwhenyouneedtorepeatedlyperformacalculationoractionthroughoutaprogram.Earlierinthebook,youusedvariousfunctionssuchasMath.random,Math.floor,alert,prompt,andconfirm.Inthischapter,you’lllearnhowtocreateyourownfunctions.
TheBasicAnatomyofaFunctionFigure8-1showshowafunctionisbuilt.Thecodebetweenthecurlybracketsiscalledthefunctionbody,justasthecodebetweenthecurlybracketsinaloopiscalledtheloopbody.
Figure8-1.Thesyntaxforcreatingafunction
CreatingaSimpleFunctionLet’screateasimplefunctionthatprintsHelloworld!.Enterthefollowingcodeinthebrowserconsole.UseSHIFT-ENTERtostarteachnewlinewithoutexecutingthecode.
varourFirstFunction=function(){
console.log("Helloworld!");
};
ThiscodecreatesanewfunctionandsavesitinthevariableourFirstFunction.
CallingaFunctionTorunthecodeinsideafunction(thefunctionbody),weneedtocallthefunction.Tocallafunction,youenteritsnamefollowedbyapairofopeningandclosingparentheses,asshownhere.
ourFirstFunction();
Helloworld!
CallingourFirstFunctionexecutesthebodyofthefunction,whichisconsole.log("Helloworld!");,andthetextweaskedtobeprintedisdisplayedonthenextline:Helloworld!.Butifyoucallthisfunctioninyourbrowser,you’llnoticethatthere’sathirdline,withalittleleft-facingarrow,asshowninFigure8-2.Thisisthereturnvalueofthefunction.
Figure8-2.Callingafunctionwithanundefinedreturnvalue
Areturnvalueisthevaluethatafunctionoutputs,whichcanthenbeusedelsewhereinyourcode.Inthiscase,thereturnvalueisundefinedbecausewedidn’ttellthefunctiontoreturnanyparticularvalueinthebodyofthefunction.Allwedidwasaskittoprintamessagetotheconsole,whichisnotthesameasreturningavalue.Afunctionalwaysreturnsundefinedunlessthereissomethinginthefunctionbodythattellsittoreturnadifferentvalue.(We’lllookathowtospecifyareturnvalueinReturningValuesfromFunctions.)
NOTE
IntheChromeconsoleandinthecodelistingsthroughoutthisbook,returnvaluesarealwayscolor-codedbasedondatatype,whiletextprintedwithconsole.logisalwaysplainblack.
PassingArgumentsintoFunctionsourFirstFunctionjustprintsthesamelineoftexteverytimeyoucallit,butyou’llprobablywantyourfunctionstobemoreflexiblethanthat.Functionargumentsallowustopassvaluesintoafunctioninordertochangethefunction’sbehaviorwhenit’scalled.Argumentsalwaysgobetweenthefunctionparentheses,bothwhenyoucreatethefunctionandwhenyoucallit.ThefollowingsayHelloTofunctionusesanargument(name)tosayhellotosomeoneyouspecify.
varsayHelloTo=function(name){
console.log("Hello"+name+"!");
};
WecreatethefunctioninthefirstlineandassignittothevariablesayHelloTo.Whenthefunctioniscalled,itlogsthestring"Hello"+name+"!",replacingnamewithwhatevervalueyoupasstothefunctionasanargument.Figure8-3showsthesyntaxforafunctionwithoneargument.
Figure8-3.Thesyntaxforcreatingafunctionwithoneargument
Tocallafunctionthattakesanargument,placethevalueyou’dliketousefortheargumentbetweentheparenthesesfollowingthefunctionname.Forexample,tosayhellotoNick,youwouldwrite:
sayHelloTo("Nick");
HelloNick!
Or,tosayhellotoLyra,write:sayHelloTo("Lyra");
HelloLyra!
Eachtimewecallthefunction,theargumentwepassinfornameisincludedinthestringprintedbythefunction.Sowhenwepassin"Nick",theconsoleprints"HelloNick!",andwhenwepassin"Lyra",itprints"HelloLyra!".
PrintingCatFaces!Onereasontopassanargumentintoafunctionmightbetotellithowmanytimestodosomething.Forexample,thefunctiondrawCatsprintscatfaces(likethis:=^.^=)totheconsole.WetellthefunctionhowmanycatstoprintusingtheargumenthowManyTimes:
vardrawCats=function(howManyTimes){
for(vari=0;i<howManyTimes;i++){
console.log(i+"=^.^=");
}
};
ThebodyofthefunctionisaforloopthatloopsasmanytimesasthehowManyTimesargumenttellsitto(sincethevariableistartsat0andrepeatsuntilitincrementstohowManyTimesminus1).Eachtimethroughtheloop,thefunctionlogsthestringi+"=^.^=".Here’swhathappenswhenwecallthisfunctionwiththeargument5forhowManyTimes:
drawCats(5);
0=^.^=
1=^.^=
2=^.^=
3=^.^=
4=^.^=
TryitoutwithhowManyTimesequalto100toprint100catfaces!
PassingMultipleArgumentstoaFunctionYoucanpassmorethanonevalueintoafunctionusingmultiplearguments.Toaddanotherargument,entertheargumentsbetweentheparenthesesafterthefunctionkeyword,separatingthembycommas.Figure8-4showsthesyntaxforafunctionwithtwoarguments.
Figure8-4.Thesyntaxforcreatingafunctionwithtwoarguments
Thefollowingfunction,printMultipleTimes,islikedrawCatsexceptthatithasasecondargumentcalledwhatToDraw.
varprintMultipleTimes=function(howManyTimes,whatToDraw){
for(vari=0;i<howManyTimes;i++){
console.log(i+""+whatToDraw);
}
};
TheprintMultipleTimesfunctionprintsthestringyouenterforwhatToDrawasmanytimesasyouspecifywiththeargumenthowManyTimes.Thesecondargumenttellsthefunctionwhattoprint,andthefirstargumenttellsthefunctionhowmanytimestoprintit.
Whencallingafunctionwithmultiplearguments,insertthevaluesyouwishtousebetweentheparenthesesfollowingthefunctionname,separatedbycommas.Forexample,toprintoutcatfacesusingthisnewprintMultipleTimesfunction,you’dcallitlikethis:
printMultipleTimes(5,"=^.^=");
0=^.^=
1=^.^=
2=^.^=
3=^.^=
4=^.^=
TohaveprintMultipleTimesprintahappyfacefourtimes,youcoulddothis:printMultipleTimes(4,"^_^");
0^_^
1^_^
2^_^
3^_^
WhenwecallprintMultipleTimes,wepassinthearguments4forhowManyTimesand"^_^"forwhatToDraw.Asaresult,theforlooploopsfourtimes(withiincrementingfrom0to3),printingi+""+"^_^"eachtime.Todrawthecharacter(>_<)twotimes,youcouldwrite:
printMultipleTimes(2,"(>_<)");
0(>_<)
1(>_<)
Inthiscase,wepassin2forhowManyTimesand"(>_<)"forwhatToDraw.
ReturningValuesfromFunctionsThefunctionswe’velookedatsofarhaveallprintedtexttotheconsoleusingconsole.log.That’saneasyandusefulwaytomakeJavaScriptdisplayvalues,butwhenwelogavaluetotheconsole,wearen’tabletousethatvaluelaterintheprogram.Whatifyouwantyourfunctiontooutputthatvaluesothatyoucankeepusingitinotherpartsofyourcode?Asmentionedearlierinthischapter,theoutputofafunctioniscalledthereturnvalue.Whenyoucallafunctionthatreturnsavalue,youcanusethatvalueintherestofyourcode(youcouldsaveareturnvalueinavariable,passittoanotherfunction,orsimplycombineitwithothercode).Forexample,thefollowinglineofcodeadds5tothereturnvalueofthecalltoMath.floor(1.2345):
5+Math.floor(1.2345);
6
Math.floorisafunctionthatreturnsthenumberyoupasstoit,roundeddowntothenearestwholenumber.WhenyouseeafunctioncalllikeMath.floor(1.2345),imaginereplacingitwiththereturnvalueofthatfunctioncall,whichisthenumber1.Let’screateafunctionthatreturnsavalue.Thefunctiondoubletakestheargumentnumberandreturnstheresultofnumber*2.Inotherwords,thevaluereturnedbythisfunctionistwicethenumbersuppliedasitsargument.
vardouble=function(number){
➊returnnumber*2;
};
Toreturnavaluefromafunction,usethekeywordreturn,followedbythevalueyouwanttoreturn.At➊,weusethereturnkeywordtoreturnthevaluenumber*2fromthedoublefunction.Nowwecancallourdoublefunctiontodoublenumbers:
double(3);
6
Here,thereturnvalue(6)isshownonthesecondline.Eventhoughfunctionscantakemultiplearguments,theycanreturnonlyonevalue.Ifyoudon’ttellthefunctiontoreturnanything,itwillreturnundefined.
UsingFunctionCallsasValuesWhenyoucallafunctionfromwithinalargerpieceofcode,thefunction’sreturnvalueisusedwhereverthatfunctioncallwasplaced.Forexample,let’suseourdoublefunctiontodeterminetheresultofdoublingtwonumbersandthenaddingtheresults:
double(5)+double(6);
22
Inthisexample,wecallthedoublefunctiontwiceandaddthetworeturnvaluestogether.Youcanthinkofthecalldouble(5)asthevalue10andthecalldouble(6)asthevalue12.Youcanalsopassafunctioncallintoanotherfunctionasanargument,andthefunctioncallwillbesubstitutedwithitsreturnvalue.Inthisnextexamplewecalldouble,passingtheresultofcallingdoublewith3asanargument.Wereplacedouble(3)with6sothatdouble(double(3))simplifiestodouble(6),whichthensimplifiesto12.
double(double(3));
12
Here’showJavaScriptcalculatesthis:
Thebodyofthedoublefunctionreturnsnumber*2,soat➊wereplacedouble(3)with3*2.At➋wereplace3*2with6.Thenat➌,wedothesamethingandreplacedouble(6)with6*2.Finally,at➍,wecanreplace6*2with12.
UsingFunctionstoSimplifyCodeInChapter3,weusedthemethodsMath.randomandMath.floortopickrandomwordsfromarraysandgeneraterandominsults.Inthissection,we’llre-createourinsultgeneratorandsimplifyitbycreatingfunctions.
AFunctiontoPickaRandomWordHereisthecodeweusedinChapter3tochoosearandomwordfromanarray:
randomWords[Math.floor(Math.random()*randomWords.length)];
Ifweturnthiscodeintoafunction,wecanreuseittopickarandomwordfromanarraywithouthavingtoenterthesamecodeeachtime.Forexample,here’showwecoulddefineapickRandomWordfunction.
varpickRandomWord=function(words){
returnwords[Math.floor(Math.random()*words.length)];
};
Allwe’redoinghereiswrappingthepreviouscodeinafunction.Now,wecancreatethisrandomWordsarray...
varrandomWords=["Planet","Worm","Flower","Computer"];
andpickarandomwordfromthisarrayusingthepickRandomWordfunction,likethis:pickRandomWord(randomWords);
"Flower"
Wecanusethissamefunctiononanyarray.Forexample,here’showwewouldpickarandomnamefromanarrayofnames:
pickRandomWord(["Charlie","Raj","Nicole","Kate","Sandy"]);
"Raj"
ARandomInsultGeneratorNowlet’stryre-creatingourrandominsultgenerator,usingourfunctionthatpicksrandomwords.First,here’sareminderofwhatthecodefromChapter3lookedlike:
varrandomBodyParts=["Face","Nose","Hair"];
varrandomAdjectives=["Smelly","Boring","Stupid"];
varrandomWords=["Fly","Marmot","Stick","Monkey","Rat"];
//PickarandombodypartfromtherandomBodyPartsarray:
varrandomBodyPart=randomBodyParts[Math.floor(Math.random()*3)];
//PickarandomadjectivefromtherandomAdjectivesarray:
varrandomAdjective=randomAdjectives[Math.floor(Math.random()*3)];
//PickarandomwordfromtherandomWordsarray:
varrandomWord=randomWords[Math.floor(Math.random()*5)];
//Joinalltherandomstringsintoasentence:
varrandomString="Your"+randomBodyPart+"islikea"+
randomAdjective+""+randomWord+"!!!";
randomString;
"YourNoseislikeaStupidMarmot!!!"
Noticethatweenduprepeatingwords[Math.floor(Math.random()*length)]quiteafewtimesinthiscode.UsingourpickRandomWordfunction,wecouldrewritetheprogramlikethis:
varrandomBodyParts=["Face","Nose","Hair"];
varrandomAdjectives=["Smelly","Boring","Stupid"];
varrandomWords=["Fly","Marmot","Stick","Monkey","Rat"];
//Joinalltherandomstringsintoasentence:
varrandomString="Your"+pickRandomWord(randomBodyParts)+
"islikea"+pickRandomWord(randomAdjectives)+
""+pickRandomWord(randomWords)+"!!!";
randomString;
"YourNoseislikeaSmellyMarmot!!!"
Therearetwochangeshere.First,weusethepickRandomWordfunctionwhenweneedarandomwordfromanarray,insteadofusingwords[Math.floor(Math.random()*length)]eachtime.Also,insteadofsavingeachrandomwordinavariablebeforeaddingittothefinalstring,we’readdingthereturnvaluesfromthefunctioncallsdirectlytogethertoformthestring.Acalltoafunctioncanbetreatedasthevaluethatthefunctionreturns.Soreally,allwe’redoinghereisaddingtogetherstrings.Asyoucansee,thisversionoftheprogramisaloteasiertoread,anditwaseasiertowritetoo,sincewereusedsomecodebyusingafunction.
MakingtheRandomInsultGeneratorintoaFunctionWecantakeourrandominsultgeneratoronestepfurtherbycreatingalargerfunctionthatproducesrandominsults.Let’stakealook:
generateRandomInsult=function(){
varrandomBodyParts=["Face","Nose","Hair"];
varrandomAdjectives=["Smelly","Boring","Stupid"];
varrandomWords=["Fly","Marmot","Stick","Monkey","Rat"];
//Joinalltherandomstringsintoasentence:
varrandomString="Your"+pickRandomWord(randomBodyParts)+
"islikea"+pickRandomWord(randomAdjectives)+
""+pickRandomWord(randomWords)+"!!!";
➊returnrandomString;
};
generateRandomInsult();
"YourFaceislikeaSmellyStick!!!"
generateRandomInsult();
"YourHairislikeaBoringStick!!!"
generateRandomInsult();
"YourFaceislikeaStupidFly!!!"
OurnewgenerateRandomInsultfunctionisjustthecodefrombeforeplacedinsideafunctionwithnoarguments.Theonlyadditionisat➊,wherewehavethefunctionreturnrandomStringattheend.Youcanseeafewsamplerunsoftheprecedingfunction,anditreturnsanewinsultstringeachtime.Havingthecodeinonefunctionmeanswecankeepcallingthatfunctiontogetarandominsult,insteadofhavingtocopyandpastethesamecodeeverytimewewantanewinsult.
LeavingaFunctionEarlywithreturnAssoonastheJavaScriptinterpreterreachesreturninafunction,itleavesthefunction,evenifmorecoderemainsinthefunctionbody.Onecommonwaytousereturnistoleaveafunctionearlyifanyoftheargumentstothefunctionareinvalid;thatis,ifthey’renotthekindofargumentsthefunctionneedsinordertorunproperly.Forexample,thefollowingfunctionreturnsastringtellingyouthefifthcharacterofyourname.Ifthenamepassedtothefunctionhasfewerthanfivecharacters,thefunctionusesreturntoleavethefunctionimmediately.Thismeansthereturnstatementattheend,whichtellsyouthefifthletterofyourname,isneverexecuted.
varfifthLetter=function(name){
➊if(name.length<5){
➋return;
}
return"Thefifthletterofyournameis"+name[4]+".";
};
At➊wechecktoseewhetherthelengthoftheinputnameislessthanfive.Ifitis,weusereturnat➋toexitthefunctionearly.Let’strycallingthisfunction.
fifthLetter("Nicholas");
"Thefifthletterofyournameiso."
ThenameNicholasislongerthanfivecharacters,sofifthLettercompletesandreturnsthefifthletterinthenameNicholas,whichisthelettero.Let’strycallingitagainonashortername:
fifthLetter("Nick");
undefined
WhenwecallfifthLetterwiththenameNick,thefunctionknowsthatthenameisn’tlongenough,soitexitsearlywiththefirstreturnstatementat➋.Becausethereisnovaluespecifiedafterthereturnat➋,thefunctionreturnsundefined.
UsingreturnMultipleTimesInsteadofif...elseStatementsWecanusemultiplereturnkeywordsinsidedifferentifstatementsinafunctionbodytohaveafunctionreturnadifferentvaluedependingontheinput.Forexample,sayyou’rewritingagamethatawardsplayersmedalsbasedontheirscore.Ascoreof3orbelowisabronzemedal,scoresbetween3and7aresilver,andanythingabove7isgold.YoucoulduseafunctionlikemedalForScoretoevaluateascoreandreturntherightkindofmedal,asshownhere:
varmedalForScore=function(score){
if(score<3){
➊return"Bronze";
}
➋if(score<7){
return"Silver";
}
➌return"Gold";
};
At➊wereturn"Bronze"andexitthefunctionifthescoreislessthan3.Ifwereach➋weknowthatscoremustbeatleast3,becauseifitwaslessthan3,wewouldhavereturnedalready(thatis,wewouldhaveexitedthefunctionwhenwereachedthereturnkeywordinthefirsttest).Finally,ifwereach➌,weknowthatscoremustbeatleast7,sothere’snothinglefttocheck,andwecanjustreturn"Gold".Althoughwe’recheckingmultipleconditions,wedon’tneedtousechainedif...elsestatements.Weuseif...elsestatementstoensurethatonlyoneoftheoptionsisexecuted.Wheneachoftheoptionshasitsownreturnstatement,thisalsoensuresthatonlyoneoftheoptionswillbeexecuted(becausefunctionscanreturnonlyonce).
SHORTHANDFORCREATINGFUNCTIONS
There’salonghandwayandashorthandwaytowritefunctions.I’musingthelonghandwaybecauseitshowsmoreclearlyhowafunctionisstoredasavariable.Still,youshouldknowwhattheshorthandlookslikebecauselotsofJavaScriptcodeusesit.Onceyou’reusedtohowfunctionswork,youmightwanttousetheshorthandversion,too.
Here’sanexampleofalonghandfunction:vardouble=function(number){
returnnumber*2;
};
Theshorthandversionlookslikethis:functiondouble(number){
returnnumber*2;
}
Asyoucansee,inthelonghandversion,weexplicitlycreateavariablenameandassignthefunctiontothevariable,sodoubleappearsbeforethefunctionkeyword.Bycontrast,thefunctionkeywordappearsfirstintheshorthandversion,followedbythefunctionname.Inthisversion,thevariabledoubleiscreatedbyJavaScriptbehindthescenes.
Intechnicalterms,thelonghandversionisknownasafunctionexpression.Theshorthandversionisknownasafunctiondeclaration.
WhatYouLearnedFunctionsallowustoreuseblocksofcode.Theycandodifferentthingsdependingontheargumentspassedtothem,andtheycanreturnvaluestothelocationinthecodewherethefunctionwascalled.Functionsalsomakeitpossibletogiveapieceofcodeameaningfulname.Forexample,thenameofthefunctionpickRandomWordmakesclearthatthefunctionhassomethingtodowithpickingarandomword.Inthenextchapter,we’lllearnhowtowriteJavaScriptthatcanmanipulateHTMLdocuments.
ProgrammingChallengesHerearesomechallengesforyoutopracticeworkingwithfunctions.#1:DOINGARITHMETICWITHFUNCTIONSCreatetwofunctions,addandmultiply.Eachshouldtaketwoarguments.Theaddfunctionshouldsumitsargumentsandreturntheresult,andmultiplyshouldmultiplyitsarguments.Usingonlythesetwofunctions,solvethissimplemathematicalproblem:
36325*9824+777
#2:ARETHESEARRAYSTHESAME?WriteafunctioncalledareArraysSamethattakestwoarraysofnumbersasarguments.Itshouldreturntrueifthetwoarraysarethesame(thatis,theyhavethesamenumbersinthesameorder)andfalseifthey’redifferent.Tryrunningthefollowingcodetomakesureyourfunctionsareworkingcorrectly:
areArraysSame([1,2,3],[4,5,6]);
false
areArraysSame([1,2,3],[1,2,3]);
true
areArraysSame([1,2,3],[1,2,3,4]);
false
Hint1:you’llneedtouseaforlooptogothrougheachofthevaluesinthefirstarraytoseewhetherthey’rethesameinthesecondarray.Youcanreturnfalseintheforloopifyoufindavaluethat’snotequal.Hint2:youcanleavethefunctionearlyandskiptheforloopaltogetherifthearraysaredifferentlengths.#3:HANGMAN,USINGFUNCTIONSGobacktoyourHangmangamefromChapter7.We’regoingtorewriteitusingfunctions.I’verewrittenthefinalHangmancodehere,butwithcertainpartsofthecodereplacedbyfunctioncalls.Allyouneedtodoiswritethefunctions!
//Writeyourfunctionshere
varword=pickWord();
varanswerArray=setupAnswerArray(word);
varremainingLetters=word.length;
while(remainingLetters>0){
showPlayerProgress(answerArray);
varguess=getGuess();
if(guess===null){
break;
}elseif(guess.length!==1){
alert("Pleaseenterasingleletter.");
}else{
varcorrectGuesses=updateGameState(guess,word,answerArray);
remainingLetters-=correctGuesses;
}
}
showAnswerAndCongratulatePlayer(answerArray);
ThisversionofthecodeusingfunctionsisalmostassimpleasthepseudocodeversionfromChapter7.Thisshouldgiveyousomeideaofhowusefulfunctionscanbeformakingcodeeasiertounderstand.Herearethefunctionsyouneedtofillin:
varpickWord=function(){
//Returnarandomword
};
varsetupAnswerArray=function(word){
//Returntheanswerarray
};
varshowPlayerProgress=function(answerArray){
//Usealerttoshowtheplayertheirprogress
};
vargetGuess=function(){
//Useprompttogetaguess
};
varupdateGameState=function(guess,word,answerArray){
//UpdateanswerArrayandreturnanumbershowinghowmany
//timestheguessappearsinthewordsoremainingLetters
//canbeupdated
};
varshowAnswerAndCongratulatePlayer=function(answerArray){
//Usealerttoshowtheanswerandcongratulatetheplayer
};
PartII.AdvancedJavaScript
Chapter9.TheDOMandjQuerySofar,we’vebeenusingJavaScripttodorelativelysimplethingslikeprinttexttothebrowserconsoleordisplayanalertorpromptdialog.ButyoucanalsouseJavaScripttomanipulate(controlormodify)andinteractwiththeHTMLyouwriteinwebpages.Inthischapter,we’lldiscusstwotoolsthatwillallowyoutowritemuchmorepowerfulJavaScript:theDOMandjQuery.TheDOM,ordocumentobjectmodel,iswhatallowsJavaScripttoaccessthecontentofawebpage.WebbrowsersusetheDOMtokeeptrackoftheelementsonapage(suchasparagraphs,headings,andotherHTMLelements),andJavaScriptcanmanipulateDOMelementsinvariousways.Forexample,you’llsoonseehowyoucanuseJavaScripttoreplacethemainheadingoftheHTMLdocumentwithinputfromapromptdialog.
We’llalsolookatausefultoolcalledjQuery,whichmakesitmucheasiertoworkwiththeDOM.jQuerygivesusasetoffunctionsthatwecanusetochoosewhichelementstoworkwithandtomakechangestothoseelements.Inthischapter,we’lllearnhowtousetheDOMandjQuerytoeditexistingDOMelementsandcreatenewDOMelements,givingusfullcontroloverthecontentofourwebpagesfromJavaScript.We’llalsolearnhowtousejQuerytoanimateDOMelements—forexample,fadingelementsinandout.
SelectingDOMElementsWhenyouloadanHTMLdocumentintoabrowser,thebrowserconvertstheelementsintoatree-likestructure.ThistreeisknownastheDOMtree.Figure9-1showsasimpleDOMtree—thesametreeweusedinChapter5toillustratethehierarchyofHTML.ThebrowsergivesJavaScriptprogrammersawaytoaccessandmodifythistreestructureusingacollectionofmethodscalledtheDOM.
Figure9-1.TheDOMtreeforasimpleHTMLdocument,liketheonewemadeinChapter5
UsingidtoIdentifyElementsTheHTMLidattributeletsyouassignauniquename,oridentifier,toanHTMLelement.Forexample,thish1elementhasanidattribute:
<h1id="main-heading">Helloworld!</h1>
Inthisexample,theidof"main-heading"willletusidentify,andeventuallychange,thisparticularheadingwithoutaffectingotherelementsorevenotherh1headings.
SelectinganElementUsinggetElementByIdHavinguniquelyidentifiedanelementwithid(eachidmusthaveauniquevalue),wecanusetheDOMmethoddocument.getElementByIdtoreturnthe"main-heading"element:
varheadingElement=document.getElementById("main-heading");
Bycallingdocument.getElementById("main-heading"),wetellthebrowsertolookfortheelementwiththeidof"main-heading".ThiscallreturnsaDOMobjectthatcorrespondstotheid,andwesavethisDOMobjecttothevariableheadingElement.Oncewe’veselectedanelement,wecanmanipulateitwithJavaScript.Forexample,wecanusetheinnerHTMLpropertytoretrieveandreplacethetextinsidetheselectedelement:
headingElement.innerHTML;
ThiscodereturnstheHTMLcontentsofheadingElement—theelementweselectedusinggetElementById.Inthiscase,thecontentofthiselementisthetextHelloworld!thatweenteredbetweenthe<h1>tags.
ReplacingtheHeadingTextUsingtheDOMHere’sanexampleofhowtoreplaceheadingtextusingtheDOM.First,wecreateanewHTMLdocumentcalleddom.htmlcontainingthiscode:
<!DOCTYPEhtml>
<html>
<head>
<title>PlayingwiththeDOM</title>
</head>
<body>
<h1id="main-heading">Helloworld!</h1>
<script>
➊varheadingElement=document.getElementById("main-heading");
➋console.log(headingElement.innerHTML);
➌varnewHeadingText=prompt("Pleaseprovideanewheading:");
➍headingElement.innerHTML=newHeadingText;
</script>
</body>
</html>
At➊weusedocument.getElementByIdtogettheh1element(withtheidof"main-heading")andsaveitintothevariableheadingElement.At➋weprintthestringreturnedbyheadingElement.innerHTML,whichprintsHelloworld!totheconsole.At➌weuseapromptdialogtoasktheuserforanewheadingandsavethetexttheuserentersinthevariablenewHeadingText.Finally,at➍wesettheinnerHTMLpropertyofheadingElementtothetextsavedinnewHeadingText.
Whenyouloadthispage,youshouldseeapromptdialogliketheoneshowninFigure9-2.
Figure9-2.Ourpagewiththedialogopen
EnterthetextJAVASCRIPTISAWESOMEintothedialogandclickOK.Theheadingshouldupdateinstantlywiththenewtext,asshowninFigure9-3.
Figure9-3.Ourpageaftertheheadingchange
UsingtheinnerHTMLproperty,wecanchangethecontentofanyDOMelementusingJavaScript.
UsingjQuerytoWorkwiththeDOMTreeThebuilt-inDOMmethodsaregreat,butthey’renotveryeasytouse.Becauseofthis,manydevelopersuseasetoftoolscalledjQuerytoaccessandmanipulatetheDOMtree.jQueryisaJavaScriptlibrary—acollectionofrelatedtools(mostlyfunctions)thatgivesus,inthiscase,asimplerwaytoworkwithDOMelements.Onceweloadalibraryontoourpage,wecanuseitsfunctionsandmethodsinadditiontothosebuiltintoJavaScriptandthoseprovidedbythebrowser.
LoadingjQueryonYourHTMLPageTousethejQuerylibrary,wefirsttellthebrowsertoloaditwiththislineofHTML:
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
Noticethatthe<script>tagherehasnocontents,andithasasrcattribute.ThesrcattributeletsusinsertaJavaScriptfileintoourpagebyincludingitsURL(webaddress).Inthiscase,https://code.jquery.com/jquery-2.1.0.jsistheURLforaspecificversionofjQuery(version2.1.0)onthejQuerywebsite.ToseethejQuerylibrary,visitthatURL;you’llseetheJavaScriptthatwillbeloadedwhenthis<script>tagisadded.Theentirelibraryisover9,000linesofcomplicatedJavaScript,though,sodon’texpecttounderstanditallrightnow!
ReplacingtheHeadingTextUsingjQueryInReplacingtheHeadingTextUsingtheDOM,youlearnedhowtoreplacetextusingthebuilt-inDOMmethods.Inthissection,we’llupdatethatcodetousejQuerytoreplacetheheadingtextinstead.Opendom.htmlandmakethechangesshown.
<!DOCTYPEhtml>
<html>
<head>
<title>PlayingwiththeDOM</title>
</head>
<body>
<h1id="main-heading">Helloworld!</h1>
➊<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
varnewHeadingText=prompt("Pleaseprovideanewheading:");
➋$("#main-heading").text(newHeadingText);
</script>
</body>
</html>
At➊weaddanew<script>tagtothepagetoloadjQuery.WithjQueryloaded,weusethejQueryfunction$toselectanHTMLelement.The$functiontakesoneargument,calledaselectorstring,whichtellsjQuerywhichelementorelementstoselectfromtheDOMtree.Inthiscase,weentered"#main-heading"astheargument.The#characterinaselectorstringmeans“ID,”soourselectorstring"#main-heading"means“theelementwithanidofmain-heading.”The$functionreturnsajQueryobjectthatrepresentstheelementsyouselected.Forexample,$("#main-heading")returnsajQueryobjectfortheh1element(whichhasanidof"main-heading").WenowhaveajQueryobjectrepresentingtheh1element.WecanmodifyitstextbycallingthetextmethodonthejQueryobjectat➋,passinginthenewtextforthatelement,andreplacingthetextoftheheadingwiththeuserinputsavedtothevariablenewHeadingText.Asbefore,whenyouloadthispage,adialogshouldpromptyoutoenterreplacementtextfortheoldtextintheh1element.
CreatingNewElementswithjQueryInadditiontomanipulatingelementswithjQuery,wecanalsousejQuerytocreatenewelementsandaddthemtotheDOMtree.Todoso,wecallappendonajQueryobjectwithastringcontainingHTML.TheappendmethodconvertsthestringtoaDOMelement(usingtheHTMLtagsinthestring)andaddsthenewelementtotheendoftheoriginalone.Forexample,toaddapelementtotheendofthepage,wecouldaddthistoourJavaScript:
$("body").append("<p>Thisisanewparagraph</p>");
Thefirstpartofthisstatementusesthe$functionwiththeselectorstring"body"toselectthebodyofourHTMLdocument.Theselectorstringdoesn’thavetobeanid.Thecode$("body")selectsthebodyelement.Likewise,wecouldusethecode$("p")toselectallthepelements.Next,wecalltheappendmethodontheobjectreturnedby$("body").ThestringpassedtoappendisturnedintoaDOMelement,anditisaddedinsidethebodyelement,justbeforetheclosingtag.Figure9-4showswhatourrevisedpagewouldlooklike.
Figure9-4.Ourdocumentwithanewelement
Wecouldalsouseappendtoaddmultipleelementsinaforlooplikethis:for(vari=0;i<3;i++){
varhobby=prompt("Tellmeoneofyourhobbies!");
$("body").append("<p>"+hobby+"</p>");
}
Thisloopsthreetimes.Eachtimethroughaloop,apromptappears,askinguserstoenteroneoftheirhobbies.Eachhobbyisthenputinsideasetof<p>tagsandpassedtotheappendmethod,whichaddsthehobbytotheendofthebodyelement.Tryaddingthiscodetoyourdom.htmldocument,andthenloaditinabrowsertotestit.ItshouldlooklikeFigure9-5.
Figure9-5.Extraelementsaddedinaloop
AnimatingElementswithjQueryLotsofwebsitesuseanimationstoshowandhidecontent.Forexample,ifyouwereaddinganewparagraphoftexttoyourpage,youmightwanttofadeitinslowlysoitdoesn’tappearallofasudden.jQuerymakesiteasytoanimateelements.Forexample,tofadeanelementout,wecanusethefadeOutmethod.Totestthismethod,replacethecontentsofthesecondscriptelementindom.htmlwiththis:
$("h1").fadeOut(3000);
Weusethe$functiontoselectallh1elements.Becausedom.htmlhasonlyoneh1element(theheadingcontainingthetextHelloworld!),thatheadingisselectedasajQueryobject.Bycalling.fadeOut(3000)onthisjQueryobject,wemaketheheadingfadeawayuntilitdisappears,overthecourseof3seconds.(TheargumenttofadeOutisinmilliseconds,orthousandthsofasecond,soentering3000makestheanimationlast3seconds.)Assoonasyouloadthepagewiththiscode,theh1elementshouldstarttofadeaway.
ChainingjQueryAnimationsWhenyoucallamethodonajQueryobject,themethodusuallyreturnstheoriginalobjectthatitwascalledon.Forexample,$("h1")returnsajQueryobjectrepresentingallh1elements,and$("h1").fadeOut(3000)returnsthesamejQueryobjectrepresentingallh1elements.Tochangethetextoftheh1elementandfadeitout,youcouldenter:
$("h1").text("Thiswillfadeout").fadeOut(3000);
Callingmultiplemethodsinarowlikethisisknownaschaining.Wecanchainmultipleanimationsonthesameelement.Forexample,here’showwecouldchainacalltothefadeOutandfadeInmethodstofadeanelementoutandthenimmediatelyfadeitinagain:
$("h1").fadeOut(3000).fadeIn(2000);
ThefadeInanimationmakesaninvisibleelementfadebackin.jQueryissmartenoughtoknowthatwhenyouchaintwoanimationsinarowlikethis,youprobablywantthemtohappenoneaftertheother.Therefore,thiscodefadestheh1elementoutoverthecourseof3secondsandthenfadesitbackinover2seconds.jQueryprovidestwoadditionalanimationmethodssimilartofadeOutandfadeIn,calledslideUpandslideDown.TheslideUpmethodmakeselementsdisappearbyslidingthemup,andslideDownmakesthemreappearbyslidingthemdown.Replacethesecondscriptelementinthedom.htmldocumentwiththefollowing,andreloadthepagetotryitout:
$("h1").slideUp(1000).slideDown(1000);
Hereweselecttheh1element,slideitupover1second,andthenslideitdownover1seconduntilitreappears.
TRYITOUT!
WeusefadeIntomakeinvisibleelementsvisible.ButwhathappensifyoucallfadeInonanelementthat’salreadyvisibleoranelementthatcomesaftertheelementyou’reanimating?
Forexample,sayyouaddanewpelementtoyourdom.htmldocumentaftertheheading.TryusingslideUpandslideDowntohideandshowtheh1element,andseewhathappenstothepelement.WhatifyouusefadeOutandfadeIn?
WhathappensifyoucallfadeOutandfadeInonthesameelementwithoutchainingthecalls?Forexample:$("h1").fadeOut(1000);
$("h1").fadeIn(1000);
Tryaddingtheprecedingcodeinsideaforloopsettorunfivetimes.Whathappens?
WhatdoyouthinktheshowandhidejQuerymethodsdo?Trythemouttoseeifyou’reright.Howcouldyouusehidetofadeinanelementthat’salreadyvisible?
WhatYouLearnedInthischapter,youlearnedhowtoupdateHTMLpagesusingJavaScriptbymanipulatingDOMelements.Asyou’veseen,jQuerygivesusevenmorepowerfulwaystoselectelementsandchangeorevenanimatethem.YoualsolearnedanewHTMLattribute,id,whichallowsyoutogiveanelementauniqueidentifier.Inthenextchapter,you’lllearnhowtocontrolwhenyourJavaScriptisrun—forexample,onceatimerhasrunoutorwhenyouclickabutton.We’llalsolookathowtorunthesamepieceofcodemultipletimeswithatimedelayinbetween—forexample,updatingaclockonceeverysecond.
ProgrammingChallengesTrythesechallengestopracticemorethingsyoucandowithjQueryandDOMelements.#1:LISTINGYOURFRIENDSWITHJQUERY(ANDMAKINGTHEMSMELL!)Createanarraycontainingthenamesofafewfriends.Usingaforloop,createapelementforeachofyourfriendsandaddittotheendofthebodyelementusingthejQueryappendmethod.UsejQuerytochangetheh1elementsoitsaysMyfriendsinsteadofHelloworld!.UsethehidemethodfollowedbythefadeInmethodtofadeineachnameasit’sprovided.Now,modifythepelementsyoucreatedtoaddthetextsmells!aftereachfriend.Hint:Ifyouselectthepelementsusing$("p"),theappendmethodwillapplytoallthepelements.#2:MAKINGAHEADINGFLASHHowcouldyouusefadeOutandfadeIntocausetheheadingtoflashfivetimes,onceasecond?Howcouldyoudothisusingaforloop?Trymodifyingyourloopsoitfadesoutandfadesinover1secondthefirsttime,over2secondsthesecondtime,over3secondsthethirdtime,andsoon.#3:DELAYINGANIMATIONSThedelaymethodcanbeusedtodelayanimations.Usingdelay,fadeOut,andfadeIn,makeanelementonyourpagefadeoutandthenfadebackinagainafter5seconds.#4:USINGFADETOTryusingthefadeTomethod.Itsfirstargumentisanumberofmilliseconds,asinalltheotheranimationmethods.Itssecondargumentisanumberbetween0and1.Whathappenswhenyourunthefollowingcode?
$("h1").fadeTo(2000,0.5);
Whatdoyouthinkthesecondargumentmeans?Tryusingdifferentvaluesbetween0and1tofigureoutwhatthesecondargumentisusedfor.
Chapter10.InteractiveProgrammingUntilnow,theJavaScriptcodeonourwebpageshasrunassoonasthepageisloaded,pausingonlyifweincludeacalltoafunctionlikealertorconfirm.Butwedon’talwaysnecessarilywantallofourcodetorunassoonasthepageloads—whatifwewantsomecodetorunafteradelayorinresponsetosomethingtheuserdoes?Inthischapter,we’lllookatdifferentwaysofmodifyingwhenourcodeisrun.Programminginthiswayiscalledinteractiveprogramming.Thiswillletuscreateinteractivewebpagesthatchangeovertimeandrespondtoactionsbytheuser.
DelayingCodewithsetTimeoutInsteadofhavingJavaScriptexecuteafunctionimmediately,youcantellittoexecuteafunctionafteracertainperiodoftime.Delayingafunctionlikethisiscalledsettingatimeout.TosetatimeoutinJavaScript,weusethefunctionsetTimeout.Thisfunctiontakestwoarguments(asshowninFigure10-1):thefunctiontocallafterthetimehaselapsedandtheamountoftimetowait(inmilliseconds).
Figure10-1.TheargumentsforsetTimeout
ThefollowinglistingshowshowwecouldusesetTimeouttodisplayanalertdialog.➊vartimeUp=function(){
alert("Time'sup!");
};
➋setTimeout(timeUp,3000);
1
At➊wecreatethefunctiontimeUp,whichopensanalertdialogthatdisplaysthetext"Time'sup!".At➋wecallsetTimeoutwithtwoarguments:thefunctionwewanttocall(timeUp)andthenumberofmilliseconds(3000)towaitbeforecallingthatfunction.We’reessentiallysaying,“Wait3secondsandthencalltimeUp.”WhensetTimeout(timeUp,3000)isfirstcalled,nothinghappens,butafter3secondstimeUpiscalledandthealertdialogpopsup.NoticethatcallingsetTimeoutreturns1.ThisreturnvalueiscalledthetimeoutID.ThetimeoutIDisanumberthat’susedtoidentifythisparticulartimeout(thatis,thisparticulardelayedfunctioncall).Theactualnumberreturnedcouldbeanynumber,sinceit’sjustanidentifier.CallsetTimeoutagain,anditshouldreturnadifferenttimeoutID,asshownhere:
setTimeout(timeUp,5000);
2
YoucanusethistimeoutIDwiththeclearTimeoutfunctiontocancelthatspecifictimeout.We’lllookatthatnext.
CancelingaTimeoutOnceyou’vecalledsetTimeouttosetupadelayedfunctioncall,youmayfindthatyoudon’tactuallywanttocallthatfunctionafterall.Forexample,ifyousetanalarmtoremindyoutodoyourhomework,butyouendupdoingyourhomeworkearly,you’dwanttocancelthatalarm.Tocancelatimeout,usethefunctionclearTimeoutonthetimeoutIDreturnedbysetTimeout.Forexample,saywecreatea“doyourhomework”alarmlikethis:
vardoHomeworkAlarm=function(){
alert("Hey!Youneedtodoyourhomework!");
};
➊vartimeoutId=setTimeout(doHomeworkAlarm,60000);
ThefunctiondoHomeworkAlarmpopsupanalertdialogtellingyoutodoyourhomework.WhenwecallsetTimeout(doHomeworkAlarm,60000)we’retellingJavaScripttoexecutethatfunctionafter60,000milliseconds(or60seconds)haspassed.At➊wemakethiscalltosetTimeoutandsavethetimeoutIDinanewvariablecalledtimeoutId.Tocancelthetimeout,passthetimeoutIDtotheclearTimeoutfunctionlikethis:
clearTimeout(timeoutId);
NowsetTimeoutwon’tcallthedoHomeworkAlarmfunctionafterall.
CallingCodeMultipleTimeswithsetIntervalThesetIntervalfunctionislikesetTimeout,exceptthatitrepeatedlycallsthesuppliedfunctionafterregularpauses,orintervals.Forexample,ifyouwantedtoupdateaclockdisplayusingJavaScript,youcouldusesetIntervaltocallanupdatefunctioneverysecond.YoucallsetIntervalwithtwoarguments:thefunctionyouwanttocallandthelengthoftheinterval(inmilliseconds),asshowninFigure10-2.
Figure10-2.TheargumentsforsetInterval
Here’showwecouldwriteamessagetotheconsoleeverysecond:➊varcounter=1;
➋varprintMessage=function(){
console.log("Youhavebeenstaringatyourconsolefor"+counter
+"seconds");
➌counter++;
};
➍varintervalId=setInterval(printMessage,1000);
Youhavebeenstaringatyourconsolefor1seconds
Youhavebeenstaringatyourconsolefor2seconds
Youhavebeenstaringatyourconsolefor3seconds
Youhavebeenstaringatyourconsolefor4seconds
Youhavebeenstaringatyourconsolefor5seconds
Youhavebeenstaringatyourconsolefor6seconds
➎clearInterval(intervalId);
At➊wecreateanewvariablecalledcounterandsetitto1.We’llbeusingthisvariabletokeeptrackofthenumberofsecondsyou’vebeenlookingatyourconsole.At➋wecreateafunctioncalledprintMessage.Thisfunctiondoestwothings.First,itprintsoutamessagetellingyouhowlongyouhavebeenstaringatyourconsole.Then,at➌,itincrementsthecountervariable.Next,at➍,wecallsetInterval,passingtheprintMessagefunctionandthenumber1000.CallingsetIntervallikethismeans“callprintMessageevery1,000milliseconds.”JustassetTimeoutreturnsatimeoutID,setIntervalreturnsanintervalID,whichwesaveinthevariableintervalId.WecanusethisintervalIDtotellJavaScripttostopexecutingtheprintMessagefunction.Thisiswhatwedoat➎,usingtheclearIntervalfunction.
TRYITOUT!
Modifytheprecedingexampletoprintthemessageeveryfivesecondsinsteadofeverysecond.
AnimatingElementswithsetIntervalAsitturnsout,wecanusesetIntervaltoanimateelementsinabrowser.Basically,weneedtocreateafunctionthatmovesanelementbyasmallamount,andthenpassthatfunctiontosetIntervalwithashortintervaltime.Ifwemakethemovementssmallenoughandtheintervalshortenough,theanimationwilllookverysmooth.Let’sanimatethepositionofsometextinanHTMLdocumentbymovingthetexthorizontallyinthebrowserwindow.Createadocumentcalledinteractive.html,andfillitwiththisHTML:
<!DOCTYPEhtml>
<html>
<head>
<title>Interactiveprogramming</title>
</head>
<body>
<h1id="heading">Helloworld!</h1>
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
//We'llfillthisinnext
</script>
</body>
</html>
Nowlet’slookattheJavaScript.Asalways,putyourcodeinsidethe<script>tagsoftheHTMLdocument.
➊varleftOffset=0;
➋varmoveHeading=function(){
➌$("#heading").offset({left:leftOffset});
➍leftOffset++;
➎if(leftOffset>200){
leftOffset=0;
}
};
➏setInterval(moveHeading,30);
Whenyouopenthispage,youshouldseetheheadingelementgraduallymoveacrossthescreenuntilittravels200pixels;atthatpoint,itwilljumpbacktothebeginningandstartagain.Let’sseehowthisworks.At➊wecreatethevariableleftOffset,whichwe’lluselatertopositionourHelloworld!heading.Itstartswithavalueof0,whichmeanstheheadingwillstartonthefarleftsideofthepage.
Next,at➋,wecreatethefunctionmoveHeading,whichwe’llcalllaterwithsetInterval.InsidethemoveHeadingfunction,at➌,weuse$("#heading")toselecttheelementwiththeidof"heading"(ourh1element)andusetheoffsetmethodtosettheleftoffsetoftheheading—thatis,howfaritisfromtheleftsideofthescreen.Theoffsetmethodtakesanobjectthatcancontainaleftproperty,whichsetstheleftoffsetofthe
element,oratopproperty,whichsetsthetopoffsetoftheelement.InthisexampleweusetheleftpropertyandsetittoourleftOffsetvariable.Ifwewantedastaticoffset(thatis,anoffsetthatdoesn’tchange),wecouldsetthepropertytoanumericvalue.Forexample,calling$("#heading").offset({left:100})wouldplacetheheadingelement100pixelsfromtheleftsideofthepage.At➍weincrementtheleftOffsetvariableby1.Tomakesuretheheadingdoesn’tmovetoofar,at➎wechecktoseeifleftOffsetisgreaterthan200,andifitis,weresetitto0.Finally,at➏wecallsetInterval,andforitsargumentswepassinthefunctionmoveHeadingandthenumber30(for30milliseconds).ThiscodecallsthemoveHeadingfunctionevery30milliseconds,orabout33timeseverysecond.EachtimemoveHeadingiscalled,theleftOffsetvariableisincremented,andthevalueofthisvariableisusedtosetthepositionoftheheadingelement.BecausethefunctionisconstantlybeingcalledandleftOffsetisincrementedby1eachtime,theheadinggraduallymovesacrossthescreenby1pixelevery30milliseconds.
TRYITOUT!
YoucanspeedupthisanimationbyraisingtheamountthatleftOffsetisincreasedeverytimemoveHeadingiscalledorbyreducingthetimethatsetIntervalwaitsbetweencallstomoveHeading.
Howwouldyoudoublethespeedthattheheadingmoves?Tryitwithbothtechniques.Whatdifferencedoyousee?
RespondingtoUserActionsAsyou’veseen,onewaytocontrolwhencodeisruniswiththefunctionssetTimeoutandsetInterval,whichrunafunctiononceafixedamountoftimehaspassed.Anotherwayistoruncodeonlywhenauserperformscertainactions,suchasclicking,typing,orevenjustmovingthemouse.Thiswillletusersinteractwithyourwebpagesothatyourpagerespondsaccordingtowhattheydo.Inabrowser,everytimeyouperformanactionsuchasclicking,typing,ormovingyourmouse,somethingcalledaneventistriggered.Aneventisthebrowser’swayofsaying,“Thisthinghappened!”Youcanlistentotheseeventsbyaddinganeventhandlertotheelementwheretheeventhappened.AddinganeventhandlerisyourwayoftellingJavaScript,“Ifthiseventhappensonthiselement,callthisfunction.”Forexample,ifyouwantafunctiontobecalledwhentheuserclicksaheadingelement,youcouldaddaclickeventhandlertotheheadingelement.We’lllookathowtodothatnext.
RespondingtoClicksWhenauserclicksanelementinthebrowser,thistriggersaclickevent.jQuerymakesiteasytoaddahandlerforaclickevent.Opentheinteractive.htmldocumentyoucreatedearlier,useFile▸SaveAstosaveitasclicks.html,andreplaceitssecondscriptelementwiththiscode:
➊varclickHandler=function(event){
➋console.log("Click!"+event.pageX+""+event.pageY);
};
➌$("h1").click(clickHandler);
At➊wecreatethefunctionclickHandlerwiththesingleargumentevent.Whenthisfunctioniscalled,theeventargumentwillbeanobjectholdinginformationabouttheclickevent,suchasthelocationoftheclick.At➋,insidethehandlerfunction,weuseconsole.logtooutputthepropertiespageXandpageYfromtheeventobject.Thesepropertiestellustheevent’sx-andy-coordinates—inotherwords,theysaywhereonthepagetheclickoccurred.Finally,at➌weactivatetheclickhandler.Thecode$("h1")selectstheh1element,andcalling$("h1").click(clickHandler)means“Whenthereisaclickontheh1element,calltheclickHandlerfunctionandpassittheeventobject.”Inthiscase,theclickhandlerretrievesinformationfromtheeventobjecttooutputthex-andy-coordinatesoftheclicklocation.
Reloadyourmodifiedpageinyourbrowserandclicktheheadingelement.Eachtimeyouclicktheheading,anewlineshouldbeoutputtotheconsole,asshowninthefollowinglisting.Eachlineshowstwonumbers:thex-andy-coordinatesoftheclickedlocation.
Click!8843
Click!6353
Click!2453
Click!12146
Click!9355
Click!10348
BROWSERCOORDINATES
Inthewebbrowserandinmostprogrammingandgraphicsenvironments,the0positionofthex-andy-coordinatesisatthetop-leftcornerofthescreen.Asthex-coordinateincreases,youmoverightacrossthepage,andasthey-coordinateincreases,youmovedownthepage(seeFigure10-3).
Figure10-3.Coordinatesinthebrowser,showingaclickatthecoordinate(3,2)
ThemousemoveEventThemousemoveeventistriggeredeverytimethemousemoves.Totryitout,createafilecalledmousemove.htmlandenterthiscode:
<!DOCTYPEhtml>
<html>
<head>
<title>Mousemove</title>
</head>
<body>
<h1id="heading">Helloworld!</h1>
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
➊$("html").mousemove(function(event){
➋$("#heading").offset({
left:event.pageX,
top:event.pageY
});
});
</script>
</body>
</html>
At➊weaddahandlerforthemousemoveeventusing$("html").mousemove(handler).Inthiscase,thehandleristheentirefunctionthatappearsaftermousemoveandbefore</script>.Weuse$("html")toselectthehtmlelementsothatthehandleristriggeredbymousemovementsthatoccuranywhereonthepage.Thefunctionthatwepassintotheparenthesesaftermousemovewillbecalledeverytimetheusermovesthemouse.Inthisexample,insteadofcreatingtheeventhandlerseparatelyandpassingthefunctionnametothemousemovemethod(aswedidwithourclickHandlerfunctionearlier),we’repassingthehandlerfunctiondirectlytothemousemovemethod.Thisisaverycommonwayofwritingeventhandlers,soit’sgoodtobefamiliarwiththistypeofsyntax.
At➋,insidetheeventhandlerfunction,weselecttheheadingelementandcalltheoffsetmethodonit.AsImentionedbefore,theobjectpassedtooffsetcanhaveleftandtopproperties.Inthiscase,wesettheleftpropertytoevent.pageXandthetoppropertytoevent.pageY.Now,everytimethemousemoves,theheadingwillmovetothatlocation.Inotherwords,whereveryoumovethemouse,theheadingfollowsit!
WhatYouLearnedInthischapter,youlearnedhowtowriteJavaScriptthatrunsonlywhenyouwantitto.ThesetTimeoutandsetIntervalfunctionsaregreatfortimingcodetorunafteradelayoratcertainintervals.Ifyouwanttoruncodewhentheuserdoessomethinginthebrowser,youcanuseeventslikeclickandmousemove,buttherearemanyothers.Inthenextchapter,we’llputwhatyou’vejustlearnedtogoodusetomakeagame!
ProgrammingChallengesHereareafewchallengestoexploremorewaystouseinteractiveprogramming.#1:FOLLOWTHECLICKSModifythepreviousmousemoveprogramsothatinsteadoffollowingyourmouse,theheadingwillfollowjustyourclicks.Wheneveryouclickthepage,theheadingshouldmovetotheclicklocation.#2:CREATEYOUROWNANIMATIONUsesetIntervaltoanimateanh1headingelementaroundthepage,inasquare.Itshouldmove200pixelstotheright,200pixelsdown,200pixelstotheleft,200pixelsup,andthenstartagain.Hint:You’llneedtokeeptrackofyourcurrentdirection(right,down,left,orup)sothatyouknowwhethertoincreaseordecreasetheleftortopoffsetoftheheading.You’llalsoneedtochangethedirectionwhenyoureachacornerofthesquare.#3:CancelanAnimationwithaClickBuildinguponChallenge#2,addaclickhandlertothemovingh1elementthatcancelstheanimation.Hint:YoucancancelintervalswiththeclearIntervalfunction.#4:MAKEA“CLICKTHEHEADER”GAME!ModifyChallenge#3sothateverytimeaplayerclickstheheading,insteadofstopping,theheadingspeedsup,makingitharderandhardertoclick.Keeptrackofthenumberoftimestheheadinghasbeenclickedandupdatetheheadingtextsoitshowsthisnumber.Whentheplayerhasreached10clicks,stoptheanimationandchangethetextoftheheadingto“YouWin.”Hint:Tospeedup,you’llhavetocancelthecurrentintervalandthenstartanewonewithashorterintervaltime.
Chapter11.FindtheBuriedTreasure!Let’sputwhatwe’velearnedsofartogooduseandmakeagame!Theaimofthisgameistofindthehiddentreasure.Inthisgame,thewebpagewilldisplayatreasuremap.Insidethatmap,theprogramwillpickasinglepixellocation,whichrepresentswherethehiddentreasureisburied.Everytimetheplayerclicksthemap,thewebpagewilltellthemhowclosetothetreasuretheyare.Whentheyclickthelocationofthetreasure(orveryclosetoit),thegamecongratulatesthemonfindingthetreasureandsayshowmanyclicksittooktofindit.Figure11-1showswhatthegamewilllooklikeafteraplayerclicksthemap.
Figure11-1.Theburiedtreasuregame
DesigningtheGameBeforewestartwritingthecode,let’sbreakdowntheoverallstructureofthisgame.Hereisalistofstepsweneedtotaketosetupthegamesoitcanrespondaccordinglywhenaplayerclicksthetreasuremap.1. Createawebpagewithanimage(thetreasuremap)andaplacetodisplaymessagestotheplayer.2. Pickarandomspotonthemappicturetohidethetreasure.3. Createaclickhandler.Eachtimetheplayerclicksthemap,theclickhandlerwilldothefollowing:
a. Add1toaclickcounter.b. Calculatehowfartheclicklocationisfromthetreasurelocation.c. Displayamessageonthewebpagetotelltheplayerwhetherthey’rehotorcold.d. Congratulatetheplayeriftheyclickonthetreasureorveryclosetoit,andsayhowmany
clicksittooktofindthetreasure.I’llshowyouhowtoimplementeachofthesefeaturesinthegame,andthenwe’llgothroughthefullcode.
CreatingtheWebPagewithHTMLLet’slookattheHTMLforthegame.We’lluseanewelementcalledimgforthetreasuremapandaddapelementwherewecandisplaymessagestotheplayer.Enterthefollowingcodeintoanewfilecalledtreasure.html.
<!DOCTYPEhtml>
<html>
<head>
<title>Findtheburiedtreasure!</title>
</head>
<body>
<h1id="heading">Findtheburiedtreasure!</h1>
➊<imgid="map"width=400height=400
➋src="http://nostarch.com/images/treasuremap.png">
➌<pid="distance"></p>
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
//Gamecodegoeshere
</script>
</body>
</html>
TheimgelementisusedtoincludeimagesinHTMLdocuments.UnliketheotherHTMLelementswe’velookedat,imgdoesn’tuseaclosingtag.Allyouneedisanopeningtag,which,likeotherHTMLtags,cancontainvariousattributes.At➊we’veaddedanimgelementwithanidof"map".Wesetthewidthandheightofthiselementusingthewidthandheightattributes,whicharebothsetto400.Thismeansourimagewillbe400pixelstalland400pixelswide.Totellthedocumentwhichimagewewanttodisplay,weusethesrcattributetoincludethewebaddressoftheimageat➋.Inthiscase,we’relinkingtoanimagecalledtreasuremap.pngontheNoStarchPresswebsite.Followingtheimgelementisanemptypelementat➌,whichwegiveanidof"distance".We’lladdtexttothiselementbyusingJavaScripttotelltheplayerhowclosetheyaretothetreasure.
PickingaRandomTreasureLocationNowlet’sbuildtheJavaScriptforourgame.Firstweneedtopickarandomlocationforthehiddentreasureinsidethetreasuremapimage.Sincethedimensionsofthemapare400by400pixels,thecoordinatesofthetop-leftpixelwillbe{x:0,y:0},andthebottom-rightpixelwillbe{x:399,y:399}.
PickingRandomNumbersTosetarandomcoordinatepointwithinthetreasuremap,wepickarandomnumberbetween0and399forthexvalueandarandomnumberbetween0and399fortheyvalue.Togeneratetheserandomvalues,we’llwriteafunctionthattakesasizeargumentasinputandpicksarandomnumberfrom0upto(butnotincluding)size:
vargetRandomNumber=function(size){
returnMath.floor(Math.random()*size);
};
Thiscodeissimilartothecodewe’veusedtopickrandomwordsinearlierchapters.Wegeneratearandomnumberbetween0and1usingMath.random,multiplythatbythesizeargument,andthenuseMath.floortoroundthatnumberdowntoawholenumber.Thenweoutputtheresultasthereturnvalueofthefunction.CallinggetRandomNumber(400)willreturnarandomnumberfrom0to399,whichisjustwhatweneed!
SettingtheTreasureCoordinatesNowlet’susethegetRandomNumberfunctiontosetthetreasurecoordinates:
➊varwidth=400;
varheight=400;
➋vartarget={
x:getRandomNumber(width),
y:getRandomNumber(height)
};
Thesectionofcodeat➊setsthewidthandheightvariables,whichrepresentthewidthandheightoftheimgelementthatwe’reusingasatreasuremap.At➋wecreateanobjectcalledtarget,whichhastwoproperties,xandy,thatrepresentthecoordinatesoftheburiedtreasure.ThexandypropertiesarebothsetbygetRandomNumber.Eachtimewerunthiscode,wegetanewrandomlocationonthemap,andthechosencoordinateswillbesavedinthexandypropertiesofthetargetvariable.
TheClickHandlerTheclickhandleristhefunctionthatwillbecalledwhentheplayerclicksthetreasuremap.Startbuildingthisfunctionwiththiscode:
$("#map").click(function(event){
//Clickhandlercodegoeshere
});
Firstweuse$("#map")toselectthetreasuremaparea(becausetheimgelementhasanidof"map"),andthenwegointotheclickhandlerfunction.Eachtimetheplayerclicksthemap,thefunctionbodybetweenthecurlybracketswillbeexecuted.Informationabouttheclickispassedintothatfunctionbodyasanobjectthroughtheeventargument.Thisclickhandlerfunctionneedstodoquiteabitofwork:ithastoincrementtheclickcounter,calculatehowfareachclickisfromthetreasure,anddisplaymessages.Beforewefillinthecodefortheclickhandlerfunction,we’lldefinesomevariablesandcreatesomeotherfunctionsthatwillhelpexecuteallthesesteps.
CountingClicksThefirstthingourclickhandlerneedstodoistrackthetotalnumberofclicks.Tosetthisup,wecreateavariablecalledclicksatthebeginningoftheprogram(outsidetheclickhandler)andinitializeittozero:
varclicks=0;
Insidetheclickhandler,we’llincludeclicks++sothatweincrementclicksby1eachtimetheplayerclicksthemap.
CalculatingtheDistanceBetweentheClickandtheTreasureTofigureoutwhethertheplayerishotorcold(closetothetreasureorfaraway),weneedtomeasurethedistancebetweenwheretheplayerclickedandthelocationofthehiddentreasure.Todothis,we’llwriteafunctioncalledgetDistance,likeso:
vargetDistance=function(event,target){
vardiffX=event.offsetX-target.x;
vardiffY=event.offsetY-target.y;
returnMath.sqrt((diffX*diffX)+(diffY*diffY));
};
ThegetDistancefunctiontakestwoobjectsasarguments:eventandtarget.Theeventobjectistheobjectpassedtotheclickhandler,anditcomeswithlotsofbuilt-ininformationabouttheplayer’sclick.Inparticular,itcontainstwopropertiescalledoffsetXandoffsetY,whichtellusthex-andy-coordinatesoftheclick,andthat’sexactlytheinformationweneed.Insidethefunction,thevariablediffXstoresthehorizontaldistancebetweentheclickedlocationandthetarget,whichwecalculatebysubtractingtarget.x(thex-coordinateofthetreasure)fromevent.offsetX(thex-coordinateoftheclick).Wecalculatetheverticaldistancebetweenthepointsinthesameway,andstoretheresultasdiffY.Figure11-2showshowwewouldcalculatediffXanddiffYfortwopoints.
Figure11-2.Calculatingthehorizontalandverticaldistancesbetweeneventandtarget
UsingthePythagoreanTheoremNext,thegetDistancefunctionusesthePythagoreantheoremtocalculatethedistancebetweentwopoints.ThePythagoreantheoremsaysthatforarighttriangle,whereaandbrepresentthelengthsofthetwosidesborderingtherightangleandcrepresentsthelengthofthediagonalside(thehypotenuse),a2+b2=c2.Giventhelengthsofaandb,wecancalculatethelengthofthehypotenusebycalculatingthesquarerootofa2+b2.
Tocalculatethedistancebetweentheeventandthetarget,wetreatthetwopointsasifthey’repartofarighttriangle,asshowninFigure11-3.InthegetDistancefunction,diffXisthelengthofthehorizontaledgeofthetriangle,anddiffYisthelengthoftheverticaledge.Tocalculatethedistancebetweentheclickandthetreasure,weneedtocalculatethelengthofthehypotenuse,basedonthelengthsdiffXanddiffY.AsamplecalculationisshowninFigure11-3.
Figure11-3.Calculatingthehypotenusetofindoutthedistancebetweeneventandtarget
Togetthelengthofthehypotenuse,wefirsthavetosquarediffXanddiffY.Wethenaddthesesquaredvaluestogether,andgetthesquarerootusingtheJavaScriptfunctionMath.sqrt.Soourcompleteformulaforcalculatingthedistancebetweentheclickandthetargetlookslikethis:
Math.sqrt((diffX*diffX)+(diffY*diffY))
ThegetDistancefunctioncalculatesthisandreturnstheresult.
TellingthePlayerHowCloseTheyAreOnceweknowthedistancebetweentheplayer’sclickandthetreasure,wewanttodisplayahinttellingtheplayerhowclosetheyaretothetreasure,withouttellingthemexactlyhowfarawaythetreasureis.Forthis,weusethegetDistanceHintfunctionshownhere:
vargetDistanceHint=function(distance){
if(distance<10){
return"Boilinghot!";
}elseif(distance<20){
return"Reallyhot";
}elseif(distance<40){
return"Hot";
}elseif(distance<80){
return"Warm";
}elseif(distance<160){
return"Cold";
}elseif(distance<320){
return"Reallycold";
}else{
return"Freezing!";
}
};
Thisfunctionreturnsdifferentstringsdependingonthecalculateddistancefromthetreasure.Ifthedistanceislessthan10,thefunctionreturnsthestring"Boilinghot!".Ifthedistanceisbetween10and20,thefunctionreturns"Reallyhot".Thestringsgetcolderasthedistanceincreases,uptothepointwherewereturn"Freezing!"ifthedistanceisgreaterthan320pixels.Wedisplaythemessagetotheplayerbyaddingitastextinthepelementofthewebpage.Thefollowingcodewillgoinsideourclickhandlertocalculatethedistance,picktheappropriatestring,anddisplaythatstringtotheplayer:
vardistance=getDistance(event,target);
vardistanceHint=getDistanceHint(distance);
$("#distance").text(distanceHint);
Asyoucansee,wefirstcallgetDistanceandthensavetheresultasthevariabledistance.NextwepassthatdistancetothegetDistanceHintfunctiontopicktheappropriatestringandsaveitasdistanceHint.Thecode$("#distance").text(distanceHint);selectstheelementwiththeidof"distance"(inthiscasethepelement)andsetsitstexttodistanceHintsothateachtimetheplayerclicksthemap,
ourwebpagetellsthemhowclosetheyaretothetarget.
CheckingIfthePlayerWonFinally,ourclickhandlerneedstocheckwhethertheplayerhaswon.Becausepixelsaresosmall,insteadofmakingtheplayerclicktheexactlocationofthetreasure,we’llletthemwiniftheyclickwithin8pixels.Thiscodechecksthedistancetothetreasureanddisplaysamessagetellingtheplayerthatthey’vewon:
if(distance<8){
alert("Foundthetreasurein"+clicks+"clicks!");
}
Ifthedistanceislessthan8pixels,thiscodeusesalerttotelltheplayertheyfoundthetreasureandhowmanyclicksittookthemtodoso.
PuttingItAllTogetherNowthatwehaveallthepieces,let’scombinethemtomakeonescript.
//Getarandomnumberfrom0tosize
vargetRandomNumber=function(size){
returnMath.floor(Math.random()*size);
};
//Calculatedistancebetweenclickeventandtarget
vargetDistance=function(event,target){
vardiffX=event.offsetX-target.x;
vardiffY=event.offsetY-target.y;
returnMath.sqrt((diffX*diffX)+(diffY*diffY));
};
//Getastringrepresentingthedistance
vargetDistanceHint=function(distance){
if(distance<10){
return"Boilinghot!";
}elseif(distance<20){
return"Reallyhot";
}elseif(distance<40){
return"Hot";
}elseif(distance<80){
return"Warm";
}elseif(distance<160){
return"Cold";
}elseif(distance<320){
return"Reallycold";
}else{
return"Freezing!";
}
};
//Setupourvariables
➊varwidth=400;
varheight=400;
varclicks=0;
//Createarandomtargetlocation
➋vartarget={
x:getRandomNumber(width),
y:getRandomNumber(height)
};
//Addaclickhandlertotheimgelement
➌$("#map").click(function(event){
clicks++;
//Getdistancebetweenclickeventandtarget
➍vardistance=getDistance(event,target);
//Convertdistancetoahint
➎vardistanceHint=getDistanceHint(distance);
//Updatethe#distanceelementwiththenewhint
➏$("#distance").text(distanceHint);
//Iftheclickwascloseenough,tellthemtheywon
➐if(distance<8){
alert("Foundthetreasurein"+clicks+"clicks!");
}
});
First,wehavethethreefunctionsgetRandomNumber,getDistance,andgetDistanceHint,whichwe’vealreadylookedat.Then,at➊,wesetupthevariableswe’llneed:width,height,andclicks.Afterthat,at➋,wecreatetherandomlocationforthetreasure.At➌wecreateaclickhandleronthemapelement.Thefirstthingthisdoesisincrementtheclicksvariableby1.Then,at➍,itworksoutthedistancebetweenevent(theclicklocation)andtarget(thetreasurelocation).At➎weusethefunctiongetDistanceHinttoconvertthisdistanceintoastringrepresentingthedistance("Cold","Warm",andsoon).Weupdatethedisplayat➏sotheusercanseehowfartheyare.Finally,at➐,wechecktoseewhetherthedistanceisunder8,andifso,wetelltheplayerthey’vewonandinhowmanyclicks.ThisistheentireJavaScriptforourgame.Ifyouaddthistothesecond<script>tagintreasure.html,youshouldbeabletoplayitinyourbrowser!Howmanyclicksdoesittakeyoutofindthetreasure?
WhatYouLearnedInthischapter,youusedyournewevent-handlingskillstocreateagame.Youalsolearnedabouttheimgelement,whichcanbeusedtoaddimagestoawebpage.Finally,youlearnedhowtomeasurethedistancebetweentwopointsusingJavaScript.Inthenextchapter,we’lllearnaboutobject-orientedprogramming,whichwillgiveusmoretoolsfororganizingourcode.
ProgrammingChallengesHereareafewwaysyoucouldchangethegameandaddmorefeatures.#1:INCREASINGTHEPLAYINGAREAYoucouldmakethegameharderbyincreasingthesizeoftheplayingarea.Howwouldyoumakeit800pixelswideby800pixelstall?#2:ADDINGMOREMESSAGESTryaddingsomeextramessagestodisplaytotheplayer(like"Reallyreallycold!"),andmodifythedistancestomakethegameyourown.#3:ADDINGACLICKLIMITAddalimittothenumberofclicksandshowthemessage"GAMEOVER"iftheplayerexceedsthislimit.#4:DISPLAYINGTHENUMBEROFREMAININGCLICKSShowthenumberofremainingclicksasanextrapieceoftextafterthedistancedisplaysotheplayerknowsifthey’reabouttolose.
Chapter12.Object-OrientedProgrammingChapter4discussedJavaScriptobjects—collectionsofkeyspairedwithvalues.Inthischapter,we’lllookatwaystocreateanduseobjectsasweexploreobject-orientedprogramming.Object-orientedprogrammingisawaytodesignandwriteprogramssothatalloftheprogram’simportantpartsarerepresentedbyobjects.Forexample,whenbuildingaracinggame,youcoulduseobject-orientedprogrammingtechniquestorepresenteachcarasanobjectandthencreatemultiplecarobjectsthatsharethesamepropertiesandfunctionality.
ASimpleObjectInChapter4,youlearnedthatobjectsaremadeupofproperties,whicharesimplypairsofkeysandvalues.Forexample,inthefollowingcodetheobjectdogrepresentsadogwiththepropertiesname,legs,andisAwesome:
vardog={
name:"Pancake",
legs:4,
isAwesome:true
};
Oncewecreateanobject,wecanaccessitspropertiesusingdotnotation(discussedinAccessingValuesinObjects).Forexample,here’showwecouldaccessthenamepropertyofourdogobject:
dog.name;
"Pancake"
WecanalsousedotnotationtoaddpropertiestoaJavaScriptobject,likethis:dog.age=6;
Thisaddsanewkey-valuepair(age:6)totheobject,asyoucanseebelow:dog;
Object{name:"Pancake",legs:4,isAwesome:true,age:6}
AddingMethodstoObjectsIntheprecedingexample,wecreatedseveralpropertieswithdifferentkindsofvaluessavedtothem:astring("Pancake"),numbers(4and6),andaBoolean(true).Inadditiontostrings,numbers,andBooleans,youcansaveafunctionasapropertyinsideanobject.Whenyousaveafunctionasapropertyinanobject,thatpropertyiscalledamethod.Infact,we’vealreadyusedseveralbuilt-inJavaScriptmethods,likethejoinmethodonarraysandthetoUpperCasemethodonstrings.Nowlet’sseehowtocreateourownmethods.Onewaytoaddamethodtoanobjectiswithdotnotation.Forexample,wecouldaddamethodcalledbarktothedogobjectlikethis:
➊dog.bark=function(){
➋console.log("Woofwoof!Mynameis"+this.name+"!");
};
➌dog.bark();
Woofwoof!MynameisPancake!
At➊weaddapropertytothedogobjectcalledbarkandassignafunctiontoit.At➋,insidethisnewfunction,weuseconsole.logtologWoofwoof!MynameisPancake!.Noticethatthefunctionusesthis.name,whichretrievesthevaluesavedintheobject’snameproperty.Let’stakeacloserlookathowthethiskeywordworks.
UsingthethisKeywordYoucanusethethiskeywordinsideamethodtorefertotheobjectonwhichthemethodiscurrentlybeingcalled.Forexample,whenyoucallthebarkmethodonthedogobject,thisreferstothedogobject,sothis.namereferstodog.name.Thethiskeywordmakesmethodsmoreversatile,allowingyoutoaddthesamemethodtomultipleobjectsandhaveitaccessthepropertiesofwhateverobjectit’scurrentlybeingcalledon.
SharingaMethodBetweenMultipleObjectsLet’screateanewfunctioncalledspeakthatwecanuseasamethodinmultipleobjectsthatrepresentdifferentanimals.Whenspeakiscalledonanobject,itwillusetheobject’sname(this.name)andthesoundtheanimalmakes(this.sound)tologamessage.
varspeak=function(){
console.log(this.sound+"!Mynameis"+this.name+"!");
};
Nowlet’screateanotherobjectsowecanaddspeaktoitasamethod:varcat={
sound:"Miaow",
name:"Mittens",
➊speak:speak
};
Herewecreateanewobjectcalledcat,withsound,name,andspeakproperties.Wesetthespeakpropertyat➊andassignitthespeakfunctionwecreatedearlier.Nowcat.speakisamethodthatwecancallbyenteringcat.speak().Sinceweusedthethiskeywordinthemethod,whenwecallitoncat,itwillaccessthecatobject’sproperties.Let’sseethatnow:
cat.speak();
Miaow!MynameisMittens!
Whenwecallthecat.speakmethod,itretrievestwopropertiesfromthecatobject:this.sound(whichis"Miaow")andthis.name(whichis"Mittens").Wecanusethesamespeakfunctionasamethodinotherobjectstoo:
varpig={
sound:"Oink",
name:"Charlie",
speak:speak
};
varhorse={
sound:"Neigh",
name:"Marie",
speak:speak
};
pig.speak();
Oink!MynameisCharlie!
horse.speak();
Neigh!MynameisMarie!
Again,eachtimethisappearsinsideamethod,itreferstotheobjectonwhichthemethodiscalled.In
otherwords,whenyoucallhorse.speak(),thiswillrefertohorse,andwhenyoucallpig.speak(),thisreferstopig.Tosharemethodsbetweenmultipleobjects,youcansimplyaddthemtoeachobject,aswejustdidwithspeak.Butifyouhavelotsofmethodsorobjects,addingthesamemethodstoeachobjectindividuallycanbecomeannoying,anditcanmakeyourcodemessier,too.Justimagineifyouneededawholezoofullof100animalobjectsandyouwantedeachtoshareasetof10methodsandproperties.JavaScriptobjectconstructorsofferabetterwaytosharemethodsandpropertiesbetweenobjects,aswe’llseenext.
CreatingObjectsUsingConstructorsAJavaScriptconstructorisafunctionthatcreatesobjectsandgivesthemasetofbuilt-inpropertiesandmethods.Thinkofitasaspecializedmachineforcreatingobjects,kindoflikeafactorythatcanchurnouttonsofcopiesofthesameitem.Onceyou’vesetupaconstructor,youcanuseittomakeasmanyofthesameobjectasyouwant.Totryitout,we’llbuildthebeginningsofaracinggame,usingaCarconstructortocreateafleetofcarswithsimilarbasicpropertiesandmethodsforsteeringandacceleration.
AnatomyoftheConstructorEachtimeyoucallaconstructor,itcreatesanobjectandgivesthenewobjectbuilt-inproperties.Tocallanormalfunction,youenterthefunctionnamefollowedbyapairofparentheses.Tocallaconstructor,youenterthekeywordnew(whichtellsJavaScriptthatyouwanttouseyourfunctionasaconstructor),followedbytheconstructornameandparentheses.Figure12-1showsthesyntaxforcallingaconstructor.
Figure12-1.ThesyntaxforcallingaconstructornamedCarwithtwoarguments
NOTE
MostJavaScriptprogrammersstartconstructornameswithacapitallettersoit’seasytoseeataglancethatthey’redifferentfromotherfunctions.
CreatingaCarConstructorNowlet’screateaCarconstructorthatwilladdanxandypropertytoeachnewobjectitcreates.Thesepropertieswillbeusedtoseteachcar’sonscreenpositionwhenwedrawit.
CreatingtheHTMLDocumentBeforewecanbuildourconstructor,weneedtocreateanewHTMLdocument.Makeanewfilecalledcars.htmlandenterthisHTMLintoit:
<!DOCTYPEhtml>
<html>
<head>
<title>Cars</title>
</head>
<body>
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
//Codegoeshere
</script>
</body>
</html>
TheCarConstructorfunctionNowaddthiscodetotheempty<script>tagsincars.html(replacingthecomment//Codegoeshere)tocreatetheCarconstructorthatgiveseachcarasetofcoordinates.
<script>
varCar=function(x,y){
this.x=x;
this.y=y;
};
</script>
OurnewconstructorCartakestheargumentsxandy.We’veaddedthepropertiesthis.xandthis.ytostorethexandyvaluespassedtoCarinournewobject.Thisway,eachtimewecallCarasaconstructor,anewobjectiscreatedwithitsxandypropertiessettotheargumentswespecify.
CallingtheCarConstructorAsImentionedearlier,thekeywordnewtellsJavaScriptthatwe’recallingaconstructortocreateanewobject.Forexample,tocreateacarobjectnamedtesla,opencars.htmlinawebbrowserandthenenterthiscodeintheChromeJavaScriptconsole:
vartesla=newCar(10,20);
tesla;
Car{x:10,y:20}
ThecodenewCar(10,20)tellsJavaScripttocreateanobjectusingCarasaconstructor,passinthearguments10and20foritsxandyproperties,andreturnthatobject.Weassignthereturnedobjecttotheteslavariablewithvartesla.Thenwhenweentertesla,theChromeconsolereturnsthenameoftheconstructoranditsxandyvalues:Car{x:10,y:20}.
DrawingtheCarsToshowtheobjectscreatedbytheCarconstructor,we’llcreateafunctioncalleddrawCartoplaceanimageofacarateachcarobject’s(x,y)positioninabrowserwindow.Oncewe’veseenhowthisfunctionworks,we’llrewriteitinamoreobject-orientedwayinAddingadrawMethodtotheCarPrototype.Addthiscodebetweenthe<script>tagsincars.html:
<script>
varCar=function(x,y){
this.x=x;
this.y=y;
};
vardrawCar=function(car){
➊varcarHtml='<imgsrc="http://nostarch.com/images/car.png">';
➋varcarElement=$(carHtml);
➌carElement.css({
position:"absolute",
left:car.x,
top:car.y
});
➍$("body").append(carElement);
};
</script>
At➊wecreateastringcontainingHTMLthatpointstoanimageofacar.(UsingsinglequotestocreatethisstringletsususedoublequotesintheHTML.)At➋wepasscarHTMLtothe$function,whichconvertsitfromastringtoajQueryelement.ThatmeansthecarElementvariablenowholdsajQueryelementwiththeinformationforour<img>tag,andwecantweakthiselementbeforeaddingittothepage.At➌weusethecssmethodoncarElementtosetthepositionofthecarimage.Thiscodesetstheleftpositionoftheimagetothecarobject’sxvalueanditstoppositiontotheyvalue.Inotherwords,theleftedgeoftheimagewillbexpixelsfromtheleftedgeofthebrowserwindow,andthetopedgeoftheimagewillbeypixelsdownfromthetopedgeofthewindow.
NOTE
Inthisexample,thecssmethodworksliketheoffsetmethodweusedinChapter10tomoveelementsaroundthepage.Unfortunately,offsetdoesn’tworkaswellwithmultipleelements,andsincewewanttodrawmultiplecars,we’reusingcsshereinstead.
Finally,at➍weusejQuerytoappendthecarElementtothebodyelementofthewebpage.ThisfinalstepmakesthecarElementappearonthepage.(Forareminderonhowappendworks,seeCreatingNewElementswithjQuery.)
TestingthedrawCarFunctionLet’stestthedrawCarfunctiontomakesureitworks.Addthiscodetoyourcars.htmlfile(aftertheotherJavaScriptcode)tocreatetwocars.
$("body").append(carElement);
};
vartesla=newCar(20,20);
varnissan=newCar(100,200);
drawCar(tesla);
drawCar(nissan);
</script>
Here,weusetheCarconstructortocreatetwocarobjects,oneatthecoordinates(20,20)andtheotherat(100,200),andthenweusedrawCartodraweachoftheminthebrowser.Nowwhenyouopencars.html,youshouldseetwocarimagesinyourbrowserwindow,asshowninFigure12-2.
Figure12-2.DrawingcarsusingdrawCar
CustomizingObjectswithPrototypesAmoreobject-orientedwaytodrawourcarswouldbetogiveeachcarobjectadrawmethod.Then,insteadofwritingdrawCar(tesla),you’dwritetesla.draw().Inobject-orientedprogramming,wewantobjectstohavetheirownfunctionalitybuiltinasmethods.Inthiscase,thedrawCarfunctionisalwaysmeanttobeusedoncarobjects,soinsteadofsavingdrawCarasaseparatefunction,weshouldincludeitaspartofeachcarobject.JavaScriptprototypesmakeiteasytosharefunctionality(asmethods)betweendifferentobjects.Allconstructorshaveaprototypeproperty,andwecanaddmethodstoit.Anymethodthatweaddtoaconstructor’sprototypepropertywillbeavailableasamethodtoallobjectscreatedbythatconstructor.Figure12-3showsthesyntaxforaddingamethodtoaprototypeproperty.
Figure12-3.Thesyntaxforaddingamethodtoaprototypeproperty
AddingadrawMethodtotheCarPrototypeLet’saddadrawmethodtoCar.prototypesothatallobjectswecreateusingCarwillhavethedrawmethod.UsingFile▸SaveAs,saveyourcars.htmlfileascars2.html.ThenreplacealloftheJavaScriptinyoursecondsetof<script>tagsincars2.htmlwiththiscode:
➊varCar=function(x,y){
this.x=x;
this.y=y;
};
➋Car.prototype.draw=function(){
varcarHtml='<imgsrc="http://nostarch.com/images/car.png">';
➌this.carElement=$(carHtml);
this.carElement.css({
position:"absolute",
➍left:this.x,
top:this.y
});
$("body").append(this.carElement);
};
vartesla=newCar(20,20);
varnissan=newCar(100,200);
tesla.draw();
nissan.draw();
AftercreatingourCarconstructorat➊,weaddanewmethodcalleddrawtoCar.prototypeat➋.ThismakesthedrawmethodpartofalloftheobjectscreatedbytheCarconstructor.ThecontentsofthedrawmethodareamodifiedversionofourdrawCarfunction.First,wecreateanHTMLstringandsaveitascarHTML.At➌wecreateajQueryelementrepresentingthisHTML,butthistimewesaveitasapropertyoftheobjectbyassigningittothis.carElement.Thenat➍,weusethis.xandthis.ytosetthecoordinatesofthetop-leftcornerofthecurrentcarimage.(Insideaconstructor,thisreferstothenewobjectcurrentlybeingcreated.)Whenyourunthiscode,theresultshouldlooklikeFigure12-2.Wehaven’tchangedthecode’sfunctionality,onlyitsorganization.Theadvantagetothisapproachisthatthecodefordrawingthecarispartofthecar,insteadofaseparatefunction.
AddingamoveRightMethodNowlet’saddsomemethodstomovethecarsaround,beginningwithamoveRightmethodtomovethecar5pixelstotherightofitscurrentposition.AddthefollowingcodeafteryourdefinitionofCar.prototype.draw:
this.carElement.css({
position:"absolute",
left:this.x,
top:this.y
});
$("body").append(this.carElement);
};
Car.prototype.moveRight=function(){
this.x+=5;
this.carElement.css({
left:this.x,
top:this.y
});
};
WesavethemoveRightmethodinCar.prototypetoshareitwithallobjectscreatedbytheCarconstructor.Withthis.x+=5weadd5tothecar’sxvalue,whichmovesthecar5pixelstotheright.Thenweusethecssmethodonthis.carElementtoupdatethecar’spositioninthebrowser.TrythemoveRightmethodinthebrowserconsole.First,refreshcars2.html,andthenopentheconsoleandentertheselines:
tesla.moveRight();
tesla.moveRight();
tesla.moveRight();
Eachtimeyouentertesla.moveRight,thetopcarshouldmove5pixelstotheright.Youcouldusethismethodinaracinggametoshowthecarmovingdowntheracetrack.
TRYITOUT!
Trymovingnissantotheright.HowmanytimesdoyouneedtocallmoveRightonnissantomakeitlineupwithtesla?
UsesetIntervalandmoveRighttoanimatenissansothatitdrivesacrossthebrowserwindow.
AddingtheLeft,Up,andDownmoveMethodsNowwe’lladdtheremainingdirectionstoourcodesothatwecanmoveourcarsaroundthescreeninanydirection.ThesemethodsarebasicallythesameasmoveRight,sowe’llwritethemallatonce.Addthefollowingmethodstocars2.htmljustafterthecodeformoveRight:
Car.prototype.moveRight=function(){
this.x+=5;
this.carElement.css({
left:this.x,
top:this.y
});
};
Car.prototype.moveLeft=function(){
this.x-=5;
this.carElement.css({
left:this.x,
top:this.y
});
};
Car.prototype.moveUp=function(){
this.y-=5;
this.carElement.css({
left:this.x,
top:this.y
});
};
Car.prototype.moveDown=function(){
this.y+=5;
this.carElement.css({
left:this.x,
top:this.y
});
};
Eachofthesemethodsmovesthecarby5pixelsinthespecifieddirectionbyaddingorsubtracting5fromeachcar’sxoryvalue.
WhatYouLearnedInthischapter,youlearnedthebasicsofobject-orientedprogramminginJavaScript,includinghowtocreateconstructorstobuildnewobjectsandhowtomodifytheprototypepropertyofthoseconstructorstosharemethodsbetweenobjects.Inobject-orientedprograms,mostfunctionsarewrittenasmethods.Forexample,todrawthecar,wecallthedrawmethodonthecar,andtomovethecartotheright,wecallthemoveRightmethod.ConstructorsandprototypesareJavaScript’sbuilt-inwayoflettingyoucreateobjectsthatsharethesamesetofmethods,buttherearemanywaystowriteobject-orientedJavaScript.(Formoreonobject-orientedJavaScript,seeNicholasC.Zakas’sThePrinciplesofObject-OrientedJavaScript[NoStarchPress,2014].)WritingJavaScriptinanobject-orientedwaycanhelpyoustructureyourcode.Havingwell-structuredcodemeansthatwhenyoucomebacktoitlatertomakechanges,itshouldbeeasiertofigureouthowyourprogramworksifyoudon’tremember(thisisparticularlyimportantwithbiggerprogramsorwhenyoustarttoworkwithotherprogrammerswhomayneedtoaccessyourcode).Forexample,inthefinalprojectinthisbook,we’llbuildaSnakegamethatrequiresquiteabitofcode,andwe’lluseobjectsandmethodstoorganizeourgameandhandlealotoftheimportantfunctionality.Inthenextchapter,we’llgooverhowtodrawandanimatelinesandshapesonawebpageusingthecanvaselement.
ProgrammingChallengesTrythesechallengestopracticeworkingwithobjectsandprototypes.#1:DRAWINGINTHECARCONSTRUCTORAddacalltothedrawmethodfrominsidetheCarconstructorsothatcarobjectsautomaticallyappearinthebrowserassoonasyoucreatethem.#2:ADDINGASPEEDPROPERTYModifytheCarconstructortoaddanewspeedpropertywithavalueof5totheconstructedobjects.Thenusethispropertyinsteadofthevalue5insidethemovementmethods.Nowtryoutdifferentvaluesforspeedtomakethecarsmovefasterorslower.#3:RACINGCARSModifythemoveLeft,moveRight,moveUp,andmoveDownmethodssotheytakeasingledistanceargument,thenumberofpixelstomove,insteadofalwaysmoving5pixels.Forexample,tomovethenissancar10pixelstotheright,youwouldcallnissan.moveRight(10).Now,usesetIntervaltomovethetwocars(nissanandtesla)totherightevery30millisecondsbyadifferentrandomdistancebetween0and5.Youshouldseethetwocarsanimateacrossthescreen,jumpingalongatvaryingspeeds.Canyouguesswhichcarwillmakeittotheedgeofthewindowfirst?
PartIII.Canvas
Chapter13.TheCanvasElementJavaScriptisn’tallaboutplayingwithtextandnumbers.YoucanalsouseJavaScripttodrawpictureswiththeHTMLcanvaselement,whichyoucanthinkofasablankcanvasorsheetofpaper.Youcandrawalmostanythingthatyouwantonthiscanvas,suchaslines,shapes,andtext.Theonlylimitisyourimagination!Inthischapter,you’lllearnthebasicsofdrawingonthecanvas.Inthefollowingchapters,we’llbuildonourknowledgetocreateacanvas-basedJavaScriptgame.
CreatingaBasicCanvasAsourfirststepinusingthecanvas,createanewHTMLdocumentforthecanvaselement,asshowninthefollowinglisting.Savethisdocumentascanvas.html:
<!DOCTYPEhtml>
<html>
<head>
<title>Canvas</title>
</head>
<body>
➊<canvasid="canvas"width="200"height="200"></canvas>
<script>
//We'llfillthisinnext
</script>
</body>
</html>
Asyoucanseeat➊,wecreateacanvaselementandgiveitanidpropertyof"canvas",whichwe’llusetoselecttheelementinourcode.Thewidthandheightpropertiessetthedimensionsofthecanvaselementinpixels.Herewesetbothdimensionsto200.
DrawingontheCanvasNowthatwe’vebuiltapagewithacanvaselement,let’sdrawsomerectangleswithJavaScript.EnterthisJavaScriptbetweenthe<script>tagsincanvas.html.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
ctx.fillRect(0,0,10,10);
We’llgooverthiscodelinebylineinthefollowingsections.
SelectingandSavingthecanvasElementFirst,weselectthecanvaselementusingdocument.getElementById("canvas").AswesawinChapter9,thegetElementByIdmethodreturnsaDOMobjectrepresentingtheelementwiththesuppliedid.Thisobjectisassignedtothecanvasvariablewiththecodevarcanvas=document.getElementById("canvas").
GettingtheDrawingContextNext,wegetthedrawingcontextfromthecanvaselement.AdrawingcontextisaJavaScriptobjectthatincludesallthemethodsandpropertiesfordrawingonacanvas.Togetthisobject,wecallgetContextoncanvasandpassitthestring"2d"asanargument.Thisargumentsaysthatwewanttodrawatwo-dimensionalimageonourcanvas.Wesavethisdrawingcontextobjectinthevariablectxusingthecodevarctx=canvas.getContext("2d").
DrawingaSquareFinally,onthethirdline,wedrawarectangleonthecanvasbycallingthemethodfillRectonthedrawingcontext.ThefillRectmethodtakesfourarguments.Inorder,thesearethex-andy-coordinatesofthetop-leftcorneroftherectangle(0,0)andthewidthandheightoftherectangle(10,10).Inthiscase,we’resaying,“Drawa10-pixel-by-10-pixelrectangleatcoordinates(0,0),”whichareatthetop-leftcornerofthecanvas.Whenyourunthiscode,youshouldseeasmallblacksquareonyourscreen,asshowninFigure13-1.
Figure13-1.Ourfirstcanvasdrawing
DrawingMultipleSquaresHowabouttryingsomethingabitmoreinteresting?Ratherthandrawingjustonesquare,let’susealooptodrawmultiplesquaresrunningdiagonallydownthescreen.Replacethecodeinthe<script>tagswiththefollowing.Whenyourunthiscode,youshouldseeasetofeightblacksquares,asshowninFigure13-2:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
for(vari=0;i<8;i++){
ctx.fillRect(i*10,i*10,10,10);
}
Thefirsttwolinesarethesameasintheearlierlisting.Inthethirdline,wecreateaforloopthatrunsfrom0to8.Next,insidethisloop,wecallfillRectonthedrawingcontext.
Figure13-2.Drawingmultiplesquaresusingaforloop
Thexandypositionsforthetop-leftcornerofeachsquarearebasedontheloopvariable,i.Thefirsttimearoundtheloop,wheniis0,thecoordinatesare(0,0)because0×10isequalto0.Thismeansthatwhenwerunthecodectx.fillRect(i*10,i*10,10,10),wewilldrawasquareatthecoordinates(0,0),withawidthandheightof10pixelsby10pixels.Thisisthetop-leftsquareinFigure13-2.Thesecondtimearoundtheloop,wheniis1,thecoordinatesare(10,10)because1×10isequalto10.Thistime,thecodectx.fillRect(i*10,i*10,10,10)drawsasquareatthecoordinates(10,10),butthesquare’ssizeisstill10pixelsby10pixels(becausewe’renotchangingthewidthandheightarguments).ThisisthesecondsquaredowninFigure13-2.
Sinceiincrementsby1eachtimethroughtheloop,thex-andy-coordinateskeepincreasingby10pixelseachtimethroughtheloop,butthewidthandheightofthesquarestayfixedat10.Theremaining
sixsquaresaredrawnovertheremainingsixtimesaroundtheloop.
TRYITOUT!
Nowthatyouknowhowtodrawsquaresandrectanglesonthecanvas,trydrawingthislittlerobotusingthefillRectmethod.
Hint:You’llneedtodrawsixseparaterectangles.Imadetheheadusinga50-pixel-by-50-pixelrectangle.Theneck,arms,andlegsareall10pixelswide.
ChangingtheDrawingColorBydefault,whenyoucallfillRect,JavaScriptdrawsablackrectangle.Touseadifferentcolor,youcanchangethefillStylepropertyofthedrawingcontext.WhenyousetfillStyletoanewcolor,everythingyoudrawwillbedrawninthatcoloruntilyouchangefillStyleagain.TheeasiestwaytosetacolorforfillStyleistogiveitthenameofacolorasastring.Forexample:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
➊ctx.fillStyle="Red";
ctx.fillRect(0,0,100,100);
At➊wetellthedrawingcontextthateverythingwedrawfromnowonshouldbecoloredred.Runningthiscodeshoulddrawabrightredsquareonthescreen,asshowninFigure13-3.
Figure13-3.Aredsquare
NOTE
JavaScriptunderstandsmorethan100colornames,includingGreen,Blue,Orange,Red,Yellow,Purple,White,Black,Pink,Turquoise,Violet,SkyBlue,PaleGreen,Lime,Fuchsia,DeepPink,Cyan,andChocolate.You’llfindafulllistontheCSS-Trickswebsite:http://css-tricks.com/snippets/css/named-colors-and-hex-equivalents/.
TRYITOUT!
LookattheCSS-Trickswebsite(http://css-tricks.com/snippets/css/named-colors-and-hex-equivalents/)andchoosethreecolorsyoulike.Drawthreerectanglesusingthesecolors.Eachrectangleshouldbe50pixelswideand100pixelstall.Don’tincludeanyspacebetweenthem.Youshouldendupwithsomethinglikethis:
...althoughI’msureyoucanfindsomemoreinterestingcolorsthanred,green,andblue!
DrawingRectangleOutlinesAswe’veseen,thefillRectmethoddrawsafilled-inrectangle.That’sfineifthat’swhatyouwant,butsometimesyoumightwanttodrawjusttheoutline,asifyouwereusingapenorpencil.Todrawjusttheoutlineofarectangle,weusethestrokeRectmethod.(Thewordstrokeisanotherwordforoutline.)Forexample,runningthiscodeshoulddrawtheoutlineofsmallrectangle,asshowninFigure13-4:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
ctx.strokeRect(10,10,100,20);
Figure13-4.UsingstrokeRecttodrawtheoutlineofarectangle
ThestrokeRectmethodtakesthesameargumentsasfillRect:firstthex-andy-coordinatesofthetop-leftcorner,followedbythewidthandheightoftherectangle.Inthisexample,weseethatarectangleisdrawnstartingat10pixelsfromthetopleftofthecanvas,anditis100pixelswideby20pixelstall.UsethestrokeStylepropertytochangethecoloroftherectangle’soutline.Tochangethethicknessoftheline,usethelineWidthproperty.Forexample:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
➊ctx.strokeStyle="DeepPink";
➋ctx.lineWidth=4;
ctx.strokeRect(10,10,100,20);
Here,wesetthecolorofthelinetoDeepPinkat➊andthewidthofthelineto4pixelsat➋.Figure13-5showstheresultingrectangle.
Figure13-5.Adeeppinkrectanglewitha4-pixel-wideoutline
DrawingLinesorPathsLinesonthecanvasarecalledpaths.Todrawapathwiththecanvas,youusex-andy-coordinatestosetwhereeachlineshouldbeginandend.Byusingacarefulcombinationofstartingandstoppingcoordinates,youcandrawspecificshapesonthecanvas.Forexample,here’showyoumightdrawtheturquoiseXshowninFigure13-6:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
➊ctx.strokeStyle="Turquoise";
➋ctx.lineWidth=4;
➌ctx.beginPath();
➍ctx.moveTo(10,10);
➎ctx.lineTo(60,60);
➏ctx.moveTo(60,10);
➐ctx.lineTo(10,60);
➑ctx.stroke();
Figure13-6.AturquoiseX,drawnwithmoveToandlineTo
At➊and➋wesetthecolorandwidthoftheline.At➌wecallthebeginPathmethodonthedrawingcontext(savedasctx)totellthecanvasthatwewanttostartdrawinganewpath.At➍wecallthemoveTomethodwithtwoarguments:x-andy-coordinates.CallingmoveTopicksupourvirtualJavaScriptpenoffthecanvaspaperandmovesittothosecoordinateswithoutdrawingaline.Tostartdrawingaline,wecallthelineTomethodat➎withx-andy-coordinates,whichplacesthevirtualpenbackonthecanvasandtracesapathtothesenewcoordinates.Here,wedrawalinefromthepoint(10,10)tothepoint(60,60)—adiagonallinefromthetopleftofthecanvastothebottomright,formingthefirstlineoftheX.
At➏wecallmoveToagain,whichsetsanewlocationtodrawfrom.At➐wecalllineToagain,to
drawalinefrom(60,10)to(10,60)—adiagonallinefromthetoprightofthecanvastothebottomleft,completingtheXshape.Butwe’renotdoneyet!Sofarwe’veonlytoldthecanvaswhatwe’dliketodraw;wehaven’tactuallydrawnanything.Soat➑,wecallthestrokemethod,whichfinallymakesthelinesappearonthescreen.
TRYITOUT!
TrydrawingthishappystickmanusingthebeginPath,moveTo,lineTo,andstrokemethods.YoucanusethestrokeRectmethodforthehead.Theheadisa20-pixel-by-20-pixelsquare,andthelinewidthis4pixels.
FillingPathsSofarwe’velookedatstrokeRectfordrawingrectangleoutlines,fillRectforfillingrectangleswithcolor,andstrokeforoutliningapath.TheequivalentoffillRectforpathsiscalledfill.Tofillaclosedpathwithcolorinsteadofjustdrawinganoutline,youcanusethefillmethodinsteadofstroke.Forexample,youcouldusethiscodetodrawthesimpleskybluehouseshowninFigure13-7.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
ctx.fillStyle="SkyBlue";
ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(100,60);
ctx.lineTo(130,30);
ctx.lineTo(160,60);
ctx.lineTo(160,100);
ctx.lineTo(100,100);
➊ctx.fill();
Figure13-7.Askybluehouse,drawnwithapathandfilledwiththefillmethod
Here’showthiscodeworks.AftersettingourdrawingcolortoSkyBlue,webeginourpathwithbeginPathandthenmovetoourstartingpointof(100,100)usingmoveTo.NextwecalllineTofivetimesforeachcornerofthehouse,usingfivesetsofcoordinates.ThefinalcalltolineTocompletesthepathbygoingbacktothestartingpointof(100,100).Figure13-8showsthesamehouse,butwitheachcoordinatelabeled.
Figure13-8.ThehousefromFigure13-7withcoordinateslabeled
Finally,at➊wecallthefillmethod,whichfillsourpathwiththechosenfillcolor,SkyBlue.
DrawingArcsandCirclesInadditiontodrawingstraightlinesonthecanvas,youcanusethearcmethodtodrawarcsandcircles.Todrawacircle,yousetthecircle’scentercoordinatesandradius(thedistancebetweenthecircle’scenterandouteredge)andtellJavaScripthowmuchofthecircletodrawbyprovidingastartingangleandendingangleasarguments.Youcandrawafullcircle,orjustaportionofacircletocreateanarc.Thestartingandendinganglesaremeasuredinradians.Whenmeasuredinradians,afullcirclestartsat0(attherightsideofthecircle)andgoesuptoπ×2radians.Sotodrawafullcircle,youtellarctodrawfrom0radianstoπ×2radians.Figure13-9showsacirclelabeledwithradiansandtheirequivalentindegrees.Thevalues360°andπ×2radiansbothmeanafullcircle.
Figure13-9.Degreesandradians,startingfromtherightsideofthecircleandmovingclockwise
Forexample,thefollowingcodewillcreateaquartercircle,ahalfcircle,andafullcircle,asshowninFigure13-10.
ctx.lineWidth=2;
ctx.strokeStyle="Green";
ctx.beginPath();
➊ctx.arc(50,50,20,0,Math.PI/2,false);
ctx.stroke();
ctx.beginPath();
➋ctx.arc(100,50,20,0,Math.PI,false);
ctx.stroke();
ctx.beginPath();
➌ctx.arc(150,50,20,0,Math.PI*2,false);
ctx.stroke();
Figure13-10.Drawingaquartercircle,ahalfcircle,andafullcircle
We’llgooverallthreeshapesinthefollowingsections.
DrawingaQuarterCircleoranArcThefirstblockofcodedrawsaquartercircle.At➊,aftercallingbeginPath,wecallthearcmethod.Wesetthecenterofthecircleatthepoint(50,50)andtheradiusto20pixels.Thestartingangleis0(whichdrawsthearcstartingfromtherightofthecircle),andtheendingangleisMath.PI/2.Math.PIishowJavaScriptreferstothenumberπ(pi).Becauseafullcircleisπ×2radians,πradiansmeansahalfcircle,andπ÷2radians(whichwe’reusingforthisfirstarc)givesusaquartercircle.Figure13-11showsthestartandendangles.
Figure13-11.Thestartangle(0radians,or0°)andendangle(π÷2radians,or90°)ofthequarter-circle
Wepassfalseforthefinalargument,whichtellsarctodrawinaclockwisedirection.Ifyouwanttodrawinacounterclockwisedirection,passtrueforthisfinalargument.
DrawingaHalfCircleNextwedrawahalfcircle.Thearcat➋hasacenterat(100,50),whichplacesit50pixelstotherightofthefirstarc,whichwasat(50,50).Theradiusisagain20pixels.Wealsostartat0radiansagain,butthistimeweendatMath.PI,drawingahalfcircle.Figure13-12showsthestartandendangles.
Figure13-12.Thestartangle(0radians,or0°)andendangle(πradians,or180°)ofthehalfcircle
DrawingaFullCircleAt➌wedrawafullcircle.Thecenterisat(150,50),andtheradiusis20pixels.Forthiscircle,westartthearcat0radiansandenditatMath.PI*2radians,drawingafullcircle.Figure13-13showsthestartandendangles.
Figure13-13.Thestartangle(0radians,or0°)andendangle(π×2radians,or360°)ofthefullcircle
DrawingLotsofCircleswithaFunctionIfyoujustwanttodrawcircles,thearcmethodisabitcomplicated.Forcircles,you’realwaysgoingtowanttostartthearcat0andendatπ×2,andthedirection(clockwiseorcounterclockwise)doesn’tmatter.Also,toactuallydrawthecircleyoualwaysneedtocallctx.beginPathandctx.strokebeforeandaftercallingthearcmethod.Wecanmakeafunctiontodrawcirclesthatletsusignorethosedetailssothatwehavetosupplyonlythex,y,andradiusarguments.Let’sdothatnow.
varcircle=function(x,y,radius){
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
ctx.stroke();
};
Aswiththearcmethod,insidethisfunctionthefirstthingwehavetodoiscallctx.beginPathtotellthecanvaswewanttodrawapath.Then,wecallctx.arc,passingthex,y,andradiusvariablesfromthefunctionarguments.Asbefore,weuse0forthestartangle,Math.PI*2fortheendangle,andfalsetodrawthecircleclockwise.Nowthatwehavethisfunction,wecandrawlotsofcirclessimplybyfillinginthecentercoordinatesandradiusasarguments.Forexample,thiscodewoulddrawsomecolorfulconcentriccircles:
ctx.lineWidth=4;
ctx.strokeStyle="Red";
circle(100,100,10);
ctx.strokeStyle="Orange";
circle(100,100,20);
ctx.strokeStyle="Yellow";
circle(100,100,30);
ctx.strokeStyle="Green";
circle(100,100,40);
ctx.strokeStyle="Blue";
circle(100,100,50);
ctx.strokeStyle="Purple";
circle(100,100,60);
YoucanseewhatthisshouldlooklikeinFigure13-14.First,wesetthelinewidthtoathick4pixels.ThenwesetthestrokeStyleto"Red"andusethecirclefunctiontodrawacircleatthecoordinates(100,100),witharadiusof10pixels.Thisistheredcenterring.
Figure13-14.Colorfulconcentriccircles,drawnusingourcirclefunction
Wethenusethesametechniquetodrawanorangecircleatthesamelocationbutwitharadiusof20pixels;wefollowthatwithayellowcircle,againinthesamelocationbutwitharadiusof30pixels.Thelastthreecirclesarealsointhesamelocation,butwithincreasinglylargerradiiandingreen,blue,andpurple.
TRYITOUT!
Howwouldyoumodifyourcirclefunctiontomakeitfillthecircleinsteadofoutlineit?Addafourthargument,aBoolean,thatsayswhetherthecircleshouldbefilledoroutlined.Passingtrueindicatesthatyouwantthecircletobefilled.YoucancalltheargumentfillCircle.
Usingyourmodifiedfunction,drawthissnowman,usingamixofoutlinedandfilledcircles.
WhatYouLearnedInthischapter,youlearnedaboutanewHTMLelementcalledcanvas.Usingthecanvas’sdrawingcontext,wecaneasilydrawrectangles,lines,andcircles,withfullcontrolovertheirlocation,linewidth,color,andsoon.Inthenextchapter,we’lllearnhowtoanimateourdrawings,usingsomeofthetechniqueswelearnedinChapter9.
ProgrammingChallengesTrythesechallengestopracticedrawingtothecanvas.#1:ASNOWMAN-DRAWINGFUNCTIONBuildingonyourcodefordrawingasnowman(Figure13-14),writeafunctionthatdrawsasnowmanataspecifiedlocation,sothatcallingthis...
drawSnowman(50,50);
woulddrawasnowmanatthepoint(50,50).#2:DRAWINGANARRAYOFPOINTSWriteafunctionthatwilltakeanarrayofpointslikethis:
varpoints=[[50,50],[50,100],[100,100],[100,50],
[50,50]];
drawPoints(points);
anddrawalineconnectingthepoints.Inthisexample,thefunctionwoulddrawalinefrom(50,50)to(50,100)to(100,100)to(100,50)andbackto(50,50).Nowusethisfunctiontodrawthefollowingpoints:
varmysteryPoints=[[50,50],[50,100],[25,120],
[100,50],[70,90],[100,90],[70,120]];
drawPoints(mysteryPoints);
Hint:Youcanusepoints[0][0]togetthefirstx-coordinateandpoints[0][1]togetthefirsty-coordinate.#3:PAINTINGWITHYOURMOUSEUsingjQueryandthemousemoveevent,drawafilledcirclewitharadiusof3pixelsatthemousepositionwheneveryoumoveyourmouseoverthecanvas.Becausethiseventistriggeredbyeverytinymovementofthemouse,thesecircleswilljoinintoalineasyoumovethemouseoverthecanvas.Hint:RefertoChapter10forareminderofhowtorespondtomousemoveevents.#4:DRAWINGTHEMANINHANGMANInChapter7wecreatedourownversionofthegameHangman.Nowyoucanmakeitclosertotherealgamebydrawingpartofastickmaneverytimetheplayergetsaletterwrong.
Hint:Keeptrackofthenumberoftimestheplayerhasguessedincorrectly.Writeafunctionthattakesthisnumberasanargumentanddrawsadifferentpartofthebodydependingonthenumberpassedin.
Chapter14.MakingThingsMoveontheCanvasCreatingcanvasanimationsinJavaScriptisalotlikecreatingastop-motionanimation.Youdrawashape,pause,erasetheshape,andthenredrawitinanewposition.Thismaysoundlikealotofsteps,butJavaScriptcanupdatethepositionoftheshapeveryquicklyinordertocreateasmoothanimation.InChapter10,welearnedhowtoanimateDOMelements.Inthischapter,we’llanimateourcanvasdrawings.
MovingAcrossthePageLet’susecanvasandsetIntervaltodrawasquareandmoveitslowlyacrossapage.Createanewfilecalledcanvasanimation.htmlandaddthefollowingHTML:
<!DOCTYPEhtml>
<html>
<head>
<title>CanvasAnimation</title>
</head>
<body>
<canvasid="canvas"width="200"height="200"></canvas>
<script>
//We'llfillthisinnext
</script>
</body>
</html>
NowaddthefollowingJavaScripttothescriptelement:varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varposition=0;
setInterval(function(){
➊ctx.clearRect(0,0,200,200);
➋ctx.fillRect(position,0,20,20);
➌position++;
➍if(position>200){
position=0;
}
➎},30);
Thefirsttwolinesinthiscodecreatethecanvasandthecontext.Next,wecreatethevariablepositionandsetitto0,withthecodevarposition=0.We’llusethisvariabletocontroltheleft-to-rightmovementofthesquare.NowwecallsetIntervaltostartouranimation.ThefirstargumenttosetIntervalisafunction,whichdrawsanewsquareeachtimeit’scalled.
ClearingtheCanvasInsidethefunctionwepassedtosetInterval,wecallclearRectat➊,whichclearsarectangularareaonthecanvas.TheclearRectmethodtakesfourarguments,whichsetthepositionandsizeoftherectangletobecleared.AswithfillRect,thefirsttwoargumentsrepresentthex-andy-coordinatesofthetop-leftcorneroftherectangle,andthelasttworepresentthewidthandheight.Callingctx.clearRect(0,0,200,200)erasesa200-by-200-pixelrectangle,startingattheverytop-leftcornerofthecanvas.Becauseourcanvasisexactly200by200pixels,thiswillcleartheentirecanvas.
DrawingtheRectangleOncewe’veclearedthecanvas,at➋weusectx.fillRect(position,0,20,20)todrawa20-pixelsquareatthepoint(position,0).Whenourprogramstarts,thesquarewillbedrawnat(0,0)becausepositionstartsoffsetto0.
ChangingthePositionNext,weincreasepositionby1,usingposition++at➌.Thenat➍weensurethatpositiondoesn’tgetlargerthan200withthecheckif(position>200).Ifitis,weresetitto0.
ViewingtheAnimationintheBrowserWhenyouloadthispageinyourbrowser,setIntervalwillcallthesuppliedfunctiononceevery30milliseconds,orabout33timesasecond(thistimeintervalissetbythesecondargumenttosetInterval,at➎).Eachtimethesuppliedfunctioniscalled,itclearsthecanvas,drawsasquareat(position,0),andincrementsthevariableposition.Asaresult,thesquaregraduallymovesacrossthecanvas.Whenthesquarereachestheendofthecanvas(200pixelstotheright),itspositionisresetto0.Figure14-1showsthefirstfourstepsoftheanimation,zoomedintothetop-leftcornerofthecanvas.
Figure14-1.Aclose-upofthetop-leftcornerofthecanvasforthefirstfourstepsoftheanimation.Ateachstep,positionisincrementedby1andthesquaremoves1pixeltotheright.
AnimatingtheSizeofaSquareBymakingonlythreechangestothecodeintheprevioussection,wecancreateasquarethatgrowslargerinsteadofmoving.Here’swhatthatcodewouldlooklike:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varsize=0;
setInterval(function(){
ctx.clearRect(0,0,200,200);
ctx.fillRect(0,0,size,size);
size++;
if(size>200){
size=0;
}
},30);
Asyoucansee,we’vedonetwothings.First,insteadofapositionvariable,wenowhaveavariablenamedsize,whichwillcontrolthedimensionsofthesquare.Second,insteadofusingthisvariabletosetthesquare’shorizontalposition,we’reusingittosetthesquare’swidthandheightwiththecodectx.fillRect(0,0,size,size).Thiswilldrawasquareatthetop-leftcornerofthecanvas,withthewidthandheightbothsettomatchsize.Becausesizestartsat0,thesquarewillstartoutinvisible.Thenexttimethefunctioniscalled,sizewillbe1,sothesquarewillbe1pixelwideandtall.Eachtimethesquareisdrawn,itgrowsapixelwiderandapixeltaller.Whenyourunthiscode,youshouldseeasquareappearatthetop-leftcornerofthecanvasandgrowuntilitfillstheentirecanvas.Onceitfillstheentirecanvas—thatis,if(size>200)—thesquarewilldisappearandstartgrowingagainfromthetop-leftcorner.
Figure14-2showsaclose-upofthetop-leftcornerofthecanvasforthefirstfourstepsofthisanimation.
Figure14-2.Ineachstepofthisanimation,sizeisincrementedby1andthewidthandheightofthesquaregrowby1pixel.
ARandomBeeNowthatweknowhowtomoveandgrowobjectsonourscreen,let’strysomethingabitmorefun.Let’smakeabeethatfliesrandomlyaroundthecanvas!We’lldrawourbeeusinganumberofcircles,likethis:
Theanimationwillworkverysimilarlytothemovingsquareanimation:we’llsetaposition,andthenforeverystepoftheanimation,we’llclearthecanvas,drawthebeeatthatposition,andmodifytheposition.Thedifferenceisthattomakethebeemoverandomly,we’llneedtousemorecomplexlogicforupdatingthebee’spositionthanweusedforthesquareanimation.We’llbuildupthecodeforthisanimationinafewsections.
ANewcircleFunctionWe’lldrawourbeeusingafewcircles,sofirstwe’llmakeacirclefunctiontofilloroutlinecircles:
varcircle=function(x,y,radius,fillCircle){
ctx.beginPath();
➊ctx.arc(x,y,radius,0,Math.PI*2,false);
➋if(fillCircle){
➌ctx.fill();
}else{
➍ctx.stroke();
}
};
Thefunctiontakesfourarguments:x,y,radius,andfillCircle.WeusedasimilarcirclefunctioninChapter13,butherewe’veaddedfillCircleasanextraargument.Whenwecallthisfunction,thisargumentshouldbesettotrueorfalse,whichdetermineswhetherthefunctiondrawsafilledcircleorjustanoutline.Insidethefunction,weusethearcmethodat➊tocreatethecirclewithitscenterattheposition(x,y)andaradiusofradius.Afterthis,wechecktoseeifthefillCircleargumentistrueat➋.Ifitistrue,wefillthecircleusingctx.fillat➌.Otherwise,weoutlinethecircleusingctx.strokeat➍.
DrawingtheBeeNext,wecreatethedrawBeefunctiontodrawthebee.ThedrawBeefunctionusesthecirclefunctiontodrawabeeatthecoordinatesspecifiedbyitsxandyarguments.Itlookslikethis:
vardrawBee=function(x,y){
➊ctx.lineWidth=2;
ctx.strokeStyle="Black";
ctx.fillStyle="Gold";
➋circle(x,y,8,true);
circle(x,y,8,false);
circle(x-5,y-11,5,false);
circle(x+5,y-11,5,false);
circle(x-2,y-1,2,false);
circle(x+2,y-1,2,false);
};
Inthefirstsectionofthiscodeat➊,wesetthelineWidth,strokeStyle,andfillStylepropertiesforourdrawing.WesetthelineWidthto2pixelsandthestrokeStyletoBlack.Thismeansthatouroutlinedcircles,whichwe’lluseforthebee’sbody,wings,andeyes,willhavethickblackborders.ThefillStyleissettoGold,whichwillfillthecircleforourbeebodywithaniceyellowcolor.Inthesecondsectionofthecodeat➋,wedrawaseriesofcirclestocreateourbee.Let’sgothroughthoseoneatatime.Thefirstcircledrawsthebee’sbodyusingafilledcirclewithacenteratthepoint(x,y)andaradiusof8pixels:
circle(x,y,8,true);
BecausewesetthefillStyletoGold,thiscirclewillbefilledinwithyellowlikeso:
Thissecondcircledrawsablackoutlinearoundthebee’sbodythat’sthesamesizeandinthesameplaceasthefirstcircle:
circle(x,y,8,false);
Addedtothefirstcircle,itlookslikethis:
Next,weusecirclestodrawthebee’swings.Thefirstwingisanoutlinedcirclewithitscenter5pixelstotheleftand11pixelsabovethecenterofthebody,witharadiusof5pixels.Thesecondwingisthesame,exceptit’s5pixelstotherightofthebody’scenter.
circle(x-5,y-11,5,false);
circle(x+5,y-11,5,false);
Withthosecirclesadded,ourbeelookslikethis:
Finally,wedrawtheeyes.Thefirstoneis2pixelstotheleftofthecenterofthebodyand1pixelabove,witharadiusof2pixels.Thesecondoneisthesame,exceptit’s2pixelsrightofcenter.
circle(x-2,y-1,2,false);
circle(x+2,y-1,2,false);
Together,thesecirclescreateabee,withitsbodycenteredaroundthe(x,y)coordinatepassedintothedrawBeefunction.
UpdatingtheBee’sLocationWe’llcreateanupdatefunctiontorandomlychangethebee’sx-andy-coordinatesinordertomakeitappeartobuzzaroundthecanvas.Theupdatefunctiontakesasinglecoordinate;weupdatethex-andy-coordinatesoneatatimesothatthebeewillmoverandomlyleftandrightandupanddown.Theupdatefunctionlookslikethis:
varupdate=function(coordinate){
➊varoffset=Math.random()*4-2;
➋coordinate+=offset;
➌if(coordinate>200){
coordinate=200;
}
➍if(coordinate<0){
coordinate=0;
}
➎returncoordinate;
};
ChangingtheCoordinatewithanOffsetValueAt➊,wecreateavariablecalledoffset,whichwilldeterminehowmuchtochangethecurrentcoordinate.WegeneratetheoffsetvaluebycalculatingMath.random()*4-2.Thiswillgiveusarandomnumberbetween–2and2.Here’show:callingMath.random()onitsowngivesusarandomnumberbetween0and1,soMath.random()*4producesarandomnumberbetween0and4.Thenwesubtract2togetarandomnumberbetween–2and2.At➋weusecoordinate+=offsettomodifyourcoordinatewiththisoffsetnumber.Ifoffsetisapositivenumber,coordinatewillincrease,andifit’sanegativenumber,coordinatewilldecrease.Forexample,ifcoordinateissetto100andoffsetis1,thenafterwerunthelineat➋,coordinatewillbe101.However,ifcoordinateis100andoffsetis-1,thiswouldchangecoordinateto99.
CheckingiftheBeeReachestheEdgeAt➌and➍wepreventthebeefromleavingthecanvasbymakingsurecoordinateneverincreasesabove200orshrinksbelow0.Ifcoordinategetsbiggerthan200,wesetitbackto200,andifitgoesbelow0,weresetitto0.
ReturningtheUpdatedCoordinateFinally,at➎wereturncoordinate.Returningthenewvalueofcoordinateletsususethatvaluein
therestofourcode.Laterwe’llusethisreturnvaluefromtheupdatemethodtomodifythexandyvalueslikethis:
x=update(x);
y=update(y);
AnimatingOurBuzzingBeeNowthatwehavethecircle,drawBee,andupdatefunctions,wecanwritetheanimationcodeforourbuzzingbee.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varx=100;
vary=100;
setInterval(function(){
➊ctx.clearRect(0,0,200,200);
➋drawBee(x,y);
➌x=update(x);
y=update(y);
➍ctx.strokeRect(0,0,200,200);
},30);
Asusual,westartwiththevarcanvasandvarctxlinestogetthedrawingcontext.Next,wecreatethevariablesxandyandsetbothto100.Thissetsthebee’sstartingpositionatthepoint(100,100),whichputsitinthemiddleofthecanvas,asshowninFigure14-3.NextwecallsetInterval,passingafunctiontocallevery30milliseconds.Insidethisfunction,thefirstthingwedoiscallclearRectat➊toclearthecanvas.Next,at➋wedrawthebeeatthepoint(x,y).Thefirsttimethefunctioniscalled,thebeeisdrawnatthepoint(100,100),asyoucanseeinFigure14-3,andeachtimethefunctioniscalledafterthat,itwilldrawthebeeatanew,updated(x,y)position.Nextweupdatethexandyvaluesstartingat➌.Theupdatefunctiontakesanumber,addsarandomnumberbetween–2and2toit,andreturnsthatupdatednumber.Sothecodex=update(x)basicallymeans“changexbyasmall,randomamount.”
Figure14-3.Thebeedrawnatthepoint(100,100)
Finally,wecallstrokeRectat➍todrawalinearoundtheedgeofthecanvas.Thismakesiteasierforustoseewhenthebeeisgettingclosetoit.Withouttheborder,theedgeofthecanvasisinvisible.Whenyourunthiscode,youshouldseetheyellowbeerandomlybuzzaroundthecanvas.Figure14-4showsafewframesfromouranimation.
Figure14-4.Therandombeeanimation
BouncingaBall!Nowlet’smakeaballthatbouncesaroundthecanvas.Whenevertheballhitsoneofthewalls,itwillbounceoffatanangle,asarubberballwould.First,we’llcreateaJavaScriptobjecttorepresentourballwithaBallconstructor.Thisobjectwillstoretheball’sspeedanddirectionusingtwoproperties,xSpeedandySpeed.Theball’shorizontalspeedwillbecontrolledbyxSpeed,andtheverticalspeedwillbecontrolledbyySpeed.We’llmakethisanimationinanewfile.CreateanewHTMLfilecalledball.html,andaddthefollowingHTML:
<!DOCTYPEhtml>
<html>
<head>
<title>ABouncingBall</title>
</head>
<body>
<canvasid="canvas"width="200"height="200"></canvas>
<script>
//We'llfillthisinnext
</script>
</body>
</html>
TheBallConstructorFirstwe’llcreatetheBallconstructor,whichwe’llusetocreateourbouncingball.Typethefollowingcodeintothe<script>tagsinball.html:
varBall=function(){
this.x=100;
this.y=100;
this.xSpeed=-2;
this.ySpeed=3;
};
Ourconstructorisverystraightforward:itsimplysetsthestartingpositionoftheball(this.xandthis.y),theball’shorizontalspeed(this.xSpeed),anditsverticalspeed(this.ySpeed).Wesetthestartingpositiontothepoint(100,100),whichisthecenterofour200-by-200-pixelcanvas.this.xSpeedissetto-2.Thiswillmaketheballmove2pixelstotheleftforeverystepoftheanimation.this.ySpeedissetto3.Thiswillmaketheballmove3pixelsdownforeverystepoftheanimation.Therefore,theballwillmovediagonallydown(3pixels)andtotheleft(2pixels)betweeneveryframe.Figure14-5showsthestartingpositionoftheballanditsdirectionofmovement.
Figure14-5.Thestartingpositionoftheball,withanarrowindicatingitsdirection
DrawingtheBallNextwe’lladdadrawmethodtodrawtheball.We’lladdthismethodtotheBallprototypesothatanyobjectscreatedbytheBallconstructorcanuseit:
varcircle=function(x,y,radius,fillCircle){
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
if(fillCircle){
ctx.fill();
}else{
ctx.stroke();
}
};
Ball.prototype.draw=function(){
circle(this.x,this.y,3,true);
};
Firstweincludeourcirclefunction,thesameoneweusedearlierinANewcircleFunction.WethenaddthedrawmethodtoBall.prototype.Thismethodsimplycallscircle(this.x,this.y,3,true)todrawacircle.Thecircle’scenterwillbeat(this.x,this.y):thelocationoftheball.Itwillhavearadiusof3pixels.Wepasstrueasthefinalargumenttotellthecirclefunctiontofillthecircle.
MovingtheBallTomovetheball,wejusthavetoupdatethexandypropertiesbasedonthecurrentspeed.We’lldothatusingthefollowingmovemethod:
Ball.prototype.move=function(){
this.x+=this.xSpeed;
this.y+=this.ySpeed;
};
Weusethis.x+=this.xSpeedtoaddthehorizontalspeedoftheballtothis.x.Thenthis.y+=this.ySpeedaddstheverticalspeedtothis.y.Forexample,atthebeginningoftheanimation,theballwillbeatthepoint(100,100),withthis.xSpeedsetto-2andthis.ySpeedsetto3.Whenwecallthemovemethod,itsubtracts2fromthexvalueandadds3totheyvalue,whichplacestheballatthepoint(98,103).Thismovestheball’slocationtotheleft2pixelsanddown3pixels,asillustratedinFigure14-6.
Figure14-6.Thefirstthreestepsoftheanimation,showinghowthexandypropertieschange
BouncingtheBallAteverystepoftheanimation,wechecktoseeiftheballhashitoneofthewalls.Ifithas,weupdatethexSpeedorySpeedpropertybynegatingit(multiplyingitby–1).Forexample,iftheballhitsthebottomwall,wenegatethis.ySpeed.Soifthis.ySpeedis3,negatingitwillmakeit-3.Ifthis.ySpeedis-3,negatingitwillsetitbackto3.
We’llcallthismethodcheckCollision,becauseitcheckstoseeiftheballhascollidedwith(hit)thewall.
Ball.prototype.checkCollision=function(){
➊if(this.x<0||this.x>200){
this.xSpeed=-this.xSpeed;
}
➋if(this.y<0||this.y>200){
this.ySpeed=-this.ySpeed;
}
};
At➊,wedeterminewhethertheballhashittheleftwallortherightwallbycheckingtoseeifitsxpropertyiseitherlessthan0(meaningithittheleftedge)orgreaterthan200(meaningithittherightedge).Ifeitheroftheseistrue,theballhasstartedtomoveofftheedgeofthecanvas,sowehavetoreverseitshorizontaldirection.Wedothisbysettingthis.xSpeedequalto-this.xSpeed.Forexample,ifthis.xSpeedwas-2andtheballhittheleftwall,this.xSpeedwouldbecome2.At➋,wedothesamethingforthetopandbottomwalls.Ifthis.yislessthan0orgreaterthan200,weknowtheballhashitthetopwallorthebottomwall,respectively.Inthatcase,wesetthis.ySpeedtobeequalto-this.ySpeed.Figure14-7showswhathappenswhentheballhitstheleftwall.this.xSpeedstartsas-2,butafterthecollisionitischangedto2.However,this.ySpeedremainsunchangedat3.
Figure14-7.Howthis.xSpeedchangesafteracollisionwiththeleftwall
AsyoucanseeinFigure14-7,inthiscasethecenteroftheballgoesofftheedgeofthecanvasatstep3whenitcollideswithawall.Duringthatstep,partoftheballwilldisappear,butthishappenssoquicklythatit’sbarelynoticeablewhentheanimationisrunning.
AnimatingtheBallNowwecanwritethecodethatgetstheanimationrunning.Thiscodesetsuptheobjectthatrepresentstheball,anditusessetIntervaltocallthemethodsthatdrawandupdatetheballforeachanimationstep.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
➊varball=newBall();
➋setInterval(function(){
➌ctx.clearRect(0,0,200,200);
➍ball.draw();
ball.move();
ball.checkCollision();
➎ctx.strokeRect(0,0,200,200);
➏},30);
Wegetthecanvasanddrawingcontextasusualonthefirsttwolines.ThenwecreateaballobjectusingnewBall()andsaveitinthevariableballat➊.Next,wecallsetIntervalat➋,passingafunctionandthenumber30at➏.Asyou’veseenbefore,thismeans“callthisfunctionevery30milliseconds.”
ThefunctionwepasstosetIntervaldoesseveralthings.First,itclearsthecanvas,usingctx.clearRect(0,0,200,200)at➌.Afterthis,itcallsthedraw,move,andcheckCollisionmethodsat➍ontheballobject.Thedrawmethoddrawstheballatitscurrentx-andy-coordinates.ThemovemethodupdatesthepositionoftheballbasedonitsxSpeedandySpeedproperties.Finally,thecheckCollisionmethodupdatesthedirectionoftheball,ifithitsawall.ThelastthingwedointhefunctionpassedtosetIntervaliscallctx.strokeRect(0,0,200,200)at➎todrawalinearoundtheedgeofthecanvas,sowecanseethewallstheballishitting.Whenyourunthiscode,theballshouldimmediatelystartmovingdownandtotheleft.Itshouldhitthebottomwallfirst,andbounceupandtotheleft.Itwillcontinuetobouncearoundthecanvasaslongasyouleavethebrowserwindowopen.
WhatYouLearnedInthischapter,wecombinedourknowledgeofanimationfromChapter11withourknowledgeofthecanvaselementtocreatevariouscanvas-basedanimations.Webegansimplybymovingandgrowingsquaresonthecanvas.Next,wemadeabeebuzzrandomlyaroundthescreen,andweendedwithananimationofabouncingball.Alloftheseanimationsworkinbasicallythesameway:wedrawashapeofaparticularsizeinaparticularposition,thenweupdatethatsizeorposition,andthenweclearthecanvasanddrawtheshapeagain.Forelementsmovingarounda2Dcanvas,wegenerallyhavetokeeptrackofthex-andy-coordinatesoftheelement.Forthebeeanimation,weaddedorsubtractedarandomnumberfromthex-andy-coordinates.Forthebouncingball,weaddedthecurrentxSpeedandySpeedtothex-andy-coordinates.Inthenextchapter,we’lladdinteractivitytoourcanvas,whichwillletuscontrolwhat’sdrawntothecanvasusingthekeyboard.
ProgrammingChallengesHerearesomewaysyoucanbuildonthebouncingballanimationfromthischapter.#1:BOUNCINGTHEBALLAROUNDALARGERCANVASOur200-by-200-pixelcanvasisabitsmall.Whatifyouwantedtoincreasethecanvassizeto400by400pixelsorsomeotherarbitrarysize?Insteadofenteringthewidthandheightofthecanvasmanuallythroughoutyourprogram,youcancreatewidthandheightvariablesandsetthevariablesusingthecanvasobject.Usethefollowingcode:
varwidth=canvas.width;
varheight=canvas.height;
Nowifyouusethesevariablesthroughoutyourprogram,youonlyhavetochangethepropertiesonthecanvaselementintheHTMLifyouwanttotryoutanewsize.Trychangingthesizeofthecanvasto500pixelsby300pixels.Doesyourprogramstillwork?#2:RANDOMIZINGTHIS.XSPEEDANDTHIS.YSPEEDTomaketheanimationmoreinteresting,setthis.xSpeedandthis.ySpeedtodifferentrandomnumbers(between–5and5)intheBallconstructor.#3:ANIMATINGMOREBALLSInsteadofcreatingjustoneball,createanemptyarrayofballs,anduseaforlooptoadd10ballstothearray.Now,inthesetIntervalfunction,useaforlooptodraw,move,andcheckcollisionsoneachoftheballs.#4:MAKINGTHEBALLSCOLORFULHowaboutmakingsomecoloredbouncingballs?SetanewpropertyintheBallconstructorcalledcoloranduseitinthedrawmethod.UsethepickRandomWordfunctionfromChapter8togiveeachballarandomcolorfromthisarray:
varcolors=["Red","Orange","Yellow","Green","Blue",
"Purple"];
Chapter15.ControllingAnimationswiththeKeyboardNowthatyouknowhowtoworkwiththecanvas;drawandcolorobjects;andmakeobjectsmove,bounce,andgrowinsize,let’sliventhingsupbyaddingsomeinteractivity!Inthischapter,you’lllearnhowtomakeyourcanvasanimationsrespondwhenauserpressesakeyonthekeyboard.Thisway,aplayercancontrolananimationbypressinganarrowkeyoroneofafewassignedlettersontheirkeyboard(liketheclassicW,A,S,Dgamecontrols).Forexample,insteadofjusthavingaballbounceacrossascreen,wecanhaveaplayercontrolthemovementoftheballusingthearrowkeys.
KeyboardEventsJavaScriptcanmonitorthekeyboardthroughkeyboardevents.Eachtimeauserpressesakeyonthekeyboard,theygenerateakeyboardevent,whichisalotlikethemouseeventswesawinChapter10.Withmouseevents,weusedjQuerytodeterminewherethecursorwaswhentheeventtookplace.Withkeyboardevents,youcanusejQuerytodeterminewhichkeywaspressedandthenusethatinformationinyourcode.Forexample,inthischapterwe’llmakeaballmoveleft,right,up,ordownwhentheuserpressestheleft,right,up,ordownarrowkey.We’llusethekeydownevent,whichistriggeredwheneverauserpressesakey,andwe’llusejQuerytoaddaneventhandlertothekeydownevent.Thatway,everytimeakeydowneventoccurs,oureventhandlerfunctioncanfindoutwhichkeywaspressedandrespondaccordingly.
SettingUptheHTMLFileTobegin,createacleanHTMLfilecontainingthefollowingcodeandsaveitaskeyboard.html.
<!DOCTYPEhtml>
<html>
<head>
<title>Keyboardinput</title>
</head>
<body>
<canvasid="canvas"width="400"height="400"></canvas>
<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
<script>
//We'llfillthisinnext
</script>
</body>
</html>
AddingthekeydownEventHandlerNowlet’saddsomeJavaScripttorespondtokeydownevents.Enterthiscodeinsidetheempty<script>tagsinyourkeyboard.htmlfile.
$("body").keydown(function(event){
console.log(event.keyCode);
});
Inthefirstline,weusethejQuery$functiontoselectthebodyelementinourHTMLandthencallthekeydownmethod.Theargumenttothekeydownmethodisafunctionthatwillbecalledwheneverakeyispressed.Informationaboutthekeydowneventispassedintothefunctionthroughtheeventobject.Forthisprogram,wewanttoknowwhichkeywaspressed,andthatinformationisstoredintheeventobjectasevent.keyCode.Insidethefunction,weuseconsole.logtooutputtheeventobject’skeyCodeproperty:anumberrepresentingthepressedkey.Eachkeyonyourkeyboardhasauniquekeycode.Forexample,thekeycodeforthespacebaris32,andtheleftarrowis37.Onceyou’veeditedyourkeyboard.htmlfile,saveitandthenopenitinabrowser.Nowopentheconsolesoyoucanseetheoutput,andclickinthemainbrowserwindowtohaveJavaScriptregisteryourkeypresses.Now,ifyoustartpressingkeys,thecorrespondingkeycodesshouldbeprintedtotheconsole.
Forexample,ifyoutypehithere,youshouldseethefollowingoutputintheconsole:72
73
32
84
72
69
82
69
Everykeyyoupresshasadifferentkeycode.TheHkeyis72,theIkeyis73,andsoon.
TRYITOUT!
Pressvariouskeystoseetheirkeycodes.Whatarethekeycodesfortheup,down,left,andrightarrows?WhataboutSHIFTandENTER?Thenumberandletterkeyseachhavetheirownkeycodestoo.
UsinganObjecttoConvertKeycodesintoNamesTomakeiteasiertoworkwithkeys,we’lluseanobjecttoconvertthekeycodesintonamessothatthekeypresseswillbeeasiertorecognize.Inthisnextexample,wecreateanobjectcalledkeyNames,wheretheobjectkeysarekeycodesandthevaluesarethenamesofthosekeys.DeletetheJavaScriptinkeyboard.htmlandreplaceitwiththis:
varkeyNames={
32:"space",
37:"left",
38:"up",
39:"right",
40:"down"
};
$("body").keydown(function(event){
➊console.log(keyNames[event.keyCode]);
});
First,wecreatethekeyNamesobjectandfillitwiththekeycodes32,37,38,39,and40.ThekeyNamesobjectuseskey-valuepairstomatchkeycodes(suchas32,37,andsoon)withcorrespondinglabels(suchas"space"forthespacebarand"left"fortheleftarrow).Wecanthenusethisobjecttofindoutthenameofakeybasedonitskeycode.Forexample,tolookupthekeycode32,enterkeyNames[32].Thatreturnsthestring"space".At➊,weusethekeyNamesobjectinthekeydowneventhandlertogetthenameofthekeythatwasjustpressed.Iftheeventkeycodereferencedbyevent.keyCodematchesoneofthekeysinthekeyNamesobject,thisfunctionwilllogthenameofthatkey.Ifnokeymatches,thiscodewilllogundefined.Loadkeyboard.htmlinyourbrowser.Opentheconsole,clickinthemainbrowserwindow,andtrypressingafewkeys.IfyoupressoneofthefivekeysinthekeyNameobject(thearrowkeysorspacebar),theprogramshouldprintthenameofthekey.Otherwise,itwillprintundefined.
TRYITOUT!
Addmorekey-valuepairstothekeyNamesobjectsothatitcanconvertmorekeystonames.InsertthekeycodesandnamesforSHIFT,ENTER/RETURN,andALT/OPTION.
MovingaBallwiththeKeyboardNowthatwecandeterminewhichkeyisbeingpressed,wecanwriteaprogramtousethekeyboardtocontrolthemovementofaball.Ourprogramwilldrawaballandmoveittotheright.Pressingthearrowkeyswillchangetheball’sdirection,andpressingthespacebarwillstopit.Iftheballgoesofftheedgeofthecanvas,itwillwraparoundtotheoppositeside.Forexample,iftheballgoesofftherightedgeofthecanvas,itwillshowupagainontheleftedgewhilecontinuingtomoveinthesamedirection,asshowninFigure15-1.
Figure15-1.Iftheballmovesofftherightsideofthecanvas,itwillreappearontheleft.
We’lluseanobjectcalledkeyActionstofindoutwhichkeywaspressedandthenusethatinformationtosetthedirectionoftheball’smovement.We’llusesetIntervaltocontinuallyupdatetheball’spositionandredrawitatitsnewposition.
SettingUptheCanvasFirstweneedtosetupthecanvasandthecontextobject.Openkeyboard.htmlandreplacetheJavaScriptbetweenthesecondsetof<script>tagswiththiscode:
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varwidth=canvas.width;
varheight=canvas.height;
Onthefirstline,weusedocument.getElementByIdtoselectthecanvaselement.Onthesecondline,wecallgetContextonthecanvastogetthecontextobject.Then,inthevarwidthandvarheightlines,westorethewidthandheightofthecanvaselementinthevariableswidthandheight.Thisway,whenweneedthecanvasdimensions,wecanusethesevariablesinsteadofhavingtoenterthenumbersmanually.Now,ifwechoosetochangethesizeofthecanvas,wecansimplyedittheHTML,andtheJavaScriptcodeshouldstillwork.
DefiningthecircleFunctionNext,wedefinethesamecirclefunctionfortheballthatweusedinChapter14.Addthisfunctionafterthecodefromtheprevioussection:
varcircle=function(x,y,radius,fillCircle){
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
if(fillCircle){
ctx.fill();
}else{
ctx.stroke();
}
};
CreatingtheBallConstructorNowwe’llcreateaBallconstructor.We’llusethisconstructortocreatethemovingballobject.We’llbeusingthesametechniqueformovingthisballaswedidinChapter14—usingthexSpeedandySpeedpropertiestocontrolthehorizontalandverticalspeedoftheball.Addthiscodeafterthecirclefunction:
varBall=function(){
this.x=width/2;
this.y=height/2;
this.xSpeed=5;
this.ySpeed=0;
};
Wesetthexandyvalues(theball’sposition)towidth/2andheight/2sothattheballwillstartatthecenterofthecanvas.Wealsosetthis.xSpeedto5andthis.ySpeedto0.Thismeansthattheballwillstarttheanimationbymovingtotheright(thatis,witheachanimationstep,itsxpositionwillincreaseby5pixelsanditsypositionwillstaythesame).
DefiningthemoveMethodInthissection,we’lldefinethemovemethod.We’lladdthismethodtoBall.prototypetomovetheballtoanewlocationbasedonitscurrentlocation,xSpeedandySpeed.AddthismethodaftertheBallconstructor:
Ball.prototype.move=function(){
this.x+=this.xSpeed;
this.y+=this.ySpeed;
➊if(this.x<0){
this.x=width;
}elseif(this.x>width){
this.x=0;
}elseif(this.y<0){
this.y=height;
}elseif(this.y>height){
this.y=0;
}
};
Firstweupdatethis.xandthis.yusingthis.xSpeedandthis.ySpeed,justaswedidinChapter14(seeMovingtheBall).Afterthatisthecodeforwhentheballreachestheedgeofthecanvas.Theif...elsestatementat➊checkstheball’spositiontoseeifithasmovedofftheedgeofthecanvas.Ifithas,thiscodemakestheballwraparoundtotheothersideofthecanvas.Forexample,iftheballgoesofftheleftedgeofthecanvas,itshouldreappearfromtherightsideofthecanvas.Inotherwords,ifthis.xislessthan0,wesetthis.xtowidth,whichplacesitattheveryrightedgeofthecanvas.Therestoftheif...elsestatementdealswiththeotherthreeedgesofthecanvasinasimilarway.
DefiningthedrawMethodWe’llusethedrawmethodtodrawtheball.Addthisafterthedefinitionofthemovemethod:
Ball.prototype.draw=function(){
circle(this.x,this.y,10,true);
};
Thismethodcallsthecirclefunction.Itusestheball’sxandyvaluestosetthecenteroftheball,setstheradiusto10,andsetsfillCircletotrue.Figure15-2showstheresultingball.
Figure15-2.Theballisafilledcirclewitharadiusof10.
CreatingasetDirectionMethodNowwehavetocreateawaytosetthedirectionoftheball.We’lldothatwithamethodcalledsetDirection.Thismethodwillbecalledbyourkeydowneventhandler,whichyou’llseeinthenextsection.ThekeydownhandlerwilltellsetDirectionwhichkeywaspressedbypassingitastring("left","up","right","down",or"stop").Basedonthatstring,setDirectionwillchangethexSpeedandySpeedpropertiesoftheballtomakeitmoveinthedirectionthatmatchesthekeypress.Forexample,ifthestring"down"ispassed,wesetthis.xSpeedto0andthis.ySpeedto5.Addthiscodeafterthedrawmethod:
Ball.prototype.setDirection=function(direction){
if(direction==="up"){
this.xSpeed=0;
this.ySpeed=-5;
}elseif(direction==="down"){
this.xSpeed=0;
this.ySpeed=5;
}elseif(direction==="left"){
this.xSpeed=-5;
this.ySpeed=0;
}elseif(direction==="right"){
this.xSpeed=5;
this.ySpeed=0;
}elseif(direction==="stop"){
this.xSpeed=0;
this.ySpeed=0;
}
};
Theentirebodyofthismethodisonelongif...elsestatement.Thenewdirectionispassedintothemethodasthedirectionargument.Ifdirectionisequalto"up",wesettheball’sxSpeedpropertyto0anditsySpeedpropertyto-5.Theotherdirectionsarehandledinthesameway.Finally,ifthedirectionissettothestring"stop",wesetboththis.xSpeedandthis.ySpeedto0,whichmeansthattheballwillstopmoving.
ReactingtotheKeyboardThisnextsnippetofcodecreatesaballobjectusingtheBallconstructor,anditlistensforkeydowneventsinordertosettheball’sdirection.AddthiscodeafterthesetDirectionmethod:
➊varball=newBall();
➋varkeyActions={
32:"stop",
37:"left",
38:"up",
39:"right",
40:"down"
};
➌$("body").keydown(function(event){
➍vardirection=keyActions[event.keyCode];
➎ball.setDirection(direction);
});
At➊,wecreateaballobjectbycallingnewBall().At➋wecreateakeyActionsobject,whichwe’llusetoconvertkeycodestotheircorrespondingdirection.ThisobjectisthesameasthekeyNamesobjectwecreatedinUsinganObjecttoConvertKeycodesintoNames,exceptthatfor32(thekeycodeforthespacebar)wereplacethelabel"space"with"stop"sincewewantthespacebartostoptheballfrommoving.At➌weusethejQuery$functiontoselectthebodyelementandthencallthekeydownmethodtolistenforkeydownevents.Thefunctionpassedtothekeydownmethodiscalledeverytimeakeyispressed.Insidethisfunction,weusekeyActions[event.keyCode]at➍tolookupthelabelforthekeythatwaspressedandassignthatlabeltothedirectionvariable.Thissetsthedirectionvariabletoadirection:"left"iftheleftarrowispressed,"right"iftherightarrowispressed,"up"fortheuparrow,"down"forthedownarrow,and"stop"forthespacebar.Ifanyotherkeyispressed,directionissettoundefined,andtheanimationwon’tbeaffected.Finally,at➎wecallthesetDirectionmethodontheballobject,passingthedirectionstring.Asyousawbefore,setDirectionupdatestheball’sxSpeedandySpeedpropertiesbasedonthenewdirection.
AnimatingtheBallAllwehavelefttodonowisanimatetheball.Thefollowingcodeshouldlookfamiliar,sinceit’squitesimilartowhatweusedinChapter14.ItusesthesetIntervalfunctionthatwe’veseenintheanimationcodeinpreviouschapterstoupdatetheball’spositionatregularintervals.Addthiscodeafterthecodefromtheprevioussection:
setInterval(function(){
ctx.clearRect(0,0,width,height);
ball.draw();
ball.move();
ctx.strokeRect(0,0,width,height);
},30);
WeusesetIntervaltocallouranimationfunctionevery30milliseconds.ThefunctionfirstclearstheentirecanvaswithclearRectandthencallsthedrawandmovemethodsontheball.Aswe’veseen,thedrawmethodsimplydrawsacircleattheball’scurrentlocation,andthemovemethodupdatestheball’spositionbasedonitsxSpeedandySpeedproperties.Finally,itdrawsaborderwithstrokeRectsowecanseetheedgeofthecanvas.
PuttingItAllTogetherNowthatwe’vegonethroughallthecode,here’sthefulllistingforyourconvenience.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varwidth=canvas.width;
varheight=canvas.height;
varcircle=function(x,y,radius,fillCircle){
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
if(fillCircle){
ctx.fill();
}else{
ctx.stroke();
}
};
//TheBallconstructor
varBall=function(){
this.x=width/2;
this.y=height/2;
this.xSpeed=5;
this.ySpeed=0;
};
//Updatetheball'spositionbasedonitsspeed
Ball.prototype.move=function(){
this.x+=this.xSpeed;
this.y+=this.ySpeed;
if(this.x<0){
this.x=width;
}elseif(this.x>width){
this.x=0;
}elseif(this.y<0){
this.y=height;
}elseif(this.y>height){
this.y=0;
}
};
//Drawtheballatitscurrentposition
Ball.prototype.draw=function(){
circle(this.x,this.y,10,true);
};
//Settheball'sdirectionbasedonastring
Ball.prototype.setDirection=function(direction){
if(direction==="up"){
this.xSpeed=0;
this.ySpeed=-5;
}elseif(direction==="down"){
this.xSpeed=0;
this.ySpeed=5;
}elseif(direction==="left"){
this.xSpeed=-5;
this.ySpeed=0;
}elseif(direction==="right"){
this.xSpeed=5;
this.ySpeed=0;
}elseif(direction==="stop"){
this.xSpeed=0;
this.ySpeed=0;
}
};
//Createtheballobject
varball=newBall();
//Anobjecttoconvertkeycodesintoactionnames
varkeyActions={
32:"stop",
37:"left",
38:"up",
39:"right",
40:"down"
};
//Thekeydownhandlerthatwillbecalledforeverykeypress
$("body").keydown(function(event){
vardirection=keyActions[event.keyCode];
ball.setDirection(direction);
});
//Theanimationfunction,calledevery30ms
setInterval(function(){
ctx.clearRect(0,0,width,height);
ball.draw();
ball.move();
ctx.strokeRect(0,0,width,height);
},30);
RunningtheCodeNowourprogramiscomplete.Whenyouruntheprogram,youshouldseeablackballmovingacrossthecanvastotheright,asshowninFigure15-3.Whenitreachestherightsideofthecanvas,itshouldwraparoundtotheleftsideandkeepmovingtotheright.Whenyoupressthearrowkeys,theballshouldchangedirection,andpressingthespacebarshouldmaketheballstop.
Figure15-3.Ascreenshotfromthemovingballanimation
NOTE
Iftheanimationdoesn’trespondtokeysasexpected,clickthepagetomakesuretheprogramcanaccessyourkeypresses.
WhatYouLearnedInthischapter,youlearnedhowtomakeprogramsthatreacttokeyboardevents.Weusedthisknowledgetocreateamovingball,wheretheball’sdirectionissetbythekeyboard.Nowthatwecandrawtothecanvas,createanimations,andupdatethoseanimationsbasedonuserinput,wecancreateasimplecanvas-basedgame!Inthenextchapter,we’llre-createtheclassicSnakegame,combiningeverythingwe’velearnedupuntilnow.
ProgrammingChallengesHereareafewwaysyoucanbuildonthefinalanimationtomakeitmoresophisticated.#1:BOUNCINGOFFTHEWALLSModifythecodesotheballbouncesoffthesideandtopwallsinsteadofwrappingaroundtotheotherside.Hint:Justreversethedirectionwhentheballhitsthewall.#2:CONTROLLINGTHESPEEDTheballcurrentlymoves5pixelsforeverystepoftheanimation.ThisisbecausesetDirectionalwayssetsxSpeedorySpeedto-5or5.CreateanewpropertyintheBallconstructorcalledspeedandsetitto5.Thenusethisinsteadofthenumber5insetDirection.Now,changeyourcodesothatyoucanusethenumberkeystosetthespeedfrom1to9.Hint:Createanobjectcalledspeeds,anduseittodeterminethenewspeed,ifany,basedonthekeydownevent.#3:FLEXIBLECONTROLSModifyyourcodesothatwhenyoupresstheZkey,theballslowsdown,andwhenyoupresstheXkey,itspeedsup.Oncethat’sworking,useCtomaketheballsmallerandVtomakeitlarger.Whathappensifthespeedgoesbelow0?Whataboutthesize?Addacheckinthecodetomakesurethespeedandsizenevergobelow0.
Chapter16.MakingaSnakeGame:Part1Inthischapterandthenext,we’llbuildourownversionoftheclassicarcadegameSnake.InSnake,theplayerusesthekeyboardtocontrolasnakebydirectingitsmovementup,down,left,orright.Asthesnakemovesaroundtheplayingarea,applesappear.Whenthesnakereachesanapple,iteatstheappleandgrowslonger.Butifthesnakehitsawallorrunsintopartofitsownbody,thegameisover.Asyoucreatethisgame,you’llcombinemanyofthetoolsandtechniquesyou’velearnedsofar,includingjQueryandthecanvasaswellasanimationandinteractivity.Inthischapter,we’lllookatthegeneralstructureofthegameandgothroughthecodefordrawingtheborderandthescoreandendingthegame.InChapter17,we’llwritethecodeforthesnakeandtheappleandthenputeverythingtogethertocompletethegame.
TheGamePlayFigure16-1showswhatourfinishedgamewilllooklike.We’llneedtokeeptrackofanddrawfouritemsonthescreenasthegameruns:theborder(ingray),thescore(inblack),thesnake(inblue),andtheapple(inlimegreen).
Figure16-1.OurSnakegame
TheStructureoftheGameBeforewestartwritingcode,let’stakealookattheoverallstructureofthegame.Thispseudocodedescribeswhatourprogramneedstodo:
Setupthecanvas
Setscoretozero
Createsnake
Createapple
Every100milliseconds{
Clearthecanvas
Drawcurrentscoreonthescreen
Movesnakeincurrentdirection
Ifsnakecollideswithwalloritself{
Endthegame
}ElseIfsnakeeatsanapple{
Addonetoscore
Moveappletonewlocation
Makesnakelonger
}
Foreachsegmentofthesnake{
Drawthesegment
}
Drawapple
Drawborder
}
Whentheuserpressesakey{
Ifthekeyisanarrow{
Updatethedirectionofthesnake
}
}
Overthecourseofthischapterandthenext,we’llwritethecodetoexecuteeachofthesesteps.Butfirst,let’stalkthroughsomeofthemajorpartsofthisprogramandplanoutsomeoftheJavaScripttoolswe’lluseforthem.
UsingsetIntervaltoAnimatetheGameAsyoucanseeinthepseudocode,every100millisecondsweneedtocallaseriesoffunctionsandmethodsthatupdateanddraweverythingtothegameboard.Justaswe’vedoneinChapter14andChapter15,we’llusesetIntervaltoanimatethegamebycallingthosefunctionsatregularintervals.ThisiswhatourcalltosetIntervalwilllooklikeinthefinalprogram:
varintervalId=setInterval(function(){
ctx.clearRect(0,0,width,height);
drawScore();
snake.move();
snake.draw();
apple.draw();
drawBorder();
},100);
InthefunctionthatwepasstosetInterval,thefirstlineclearsthecanvaswithclearRectsothatwecandrawthenextstepintheanimation.Nextweseeseveralfunctionandmethodcalls.Noticethattheseallroughlymatchupwiththestepsinthepseudocodelistingonthepreviouspage.AlsonoticethatwesavetheintervalIDinthevariableintervalId.We’llneedthatintervalIDwhenthegameisoverandwewanttostoptheanimation(seeEndingtheGame).
CreatingtheGameObjectsForthisprogram,we’llusetheobject-orientedprogrammingstylewelearnedaboutinChapter12torepresentthetwomainobjectsinthegame:thesnakeandtheapple.We’llcreateaconstructorforeachoftheseobjects(calledSnakeandApple),andwe’lladdmethods(likemoveanddraw)totheprototypesoftheseconstructors.We’llalsodividethegameboardintoagridandthencreateaconstructorcalledBlock,whichwe’llusetocreateobjectsthatrepresentsquaresinthegrid.We’llusetheseblockobjectstorepresentthelocationofsegmentsofthesnake,andwe’lluseasingleblockobjecttostoretheapple’scurrentlocation.Theseblockswillalsohavemethodstoletusdrawthesegmentsofthesnakeandtheapple.
SettingUpKeyboardControlIntheearlierpseudocode,there’sasectiondevotedtorespondingtokeypressesbytheuser.Toallowtheplayertocontrolthesnakeusingthearrowkeysonthekeyboard,we’llusejQuerytorespondtokeypresses,aswedidinChapter15.We’llidentifythekeythatwaspressedbylookingupthekeycode,andthenwe’llsetthesnake’sdirectionaccordingly.
GameSetupNowthatwe’vegonethroughanoverviewofhowtheprogramwillwork,let’sstartwritingsomecode!Inthischapter,we’llstartbysettinguptheHTML,thecanvas,andsomevariableswe’llneedthroughouttheprogram.Thenwe’lltackleafewofthemorestraightforwardfunctionsweneedforthisgame:onetodrawtheborderaroundtheboard,onetodrawthescoreonthescreen,andonetoendthegame.Inthenextchapter,we’llcreatetheconstructorsandmethodsforthesnakeandapple,createaneventhandlerforarrowkeypresses,andputitalltogethertocompletethegame.
CreatingtheHTMLTobegincodingourgame,enterthefollowingintoyourtexteditorandsaveitassnake.html.
<!DOCTYPEhtml>
<html>
<head>
<title>Snake!</title>
</head>
<body>
➊<canvasid="canvas"width="400"height="400"></canvas>
➋<scriptsrc="https://code.jquery.com/jquery-2.1.0.js"></script>
➌<script>
//We'llfillthisinnext
</script>
</body>
</html>
At➊wecreateacanvaselementthatis400×400pixels.Thisiswherewe’lldraweverythingforourgame.WeincludethejQuerylibraryat➋,followedbyanotherpairof<script>tagsat➌,wherewe’lladdourJavaScriptcodetocontrolthegame.Let’sstartwritingthatJavaScriptnow.
Definingthecanvas,ctx,width,andheightVariablesFirstwe’lldefinethevariablescanvasandctx,whichwillletusdrawonthecanvas,andthevariableswidthandheight,togetthewidthandheightofthecanvaselement.
varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
varwidth=canvas.width;
varheight=canvas.height;
ThecodeintheHTMLsetsthewidthandheightto400pixels;ifyouchangethosedimensionsintheHTML,widthandheightwillmatchthenewdimensions.
DividingtheCanvasintoBlocksNext,we’llcreatevariablestohelpusthinkaboutourcanvasasagridof10-by-10-pixelblocks,asshowninFigure16-2.Althoughthegridwillbeinvisible(thatis,thegamewon’tactuallydisplayit),everythinginthegamewillbedrawntolineupwithit.
Figure16-2.A10-pixelgridshowingtheblocklayoutofthegame
Thesnakeandapplewillbothbeoneblockwidesothattheyfitwithinthisgrid.Foreverystepoftheanimation,thesnakewillmoveexactlyoneblockinitscurrentdirection.We’llusethesevariablestocreatetheblocksonourcanvas:
➊varblockSize=10;
➋varwidthInBlocks=width/blockSize;
varheightInBlocks=height/blockSize;
At➊wecreateavariablecalledblockSizeandsetitto10,sincewewantourblockstobe10pixelstallandwide.At➋wecreatethevariableswidthInBlocksandheightInBlocks.WesetwidthInBlocksequaltothewidthofthecanvasdividedbytheblocksize,whichtellsushowmanyblockswidethecanvasis.Similarly,heightInBlockstellsushowmanyblockstallthecanvasis.Atthemomentthecanvasis400pixelswideandtall,sowidthInBlocksandheightInBlockswillbothbe40.IfyoucountthenumberofsquaresinFigure16-2(includingtheborder),you’llseethatit’s40blockswideandtall.
DefiningthescoreVariableFinally,wedefinethescorevariable.
varscore=0;
We’llusethescorevariabletokeeptrackoftheplayer’sscore.Becausethisisthebeginningoftheprogram,wesetscoreequalto0.We’llincrementitby1everytimethesnakeeatsanapple.
DrawingtheBorderNext,we’llcreateadrawBorderfunctiontodrawaborderaroundthecanvas.We’llmakethisborderoneblock(10pixels)thick.Ourfunctionwilldrawfourlong,thinrectangles,oneforeachedgeoftheborder.EachrectanglewillbeblockSize(10pixels)thickandthefullwidthorheightofthecanvas.
vardrawBorder=function(){
ctx.fillStyle="Gray";
➊ctx.fillRect(0,0,width,blockSize);
➋ctx.fillRect(0,height-blockSize,width,blockSize);
➌ctx.fillRect(0,0,blockSize,height);
➍ctx.fillRect(width-blockSize,0,blockSize,height);
};
FirstwesetthefillStyletogray,becausewewantthebordertobegray.Then,at➊,wedrawthetopedgeoftheborder.Herewe’redrawingarectanglestartingat(0,0)—thetop-leftcornerofthecanvas—withawidthofwidth(400pixels)andaheightofblockSize(10pixels).Next,at➋,wedrawthebottomedgeoftheborder.Thiswillbearectangleatthecoordinates(0,height-blockSize),or(0,390).Thisis10pixelsupfromthebottomofthecanvas,ontheleft.Likethetopborder,thisrectanglehasawidthofwidthandaheightofblockSize.Figure16-3showswhatthetopandbottomborderslooklike.
Figure16-3.Thetopandbottomborders
At➌wedrawtheleftborder,andat➍wedrawtherightone.Figure16-4showstheadditionofthesetwoedges.
Figure16-4.Theleftandrightborders(withthetopandbottombordersshowninalightergray)
DisplayingtheScoreNowlet’swriteadrawScorefunctiontodisplaythescoreatthetopleftofthecanvas,asshowninFigure16-1.ThisfunctionwillusethefillTextcontextmethodtoaddtexttothecanvas.ThefillTextmethodtakesatextstringandthex-andy-coordinateswhereyouwanttodisplaythattext.Forexample,
ctx.fillText("Helloworld!",50,50);
wouldwritethestringHelloworld!atthecoordinates(50,50)onyourcanvas.Figure16-5showshowthatwouldlook.
Figure16-5.ThestringHelloworld!drawnatthepoint(50,50)
Heylook,we’veprintedtexttothecanvas!Butwhatifwewanttohavemorecontroloverhowthetextlooksbytweakingthesizeandfontorchangingthealignment?ForthescoreinourSnakegame,wemightwanttouseadifferentfont,makethetextbigger,andmakesurethetextappearspreciselyinthetop-leftcorner,justbelowtheborder.SobeforewewriteourdrawScorefunction,let’slearnalittlemoreaboutthefillTextmethodandlookatsomewaystocustomizehowtextappearsonthecanvas.
SettingtheTextBaselineThecoordinatelocationthatdetermineswherethetextappearsiscalledthebaseline.Bydefault,thebottom-leftcornerofthetextislinedupwiththebaselinepointsothatthetextappearsaboveandtotherightofthatpoint.Tochangewherethetextappearsinrelationtothebaseline,wecanchangethetextBaselineproperty.Thedefaultvalueforthispropertyis"bottom",butyoucanalsosetthetextBaselinepropertyto"top"or"middle".Figure16-6showshowthetextisalignedforeachoftheseoptions,inrelationtothebaselinepoint(shownasareddot)thatyoupasstofillText.
Figure16-6.TheeffectofchangingtextBaseline
Forexample,torunyourtextbelowthebaseline,enter:ctx.textBaseline="top";
ctx.fillText("Helloworld!",50,50);
Now,whenyoucallfillText,thetextwillbebelowthepoint(50,50),asyoucanseeinFigure16-7.
Figure16-7.ThestringHelloworld!withtextBaselinesetto"top"
Similarly,tochangethehorizontalpositionofthetextrelativetothebaselinepoint,youcansetthetextAlignpropertyto"left","center",or"right".Figure16-8showstheresults.
Figure16-8.TheeffectofchangingtextAlign
SettingtheSizeandFontWecanchangethesizeandfontofthetextwedrawbysettingthefontpropertyofthedrawingcontext.Thislistingshowssomeexamplesofdifferentfontswecoulduse:
➊ctx.font="20pxCourier";
ctx.fillText("Courier",50,50);
ctx.font="24pxComicSansMS";
ctx.fillText("ComicSans",50,100);
ctx.font="18pxArial";
ctx.fillText("Arial",50,150);
Thefontpropertytakesastringthatincludesthesizeandthenameofthefontyouwanttouse.Forexample,at➊wesetthefontpropertyto"20pxCourier",whichmeansthetextwillbedrawnatasizeof20pixelsinthefontCourier.Figure16-9showshowthesedifferentfontslookwhendrawnonthecanvas.
Figure16-9.20pxCourier,24pxComicSans,and18pxArial
WritingthedrawScoreFunctionNowwecangoaheadandwritethedrawScorefunction,whichdrawsastringshowingthecurrentscoreonthecanvas.
vardrawScore=function(){
ctx.font="20pxCourier";
ctx.fillStyle="Black";
ctx.textAlign="left";
ctx.textBaseline="top";
ctx.fillText("Score:"+score,blockSize,blockSize);
};
Thisfunctionsetsthefontto20-pixelCourier(20pxCourier),setsitscolortoblackusingfillStyle,left-alignsthetextwiththetextAlignproperty,andthensetsthetextBaselinepropertyto"top".Next,wecallfillTextwiththestring"Score:"+score.Thescorevariableholdstheplayer’scurrentscoreasanumber.Wesetthestartingscoreto0atthebeginningofthegame(inDefiningthescoreVariable),soatfirstthiswilldisplay"Score:0".WhenwecallfillText,wesetthex-andy-coordinatestoblockSize.SincewesetblockSizeto10,thissetsthescore’sbaselinepointto(10,10),whichisjustinsidethetop-leftcorneroftheborder.AndsincewesettextBaselineto"top",thetextwillappearjustbelowthatbaselinepoint,asshowninFigure16-10.
Figure16-10.Thepositionofthescoretext
EndingtheGameWe’llcallthegameOverfunctiontoendthegamewhenthesnakehitsthewallorrunsintoitself.ThegameOverfunctionusesclearIntervaltostopthegameandwritesthetext“GameOver”onthecanvas.Here’swhatthegameOverfunctionlookslike:
vargameOver=function(){
clearInterval(intervalId);
ctx.font="60pxCourier";
ctx.fillStyle="Black";
ctx.textAlign="center";
ctx.textBaseline="middle";
ctx.fillText("GameOver",width/2,height/2);
};
FirstwestopthegamebycallingclearIntervalandpassinginthevariableintervalId.ThiscancelsthesetIntervalanimationfunctionthatwecreatedinUsingsetIntervaltoAnimatetheGame).Next,wesetourfontto60-pixelCourierinblack,centerthetext,andsetthetextBaselinepropertyto"middle".WethencallfillTextandtellittodrawthestring"GameOver"withwidth/2forthex-positionandheight/2forthey-position.Theresulting“GameOver”textwillbecenteredinthecanvas,asshowninFigure16-11.
Figure16-11.The“GameOver”screen,afterthesnakehashittheleftwall
WhatYouLearnedInthischapter,welookedatthegeneraloutlineofourSnakegameandsomeofthefunctionswe’llneedtomakethegame.Youlearnedhowtodrawtextontoacanvasandhowtocustomizeitssize,font,andposition.Inthenextchapter,we’llfinishoffourgamebywritingthecodeforthesnakeandtheappleandtohandlekeyboardevents.
ProgrammingChallengesHereareafewexercisesyoucantrybeforeyougoontofinishprogrammingthegame.#1:PUTTINGITTOGETHERAlthoughIhaven’tshownallthecodeforthegameyet,youcanrunthecodefordrawingtheborderandthescore.TakeyourHTMLfile(fromCreatingtheHTML)andaddthecodeforsettingupthecanvas,creatingthescore,drawingtheborder,anddrawingthescore.NowyoujustneedtocalldrawBorderanddrawScoretoseetheborderandscore.ItshouldlookjustlikeFigure16-10.YoucantryoutthegameOverfunction,too,butbeforeyoucallthatfunction,you’llneedtodeletetheclearInterval(intervalId);line.Youhaven’tcreatedtheintervalIdvariableyet,sofornow,ifyoucallthefunctionwithoutremovingthatline,itwillproduceanerror.#2:ANIMATINGTHESCOREWriteyourowncalltosetIntervalwithafunctionthatincreasesthescoreby1andthendrawstheupdatedscoreusingthedrawScorefunctionevery100milliseconds.Rememberthatyou’llneedtoclearthecanvaseachtime,usingtheclearRectmethodonthecanvascontext.#3:ADDINGTEXTTOHANGMANProgrammingchallenge#4inChapter13wastodrawthemaninourHangmangameusingcanvas.TryextendingyourHangmangamebyusingthefillTextmethodtodrawthecurrentwordunderneaththehangman,asshown.
Hint:Tounderlineeachletter,I’veused30-pixel-longstrokedlines,with10pixelsbetweeneachone.Forevenmoreofachallenge,drawtheincorrectguessescrossedout,asshowntotheright.
Chapter17.MakingaSnakeGame:Part2Inthischapter,we’llfinishbuildingourSnakegame.InChapter16,wesetuptheplayingareaandcoveredhowthegamewouldworkingeneral.Nowwe’llcreatetheobjectsthatrepresentthesnakeandappleinthegame,andwe’llprogramakeyboardeventhandlersothattheplayercancontrolthesnakewiththearrowkeys.Finally,we’lllookatthecompletecodelistingfortheprogram.Aswecreatethesnakeandappleobjectsforthisgame,we’llusetheobject-orientedprogrammingtechniqueswelearnedinChapter12tocreateconstructorsandmethodsforeachobject.Bothoursnakeandappleobjectswillrelyonamorebasicblockobject,whichwe’llusetorepresentoneblockonthegameboardgrid.Let’sstartbybuildingaconstructorforthatsimpleblockobject.
BuildingtheBlockConstructorInthissection,we’lldefineaBlockconstructorthatwillcreateobjectsthatrepresentindividualblocksonourinvisiblegamegrid.Eachblockwillhavethepropertiescol(shortforcolumn)androw,whichwillstorethelocationofthatparticularblockonthegrid.Figure17-1showsthisgridwithsomeofthecolumnsandrowsnumbered.Althoughthisgridwon’tactuallyappearonthescreen,ourgameisdesignedsothattheappleandthesnakesegmentswillalwayslineupwithit.
Figure17-1.ThecolumnandrownumbersusedbytheBlockconstructor
InFigure17-1,theblockcontainingthegreenappleisatcolumn10,row10.Theheadofthesnake(totheleftoftheapple)isatcolumn8,row10.Here’sthecodefortheBlockconstructor:
varBlock=function(col,row){
this.col=col;
this.row=row;
};
ColumnandrowvaluesarepassedintotheBlockconstructorasargumentsandsavedinthecolandrowpropertiesofthenewobject.Nowwecanusethisconstructortocreateanobjectrepresentingaparticularblockonthegamegrid.Forexample,here’showwe’dcreateanobjectthatrepresentstheblockincolumn5,row5:
varsampleBlock=newBlock(5,5);
AddingthedrawSquareMethodSofarthisblockobjectletsusrepresentalocationonthegrid,buttoactuallymakesomethingappearatthatlocation,we’llneedtodrawitonthecanvas.Next,we’lladdtwomethods,drawSquareanddrawCircle,thatwillletusdrawasquareoracircle,respectively,inaparticularblockonthegrid.First,here’sthedrawSquaremethod:
Block.prototype.drawSquare=function(color){
➊varx=this.col*blockSize;
➋vary=this.row*blockSize;
ctx.fillStyle=color;
ctx.fillRect(x,y,blockSize,blockSize);
};
InChapter12welearnedthatifyouattachmethodstotheprototypepropertyofaconstructor,thosemethodswillbeavailabletoanyobjectscreatedwiththatconstructor.SobyaddingthedrawSquaremethodtoBlock.protoype,wemakeitavailabletoanyblockobjects.
Thismethoddrawsasquareatthelocationgivenbytheblock’scolandrowproperties.Ittakesasingleargument,color,whichdeterminesthecolorofthesquare.Todrawasquarewithcanvas,weneedtoprovidethex-andy-positionsofthetop-leftcornerofthesquare.At➊and➋wecalculatethesex-andy-valuesforthecurrentblockbymultiplyingthecolandrowpropertiesbyblockSize.WethensetthefillStylepropertyofthedrawingcontexttothemethod’scolorargument.Finally,wecallctx.fillRect,passingourcomputedx-andy-valuesandblockSizeforboththewidthandheightofthesquare.Here’showwewouldcreateablockincolumn3,row4,anddrawit:
varsampleBlock=newBlock(3,4);
sampleBlock.drawSquare("LightBlue");
Figure17-2showsthissquaredrawnonthecanvasandhowthemeasurementsforthesquarearecalculated.
Figure17-2.Calculatingthevaluesfordrawingasquare
AddingthedrawCircleMethodNowforthedrawCirclemethod.ItisverysimilartothedrawSquaremethod,butitdrawsafilledcircleinsteadofasquare.
Block.prototype.drawCircle=function(color){
varcenterX=this.col*blockSize+blockSize/2;
varcenterY=this.row*blockSize+blockSize/2;
ctx.fillStyle=color;
circle(centerX,centerY,blockSize/2,true);
};
Firstwecalculatethelocationofthecircle’scenterbycreatingtwonewvariables,centerXandcenterY.Asbefore,wemultiplythecolandrowpropertiesbyblockSize,butthistimewealsohavetoaddblockSize/2,becauseweneedthepixelcoordinatesforthecircle’scenter,whichisinthemiddleofablock(asshowninFigure17-3).WesetthecontextfillStyletothecolorargumentasindrawSquareandthencallourtrustycirclefunction,passingcenterXandcenterYforthex-andy-coordinates,blockSize/2fortheradius,andtruetotellthefunctiontofillthecircle.ThisisthesamecirclefunctionwedefinedinChapter14,sowe’llhavetoincludethedefinitionforthatfunctiononceagaininthisprogram(asyoucanseeinthefinalcodelisting).
Here’showwecoulddrawacircleincolumn4,row3:varsampleCircle=newBlock(4,3);
sampleCircle.drawCircle("LightGreen");
Figure17-3showsthecircle,withthecalculationsforthecenterpointandradius.
Figure17-3.Calculatingthevaluesfordrawingacircle
AddingtheequalMethodInourgame,we’llneedtoknowwhethertwoblocksareinthesamelocation.Forexample,iftheappleandthesnake’sheadareinthesamelocation,thatmeansthesnakehaseatentheapple.Ontheotherhand,ifthesnake’sheadandtailareinthesamelocation,thenthesnakehascollidedwithitself.Tomakeiteasiertocompareblocklocations,we’lladdamethod,equal,totheBlockconstructorprototype.Whenwecallequalononeblockobjectandpassanotherobjectasanargument,itwillreturntrueiftheyareinthesamelocation(andfalseifnot).Here’sthecode:
Block.prototype.equal=function(otherBlock){
returnthis.col===otherBlock.col&&this.row===otherBlock.row;
};
Thismethodisprettystraightforward:ifthetwoblocks(thisandotherBlock)havethesamecolandrowproperties(thatis,ifthis.colisequaltootherBlock.colandthis.rowisequaltootherBlock.row),thentheyareinthesameplace,andthemethodreturnstrue.Forexample,let’screatetwonewblockscalledappleandheadandseeifthey’reinthesamelocation:
varapple=newBlock(2,5);
varhead=newBlock(3,5);
head.equal(apple);
false
Althoughappleandheadhavethesamerowproperty(5),theircolpropertiesaredifferent.Ifwesettheheadtoanewblockobjectonecolumntotheleft,nowthemethodwilltellusthatthetwoobjectsareinthesamelocation:
head=newBlock(2,5);
head.equal(apple);
true
Notethatitdoesn’tmakeanydifferencewhetherwewritehead.equal(apple)orapple.equal(head);inbothcaseswe’remakingthesamecomparison.We’llusetheequalmethodlatertocheckwhetherthesnakehaseatentheappleorcollidedwithitself.
CreatingtheSnakeNowwe’llcreatethesnake.We’llstorethesnake’spositionasanarraycalledsegments,whichwillcontainaseriesofblockobjects.Tomovethesnake,we’lladdanewblocktothebeginningofthesegmentsarrayandremovetheblockattheendofthearray.Thefirstelementofthesegmentsarraywillrepresenttheheadofthesnake.
WritingtheSnakeConstructorFirstweneedaconstructortocreateoursnakeobject:
varSnake=function(){
➊this.segments=[
newBlock(7,5),
newBlock(6,5),
newBlock(5,5)
];
➋this.direction="right";
➌this.nextDirection="right";
};
DefiningtheSnakeSegmentsThesegmentspropertyat➊isanarrayofblockobjectsthateachrepresentasegmentofthesnake’sbody.Whenwestartthegame,thisarraywillcontainthreeblocksat(7,5),(6,5),and(5,5).Figure17-4showstheseinitialthreesegmentsofthesnake.
Figure17-4.Theinitialblocksthatmakeupthesnake
SettingtheDirectionofMovementThedirectionpropertyat➋storesthecurrentdirectionofthesnake.OurconstructoralsoaddsthenextDirectionpropertyat➌,whichstoresthedirectioninwhichthesnakewillmoveforthenextanimationstep.Thispropertywillbeupdatedbyourkeydowneventhandlerwhentheplayerpressesanarrowkey(seeAddingthekeydownEventHandler).Fornow,theconstructorsetsbothofthesepropertiesto"right",soatthebeginningofthegameoursnakewillmovetotheright.
DrawingtheSnakeTodrawthesnake,wesimplyhavetoloopthrougheachoftheblocksinitssegmentsarray,callingthedrawSquaremethodwecreatedearlieroneachblock.Thiswilldrawasquareforeachsegmentofthesnake.
Snake.prototype.draw=function(){
for(vari=0;i<this.segments.length;i++){
this.segments[i].drawSquare("Blue");
}
};
Thedrawmethodusesaforlooptooperateoneachblockobjectinthesegmentsarray.Eachtimearoundtheloop,thiscodetakesthecurrentsegment(this.segments[i])andcallsdrawSquare("Blue")onit,whichdrawsabluesquareinthecorrespondingblock.Ifyouwanttotestoutthedrawmethod,youcanrunthefollowingcode,whichcreatesanewobjectusingtheSnakeconstructorandcallsitsdrawmethod:
varsnake=newSnake();
snake.draw();
MovingtheSnakeWe’llcreateamovemethodtomovethesnakeoneblockinitscurrentdirection.Tomovethesnake,weaddanewheadsegment(byaddinganewblockobjecttothebeginningofthesegmentsarray)andthenremovethetailsegmentfromtheendofthesegmentsarray.Themovemethodwillalsocallamethod,checkCollision,toseewhetherthenewheadhascollidedwiththerestofthesnakeorwiththewall,andwhetherthenewheadhaseatentheapple.Ifthenewheadhascollidedwiththebodyorthewall,weendthegamebycallingthegameOverfunctionwecreatedinChapter16.Ifthesnakehaseatentheapple,weincreasethescoreandmovetheappletoanewlocation.
AddingthemoveMethodThemovemethodlookslikethis:
Snake.prototype.move=function(){
➊varhead=this.segments[0];
➋varnewHead;
➌this.direction=this.nextDirection;
➍if(this.direction==="right"){
newHead=newBlock(head.col+1,head.row);
}elseif(this.direction==="down"){
newHead=newBlock(head.col,head.row+1);
}elseif(this.direction==="left"){
newHead=newBlock(head.col-1,head.row);
}elseif(this.direction==="up"){
newHead=newBlock(head.col,head.row-1);
}
➎if(this.checkCollision(newHead)){
gameOver();
return;
}
➏this.segments.unshift(newHead);
➐if(newHead.equal(apple.position)){
score++;
apple.move();
}else{
this.segments.pop();
}
};
Let’swalkthroughthismethodpiecebypiece.
CreatingaNewHeadAt➊wesavethefirstelementofthethis.segmentsarrayinthevariablehead.We’llrefertothisfirstsegmentofthesnakemanytimesinthismethod,sousingthisvariablewillsaveussometypingandmakethecodeabiteasiertoread.Now,insteadofrepeatingthis.segments[0]overandoveragain,wecanjusttypehead.At➋wecreatethevariablenewHead,whichwe’llusetostoretheblockrepresentingthenewheadofthesnake(whichwe’reabouttoadd).At➌wesetthis.directionequaltothis.nextDirection,whichupdatesthedirectionofthesnake’smovementtomatchthemostrecentlypressedarrowkey.(We’llseehowthisworksinmoredetailwhenwelookatthekeydowneventhandler.)
DIRECTIONANDNEXTDIRECTION
Thesnake’sdirectionpropertywillbeupdatedexactlyonceforeachstepintheanimation,sincethemovemethodiscalledonceperanimationstep.ThenextDirectionproperty,ontheotherhand,willbeupdatedanytimetheplayerpressesanarrowkey(soiftheypressthekeysreallyfast,thispropertycouldtheoreticallychangemultipletimesperanimationstep).Bykeepingthesetwopropertiesseparate,wemakesurethesnakecan’tturnbackonitselfiftheplayerpressestwoarrowkeysveryquicklybetweentwostepsintheanimation.
Beginningat➍,weuseachainofif...elsestatementstodeterminethesnake’sdirection.Ineachcase,wecreateanewheadforthesnakeandsaveitinthevariablenewHead.Dependingonthedirectionofmovement,weaddorsubtractonefromtheroworcolumnoftheexistingheadtoplacethisnewheaddirectlynexttotheoldone(eitherright,left,up,ordowndependingonthesnake’sdirectionofmovement).Forexample,Figure17-5showshowthenewheadisaddedtothesnakewhenthis.nextDirectionissetto"down".
Figure17-5.CreatingnewHeadwhenthis.nextDirectionis"down"
CheckingforCollisionsandAddingtheHeadAt➎wecallthecheckCollisionmethodtofindoutwhetherthesnakehascollidedwithawallorwithitself.We’llseethecodeforthismethodinamoment,butasyoumightguess,thismethodwillreturntrueifthesnakehascollidedwithsomething.Ifthathappens,thebodyoftheifstatementcallsthegameOverfunctiontoendthegameandprint“GameOver”onthecanvas.ThereturnkeywordthatfollowsthecalltogameOverexitsthemovemethodearly,skippinganycodethatcomesafterit.WereachthereturnkeywordonlyifcheckCollisionreturnstrue,soifthesnakehasn’tcollidedwithanything,weexecutetherestofthemethod.Aslongasthesnakehasn’tcollidedwithsomething,weaddthenewheadtothefrontofthesnakeat➏byusingunshifttoaddnewHeadtothebeginningofthesegmentsarray.Formoreabouthowtheunshiftmethodworksonarrays,seeAddingElementstoanArray.
EatingtheAppleAt➐,weusetheequalmethodtocomparenewHeadandapple.position.Ifthetwoblocksareinthesamelocation,theequalmethodwillreturntrue,whichmeansthatthesnakehaseatentheapple.Ifthesnakehaseatentheapple,weincreasethescoreandthencallmoveontheappletomoveittoanewlocation.Ifthesnakehasnoteatentheapple,wecallpoponthis.segments.Thisremovesthesnake’stailwhilekeepingthesnakethesamesize(sincemovealreadyaddedasegmenttothesnake’shead).Whenthesnakeeatsanapple,itgrowsbyonesegmentbecauseweaddasegmenttoitsheadwithoutremovingthetail.
Wehaven’tdefinedappleyet,sothismethodwon’tfullyworkinitscurrentform.Ifyouwanttotestitout,youcandeletethewholeif...elsestatementat➐andreplaceitwiththisline:
this.segments.pop();
ThenallyouneedtodoisdefinethecheckCollisionmethod,whichwe’lldonext.
AddingthecheckCollisionMethodEachtimewesetanewlocationforthesnake’shead,wehavetocheckforcollisions.Collisiondetection,averycommonstepingamemechanics,isoftenoneofthemorecomplexaspectsofgameprogramming.Fortunately,it’srelativelystraightforwardinourSnakegame.WecareabouttwotypesofcollisionsinourSnakegame:collisionswiththewallandcollisionswiththesnakeitself.Awallcollisionhappensifthesnakehitsawall.Thesnakecancollidewithitselfifyouturntheheadsothatitrunsintothebody.Atthestartofthegame,thesnakeistooshorttocollidewithitself,butaftereatingafewapples,itcan.HereisthecheckCollisionmethod:
Snake.prototype.checkCollision=function(head){
➊varleftCollision=(head.col===0);
vartopCollision=(head.row===0);
varrightCollision=(head.col===widthInBlocks-1);
varbottomCollision=(head.row===heightInBlocks-1);
➋varwallCollision=leftCollision||topCollision||
rightCollision||bottomCollision;
➌varselfCollision=false;
➍for(vari=0;i<this.segments.length;i++){
if(head.equal(this.segments[i])){
➎selfCollision=true;
}
}
➏returnwallCollision||selfCollision;
};
CheckingforWallCollisionsAt➊wecreatethevariableleftCollisionandsetittothevalueofhead.col===0.Thisvariablewillbetrueifthesnakecollideswiththeleftwall;thatis,whenitisincolumn0.Similarly,thevariabletopCollisioninthenextlinecheckstherowofthesnake’sheadtoseeifithasrunintothetopwall.Afterthat,wecheckforacollisionwiththerightwallbycheckingwhetherthecolumnvalueoftheheadisequaltowidthInBlocks-1.SincewidthInBlocksissetto40,thischeckswhethertheheadisincolumn39,whichcorrespondstotherightwall,asyoucanseebackinFigure17-1.ThenwedothesamethingforbottomCollision,checkingwhetherthehead’srowpropertyisequaltoheightInBlocks-1.At➋,wedeterminewhetherthesnakehascollidedwithawallbycheckingtoseeifleftCollisionortopCollisionorrightCollisionorbottomCollisionistrue,usingthe||(or)operator.WesavetheBooleanresultinthevariablewallCollision.
CheckingforSelf-CollisionsTodeterminewhetherthesnakehascollidedwithitself,wecreateavariableat➌calledselfCollisionandinitiallysetittofalse.Thenat➍weuseaforlooptoloopthroughallthesegmentsofthesnaketodeterminewhetherthenewheadisinthesameplaceasanysegment,usinghead.equal(this.segments[i]).Theheadandalloftheothersegmentsareblocks,sowecanusetheequalmethodthatwedefinedforblockobjectstoseewhethertheyareinthesameplace.Ifwefindthatanyofthesnake’ssegmentsareinthesameplaceasthenewhead,weknowthatthesnakehascollidedwithitself,andwesetselfCollisiontotrue(at➎).Finally,at➏,wereturnwallCollision||selfCollision,whichwillbetrueifthesnakehascollidedwitheitherthewalloritself.
SettingtheSnake’sDirectionwiththeKeyboardNextwe’llwritethecodethatletstheplayersetthesnake’sdirectionusingthekeyboard.We’lladdakeydowneventhandlertodetectwhenanarrowkeyhasbeenpressed,andwe’llsetthesnake’sdirectiontomatchthatkey.
AddingthekeydownEventHandlerThiscodehandleskeyboardevents:
➊vardirections={
37:"left",
38:"up",
39:"right",
40:"down"
};
➋$("body").keydown(function(event){
varnewDirection=directions[event.keyCode];
➌if(newDirection!==undefined){
snake.setDirection(newDirection);
}
});
At➊wecreateanobjecttoconvertthearrowkeycodesintostringsindicatingthedirectiontheyrepresent(thisobjectisquitesimilartothekeyActionsobjectweusedinReactingtotheKeyboard).At➋weattachaneventhandlertothekeydowneventonthebodyelement.Thishandlerwillbecalledwhentheuserpressesakey(aslongasthey’veclickedinsidethewebpagefirst).Thishandlerfirstconvertstheevent’skeycodeintoadirectionstring,andthenitsavesthestringinthevariablenewDirection.Ifthekeycodeisnot37,38,39,or40(thekeycodesforthearrowkeyswecareabout),directions[event.keyCode]willbeundefined.At➌wechecktoseeifnewDirectionisnotequaltoundefined.Ifit’snotundefined,wecallthesetDirectionmethodonthesnake,passingthenewDirectionstring.(Becausethereisnoelsecaseinthisifstatement,ifnewDirectionisundefined,thenwejustignorethekeypress.)Thiscodewon’tworkyetbecausewehaven’tdefinedthesetDirectionmethodonthesnake.Let’sdothatnow.
AddingthesetDirectionMethodThesetDirectionmethodtakesthenewdirectionfromthekeyboardhandlerwejustlookedatandusesittoupdatethesnake’sdirection.Thismethodalsopreventstheplayerfrommakingturnsthatwouldhavethesnakeimmediatelyrunintoitself.Forexample,ifthesnakeismovingright,andthenitsuddenlyturnsleftwithoutmovingupordowntogetoutofitsownway,itwillcollidewithitself.We’llcalltheseillegalturnsbecausewedonotwanttoallowtheplayertomakethem.Forexample,Figure17-6showsthevaliddirectionsandtheoneillegaldirectionwhenthesnakeismovingright.
Figure17-6.Validnewdirectionsbasedonthecurrentdirection
ThesetDirectionmethodcheckswhethertheplayeristryingtomakeanillegalturn.Iftheyare,themethodusesreturntoendearly;otherwise,itupdatesthenextDirectionpropertyonthesnakeobject.Here’sthecodeforthesetDirectionmethod.
Snake.prototype.setDirection=function(newDirection){
➊if(this.direction==="up"&&newDirection==="down"){
return;
}elseif(this.direction==="right"&&newDirection==="left"){
return;
}elseif(this.direction==="down"&&newDirection==="up"){
return;
}elseif(this.direction==="left"&&newDirection==="right"){
return;
}
➋this.nextDirection=newDirection;
};
Theif...elsestatementat➊hasfourpartstodealwiththefourillegalturnswewanttoprevent.Thefirstpartsaysthatifthesnakeismovingup(this.directionis"up")andtheplayerpressesthedownarrow(newDirectionis"down"),weshouldexitthemethodearlywithreturn.Theotherpartsofthestatementdealwiththeotherillegalturnsinthesameway.ThesetDirectionmethodwillreachthefinallineonlyifnewDirectionisavalidnewdirection;otherwise,oneofthereturnstatementswillstopthemethod.IfnewDirectionisallowed,wesetitasthesnake’snextDirectionproperty,at➋.
CreatingtheAppleInthisgame,we’llrepresenttheappleasanobjectwiththreecomponents:apositionproperty,whichholdstheapple’spositionasablockobject;adrawmethod,whichwe’llusetodrawtheapple;andamovemethod,whichwe’llusetogivetheappleanewpositiononceit’sbeeneatenbythesnake.
WritingtheAppleConstructorTheconstructorsimplysetstheapple’spositionpropertytoanewblockobject.
varApple=function(){
this.position=newBlock(10,10);
};
Thiscreatesanewblockobjectincolumn10,row10,andassignsittotheapple’spositionproperty.We’llusethisconstructortocreateanappleobjectatthebeginningofthegame.
DrawingtheAppleWe’llusethisdrawmethodtodrawtheapple:
Apple.prototype.draw=function(){
this.position.drawCircle("LimeGreen");
};
Theapple’sdrawmethodisverysimple,asallthehardworkisdonebythedrawCirclemethod(createdinAddingthedrawCircleMethod).Todrawtheapple,wesimplycallthedrawCirclemethodontheapple’spositionproperty,passingthecolor"LimeGreen"totellittodrawagreencircleinthegivenblock.Totestoutdrawingtheapple,runthefollowingcode:
varapple=newApple();
apple.draw();
MovingtheAppleThemovemethodmovestheappletoarandomnewpositionwithinthegamearea(thatis,anyblockonthecanvasotherthantheborder).We’llcallthismethodwheneverthesnakeeatstheapplesothattheapplereappearsinanewlocation.
Apple.prototype.move=function(){
➊varrandomCol=Math.floor(Math.random()*(widthInBlocks-2))+1;
varrandomRow=Math.floor(Math.random()*(heightInBlocks-2))+1;
➋this.position=newBlock(randomCol,randomRow);
};
At➊wecreatethevariablesrandomColandrandomRow.Thesevariableswillbesettoarandomcolumnandrowvaluewithintheplayablearea.AsyousawinFigure17-1,thecolumnsandrowsfortheplayablearearangefrom1to38,soweneedtopicktworandomnumbersinthatrange.Togeneratetheserandomnumbers,wecancallMath.floor(Math.random()*38),whichgivesusarandomnumberfrom0to37,andthenadd1totheresulttogetanumberbetween1and38(formoreabouthowMath.floorandMath.randomwork,seeDecisionMaker).Thisisexactlywhatwedoat➊tocreateourrandomcolumnvalue,butinsteadofwriting38,wewrite(widthInBlocks-2).Thismeansthatifwelaterchangethesizeofthegame,wewon’talsohavetochangethiscode.Wedothesamethingtogetarandomrowvalue,usingMath.floor(Math.random()*(heightInBlocks-2))+1.Finally,at➋wecreateanewblockobjectwithourrandomcolumnandrowvaluesandsavethisblockinthis.position.Thismeansthatthepositionoftheapplewillbeupdatedtoanewrandomlocationsomewherewithintheplayingarea.Youcantestoutthemovemethodlikethis:
varapple=newApple();
apple.move();
apple.draw();
PuttingItAllTogetherOurfullcodeforthegamecontainsalmost200linesofJavaScript!Afterweassemblethewholething,itlookslikethis.
//Setupcanvas
➊varcanvas=document.getElementById("canvas");
varctx=canvas.getContext("2d");
//Getthewidthandheightfromthecanvaselement
varwidth=canvas.width;
varheight=canvas.height;
//Workoutthewidthandheightinblocks
varblockSize=10;
varwidthInBlocks=width/blockSize;
varheightInBlocks=height/blockSize;
//Setscoreto0
varscore=0;
//Drawtheborder
➋vardrawBorder=function(){
ctx.fillStyle="Gray";
ctx.fillRect(0,0,width,blockSize);
ctx.fillRect(0,height-blockSize,width,blockSize);
ctx.fillRect(0,0,blockSize,height);
ctx.fillRect(width-blockSize,0,blockSize,height);
};
//Drawthescoreinthetop-leftcorner
vardrawScore=function(){
ctx.font="20pxCourier";
ctx.fillStyle="Black";
ctx.textAlign="left";
ctx.textBaseline="top";
ctx.fillText("Score:"+score,blockSize,blockSize);
};
//CleartheintervalanddisplayGameOvertext
vargameOver=function(){
clearInterval(intervalId);
ctx.font="60pxCourier";
ctx.fillStyle="Black";
ctx.textAlign="center";
ctx.textBaseline="middle";
ctx.fillText("GameOver",width/2,height/2);
};
//Drawacircle(usingthefunctionfromChapter14)
varcircle=function(x,y,radius,fillCircle){
ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,false);
if(fillCircle){
ctx.fill();
}else{
ctx.stroke();
}
};
//TheBlockconstructor
➌varBlock=function(col,row){
this.col=col;
this.row=row;};
//Drawasquareattheblock'slocation
Block.prototype.drawSquare=function(color){varx=this.col*blockSize;
vary=this.row*blockSize;
ctx.fillStyle=color;
ctx.fillRect(x,y,blockSize,blockSize);
};
//Drawacircleattheblock'slocation
Block.prototype.drawCircle=function(color){
varcenterX=this.col*blockSize+blockSize/2;
varcenterY=this.row*blockSize+blockSize/2;
ctx.fillStyle=color;
circle(centerX,centerY,blockSize/2,true);};
//Checkifthisblockisinthesamelocationasanotherblock
Block.prototype.equal=function(otherBlock){
returnthis.col===otherBlock.col&&this.row===otherBlock.row;
};
//TheSnakeconstructor
➍varSnake=function(){
this.segments=[
newBlock(7,5),
newBlock(6,5),
newBlock(5,5)
];
this.direction="right";
this.nextDirection="right";
};
//Drawasquareforeachsegmentofthesnake'sbody
Snake.prototype.draw=function(){
for(vari=0;i<this.segments.length;i++){
this.segments[i].drawSquare("Blue");
}
};
//Createanewheadandaddittothebeginningof
//thesnaketomovethesnakeinitscurrentdirection
Snake.prototype.move=function(){
varhead=this.segments[0];
varnewHead;
this.direction=this.nextDirection;
if(this.direction==="right"){
newHead=newBlock(head.col+1,head.row);
}elseif(this.direction==="down"){
newHead=newBlock(head.col,head.row+1);
}elseif(this.direction==="left"){
newHead=newBlock(head.col-1,head.row);
}elseif(this.direction==="up"){
newHead=newBlock(head.col,head.row-1);
}
if(this.checkCollision(newHead)){
gameOver();
return;
}
this.segments.unshift(newHead);
if(newHead.equal(apple.position)){
score++;
apple.move();
}else{
this.segments.pop();
}
};
//Checkifthesnake'snewheadhascollidedwiththewalloritself
Snake.prototype.checkCollision=function(head){
varleftCollision=(head.col===0);
vartopCollision=(head.row===0);
varrightCollision=(head.col===widthInBlocks-1);
varbottomCollision=(head.row===heightInBlocks-1);
varwallCollision=leftCollision||topCollision||
rightCollision||bottomCollision;
varselfCollision=false;
for(vari=0;i<this.segments.length;i++){
if(head.equal(this.segments[i])){
selfCollision=true;
}
}
returnwallCollision||selfCollision;
};
//Setthesnake'snextdirectionbasedonthekeyboard
Snake.prototype.setDirection=function(newDirection){
if(this.direction==="up"&&newDirection==="down"){
return;
}elseif(this.direction==="right"&&newDirection==="left"){
return;
}elseif(this.direction==="down"&&newDirection==="up"){
return;
}elseif(this.direction==="left"&&newDirection==="right"){
return;
}
this.nextDirection=newDirection;
};
//TheAppleconstructor
➎varApple=function(){
this.position=newBlock(10,10);
};
//Drawacircleattheapple'slocation
Apple.prototype.draw=function(){
this.position.drawCircle("LimeGreen");
};
//Movetheappletoanewrandomlocation
Apple.prototype.move=function(){
varrandomCol=Math.floor(Math.random()*(widthInBlocks-2))+1;
varrandomRow=Math.floor(Math.random()*(heightInBlocks-2))+1;
this.position=newBlock(randomCol,randomRow);
};
//Createthesnakeandappleobjects
➏varsnake=newSnake();
varapple=newApple();
//PassananimationfunctiontosetInterval
varintervalId=setInterval(function(){
ctx.clearRect(0,0,width,height);
drawScore();
snake.move();
snake.draw();
apple.draw();
drawBorder();
},100);
//Convertkeycodestodirections
➐vardirections={
37:"left",
38:"up",
39:"right",
40:"down"
};
//Thekeydownhandlerforhandlingdirectionkeypresses
$("body").keydown(function(event){
varnewDirection=directions[event.keyCode];
if(newDirection!==undefined){
snake.setDirection(newDirection);
}
});
Thiscodeismadeupofanumberofsections.Thefirstsection,at➊,iswhereallthevariablesforthegamearesetup,includingthecanvas,context,width,andheight(welookedattheseinChapter16).Next,at➋,comealltheindividualfunctions:drawBorder,drawScore,gameOver,andcircle.At➌comesthecodefortheBlockconstructor,followedbyitsdrawSquare,drawCircle,andequalmethods.Then,at➍,wehavetheSnakeconstructorandallofitsmethods.Afterthat,at➎,istheAppleconstructoranditsdrawandmovemethods.
Finally,at➏,youcanseethecodethatstartsthegameandkeepsitrunning.Firstwecreatethesnakeandappleobjects.ThenweusesetIntervaltogetthegameanimationgoing.NoticethatwhenwecallsetInterval,wesavetheintervalIDinthevariableintervalIdsowecancancelitlaterinthegameOverfunction.ThefunctionpassedtosetIntervaliscalledforeverystepofthegame.Itisresponsiblefordrawingeverythingonthecanvasandforupdatingthestateofthegame.Itclearsthecanvasandthendrawsthescore,thesnake,theapple,andtheborder.Italsocallsthemovemethodonthesnake,which,asyousawearlier,movesthesnakeonestepinitscurrentdirection.AfterthecalltosetInterval,at➐,weendwiththecodeforlisteningtokeyboardeventsandsettingthesnake’sdirection.
Asalways,you’llneedtotypeallthiscodeinsidethescriptelementinyourHTMLdocument.Toplaythegame,justloadsnake.htmlinyourbrowserandusethearrowstocontrolthesnake’sdirection.Ifthearrowkeysdon’twork,youmightneedtoclickinsidethebrowserwindowtomakesureitcanpickupthekeyevents.Ifthegamedoesn’twork,theremightbeanerrorinyourJavaScript.Anyerrorwillbeoutputintheconsole,solookthereforanyhelpfulmessages.Ifyoucan’tdeterminewhythingsaren’tworking,checkeachlinecarefullyagainsttheprecedinglisting.Nowthatyouhavethegamerunning,whatdoyouthink?Howhighascorecanyouget?
WhatYouLearnedInthischapter,wemadeafullgameusingthecanvaselement.Thisgamecombinesmanyofthedatatypes,concepts,andtechniquesyoulearnedthroughoutthisbook:numbers,strings,Booleans,arrays,objects,controlstructures,functions,object-orientedprogramming,eventhandlers,setInterval,anddrawingwithcanvas.Nowthatyou’veprogrammedthisSnakegame,therearelotsofothersimpletwo-dimensionalgamesthatyoucouldwriteusingJavaScript.YoucouldmakeyourownversionofclassicgameslikeBreakout,Asteroids,SpaceInvaders,orTetris.Oryoucouldmakeupyourowngame!Ofcourse,youcanuseJavaScriptforprogramsbesidesgames.Nowthatyou’veusedJavaScripttodosomecomplicatedmath,youcoulduseittohelpwithyourmathhomework.Ormaybeyouwanttocreateawebsitetoshowoffyourprogrammingskillstotheworld.Thepossibilitiesareendless!
ProgrammingChallengesHereareafewwaysyoucouldimproveandaddfeaturestothegame.#1:MAKINGTHEGAMEBIGGERChangethesizeofthegameto500pixelssquare.Wheredoyouneedtomodifythecodetomakeitworkat500pixels?#2:COLORINGTHESNAKEOursnakeisabitboring:everysegmentofthebodyisblue.Itmightlookabitmorelikearealsnakeifyoualternatedthecolorstocreatestripes.Forexample,maketheheadgreenandthenalternatebetweenblueandyellowfortherestofthebody,orchooseyourowncolors.#3:MAKINGTHEGAMESPEEDUPASYOUPLAYModifythegamesothateverytimethesnakeeatsanapple,thegamespeedsup.Todothis,you’llhavetochangethecodetousesetTimeoutinsteadofsetInterval,becausesetIntervalkeepscallingafunctionataregularintervalthatcannotbechanged.Instead,youcanrepeatedlycallafunctionwithsetTimeoutandchangethetimeoutdelayeachtimeyoucallit:
varanimationTime=100;
vargameLoop=function(){
//Thecodethatdrawsandupdatesthegameshouldgohere
setTimeout(gameLoop,animationTime);
};
gameLoop();
InsteadofusingsetIntervaltocallafunctionrepeatedly,thegameLoopfunctioncallssetTimeout(gameLoop,animationTime),whichmeans“callgameLoopagainafteranimationTimemilliseconds.”LikesetInterval,thisisawaytocallafunctionoverandoveragain,withashortpausebetweeneachfunctioncall.ThedifferenceisthatyoucaneasilymodifytheanimationtimefromanywhereinyourcodebychanginganimationTime,andtheprogramwillusethatvalueforsubsequentcallstosetTimeout.(Oneotherthingtobearinmindhereisthatyouneedtofindanewwaytostopthegamefromloopingwhenthegameisover.Howwouldyoudothat?)#4:FIXINGTHEAPPLE.MOVEMETHODEverytimeyoumovetheapple,itmovestoanewrandomlocation,butaswrittenthere’snothingtostoptheapplefrommovingtoablockthatpartofthesnakeisalreadyoccupying.Topreventthis,modifythemovemethodtotakeintoaccountthecurrentlocationsofthesnake’ssegments.(Hint:Useawhilelooptokeepcallingmoveuntilitpicksalocationthat’snotoccupiedbythesnake.)
Afterword:WhereToGoFromHereNowthatyou’velearnedthebasicsofJavaScript,you’rereadytoventureoutintoawhole,wideworldofprogramming.Youcouldlearnanotherprogramminglanguage,oryoucouldchoosetobuildonyourknowledgeofJavaScript,takingyourskillstothenextlevel.Whereyougonextisentirelyuptoyou,butherearesomeideas.
MoreJavaScriptWe’velookedatalotofJavaScriptinthisbook,butthere’smuchmoreyoucanlearnaboutthelanguage.HerearesomebooksandwebsitesthatwillhelpyoulearnmoreofthedetailsofJavaScript:
JavaScript:TheGoodPartsbyDouglasCrockford(O’ReillyMedia,2008)EloquentJavaScript,2ndEdition,byMarijnHaverbeke(NoStarchPress,2014)JavaScript:TheDefinitiveGuide,4thEdition,byDavidFlanagan(O’ReillyMedia,2001)TheMozillaDeveloperNetwork’sJavaScriptresources:https://developer.mozilla.org/en-US/docs/Web/JavaScript/CodecademyJavaScriptcourses:http://www.codecademy.com/en/tracks/javascript/
WebProgrammingTocreatewebsites,youneedtousesomeHTMLandCSS,alongwithJavaScript.
HTMLHTMListhemarkuplanguageusedforcreatingwebpages.WelearnedsomebasicHTMLinChapter5,butthere’smuchmoretolearn.HerearesomeplacesyoucanlearnmoreaboutHTML:
TheMozillaDeveloperNetwork’sIntroductiontoHTML:https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Introduction/CodecademyHTML&CSScourse:http://www.codecademy.com/tracks/web/MozillaWebmaker:https://webmaker.org/
CSSCSS(shortforCascadingStyleSheets)isthelanguageusedtocontroltheappearanceofwebpages.LearnmoreaboutCSShere:
TheMozillaDeveloperNetwork’sGettingStartedwithCSS:https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/CodecademyHTML&CSScourse:http://www.codecademy.com/tracks/web/
Server-SideCodewithNode.jsWebpagesliveonwebservers.AserverstoresalltheHTML,CSS,andJavaScriptforawebpage,anditallowspeopletoaccessthepagefromtheInternet.Youcanalsowriteprogramsfortheserver(calledserver-sidecode)tomaketheservergeneratenewHTMLfileseachtimeawebpageisloaded.Forexample,whenyouvisithttp://twitter.com/,aprogramrunsonaserverthatfindsthelatesttweetsforyourfeed,generatesanHTMLfilecontainingthosetweets,andsendsthatfiletoyourbrowser.Node.jsletsyouwriteserver-sidecodeinJavaScript.FindoutmoreaboutNode.jswiththeselinks:
Node.jsdocumentation:http://nodejs.org/TheNodeBeginnerBook:http://www.nodebeginner.org/
GraphicalProgrammingIfyouwanttomakeinteractivegraphicsinJavaScript,youhavetwomainoptions:thecanvaselementandSVG.
CanvasWelearnedthebasicsofthecanvaselementinthisbook,butthere’smuchmoreyoucandowithit.Herearesometutorialsandgamesyoucanusetolearnmore:
TheMozillaDeveloperNetwork’sCanvasTutorial:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/CodeMonsterfromCrunchzilla:http://www.crunchzilla.com/code-monster/
SVGUsingRaphaëlSVGisanimageformatthatletsyoudrawshapesandanimatethemwithoutredrawingfromscratchforeachanimationstep.SVGprogrammingcanbedifficulttogetthehangof,butit’smucheasierifyouusetheJavaScriptlibrarycalledRaphaël.HerearesomeresourcesforlearningRaphaël:
Raphaëlwebsite:http://raphaeljs.com/AnIntroductiontotheRaphaëlJSLibrary:http://code.tutsplus.com/tutorials/an-introduction-to-the-raphael-js-library--net-7186/
3DProgrammingRememberhowinChapter13wetoldcanvaswewantedtomakea2Ddrawingcontextbycallingcanvas.getContext("2d")?It’salsopossibletodo3Dgraphicsusingcanvas.Thisisanotheroneofthoseareaswhereit’seasiertousealibrary,soI’drecommendusingthelibrarythree.js.Herearesomeresourcesforlearningthree.js:
three.jsManual:http://threejs.org/docs/index.html#ManualTheBeginner’sGuidetothree.js:http://blog.teamtreehouse.com/the-beginners-guide-to-three-js/
ProgrammingRobotsYoucanevencontrolrobotsusingJavaScript!Forexample,theParrotAR.DroneisasmallflyinghelicopterthatyoucancontrolusingNode.js.OryoucancheckoutJohnny-Five,aJavaScriptlibrarythatletsyouuseNode.jstocontroldevicessuchastheArduino(apopularmicrocontrollerthat’susedinlotsofhomemadeelectronicsandroboticsprojects).HerearesomeresourcesforlearninghowtocontrolrobotsandotherdeviceswithJavaScript:
node-ar-drone:https://github.com/felixge/node-ar-drone/NodeCopter:http://nodecopter.com/NodeBots:http://nodebots.io/Johnny-Five:https://github.com/rwaldron/johnny-five/
AudioProgrammingJavaScriptalsoallowsyoutodoadvancedaudioprogramminginwebbrowsersusingtheWebAudioAPI(shortforapplicationprogramminginterface).YoucanusetheWebAudioAPItomakesoundeffectsorevencreateyourownmusic!HerearesomeresourcesforlearningmoreabouttheWebAudioAPI:
TheMozillaDeveloperNetwork’sWebAudioAPI:https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/HTML5Rocks:GettingStartedwithWebAudioAPI:http://www.html5rocks.com/en/tutorials/webaudio/intro/
GameProgrammingIfyouwanttodomoregameprogramminginJavaScript,youmightwanttotryusingagameengine.Agameengineisacollectionofcodethathandlesalotofthelower-levelconcernsofthegame(likekeyboardandmouseinput),allowingyoutoconcentrateonthepartsthatmakeyourgamedifferent.Herearesomeresourcesyoucancheckouttolearnmoreaboutgameprogrammingandgameengines:
Craftygameengine:http://craftyjs.com/PixiRenderer:https://github.com/GoodBoyDigital/pixi.jsHTML5GameEngines:http://html5gameengine.com/UdacityHTML5GameDevelopment:https://www.udacity.com/course/cs2553DGameProgrammingforKidsbyChrisStrom(PragmaticProgrammers,2013)
SharingYourCodeUsingJSFiddleWhatifyouwanttoshareallthegreatJavaScriptyou’vewrittenwiththeworld?Therearemanywaystodothat.OneoftheeasieronesisJSFiddle(http://jsfiddle.net/).JusttypeyourJavaScriptintheJavaScriptbox,addanyHTMLyouwantintheHTMLbox,andthenclickRuntorunyourprogram.Toshareit,clickSave,whichgivesyouaURLthatyoucanthensharewithanyone.
GlossaryTheworldofcomputerprogramminghasallkindsofspecialtermsanddefinitionsthatcantakesometimetogetthehangof.Inthisglossary,you’llfinddefinitionsformanyoftheprogrammingtermsusedinthisbook.Asyou’rereadingthisbook,ifyoucomeacrossatermthatyoudon’tquiteunderstand,youcanlookhereforabriefexplanation.
argumentAvaluethatcanbepassedintoafunction.
arrayAlistofJavaScriptvalues.Inanarray,eachvaluehasanindex,whichisthenumberedpositionofthatvalueinthearray.Thefirstvalueisatindex0,thenextvalueisatindex1,andsoon.
attributeAkey-valuepairinanHTMLelement.YoucanuseHTMLattributestocontrolcertainaspectsofanelement,likewheretheelementlinkstoorthesizeoftheelement.
BooleanAvaluethatcanbeeithertrueorfalse.
callToexecuteorrunafunction.TocallfunctionsinJavaScript,youenterthefunctionnamefollowedbyapairofparentheses(withanyargumentsinsidetheparentheses).
camelcaseAcommonwaytonamevariablesinwhichyoucapitalizethefirstletterofeachword(exceptthefirstword)andthenjoinallthewordstomakeonelongword,likeso:myCamelCaseVariable.
commentTextinaprogramthatisnotexecutedbytheJavaScriptinterpreter—commentsarejusttheretodescribetheprogramforthepersonreadingthecode.
conditionalstatementAstatementthatexecutescodeaftercheckingacondition.Iftheconditionistrue,thestatementwillexecuteonebitofcode;iftheconditionisfalse,itwillexecuteadifferentbitofcodeorstopaltogether.Examplesincludeifstatementsandif...elsestatements.
constructorAkindoffunctionthat’susedtocreatemultipleobjectssothattheysharebuilt-inproperties.
controlstructureAwaytocontrolwhenapieceofcodeisrunandhowoftenit’srun.Examplesincludeconditionalstatements(whichcontrolwhencodeisrunbycheckingacondition)andloops(whichrepeatapieceofcodeacertainnumberoftimes).
dataTheinformationwestoreandmanipulateincomputerprograms.
decrement
Todecreasethevalueofavariable(usuallyby1).
dialogAsmallpop-upwindow.YoucanuseJavaScripttoopendifferentkindsofdialogsinabrowser,suchasanalert(todisplayamessage)oraprompt(toaskaquestionandreceiveinput).
documentobjectmodel(DOM)ThewaythatwebbrowsersorganizeandkeeptrackofHTMLelementsonawebpage.TheseelementsareorganizedinatreelikestructurecalledtheDOMtree.JavaScriptandjQueryprovidemethodsthatworkwiththeDOMtocreateandmodifyelements.
elementPartofanHTMLpage,suchasaheader,aparagraph,orthebody.Anelementismarkedbystartandendtags(whichdeterminewhattypeofelementitis)andincludeseverythinginbetween.TheDOMtreeismadeupoftheseelements.
eventAnactionthathappensinthebrowser,suchasamouseclickorakeyboardpressbytheuser.Wecandetectandrespondtotheseeventswitheventhandlers.
eventhandlerAfunctionthatiscalledwheneveracertaineventhappensinacertainHTMLelement.Forexample,inChapter11game,wecreateaneventhandlerfunctionthatiscalledwhenevertheuserclicksonamapimage.
executeTorunapieceofcode,suchasaprogramorfunction.
functionApieceofcodethatbundlesmultiplestatementssothattheyareallexecutedtogether.Afunctionmakesiteasytorepeatacertainactionindifferentpartsofaprogram.Afunctioncantakeargumentsasinput,anditwilloutputareturnvalue.
incrementToincreasethevalueofavariable(usuallyby1).
indexAnumberthatindicatesthepositionofavalueinsideanarray.Theindexcanbeusedtoaccessaspecificvalueinanarray.
infiniteloopAloopthatneverstopsrepeating(oftencausingtheinterpretertocrash).Thiserrorcanoccuriftheconditionsofalooparesetupincorrectly.
interpreterApieceofsoftwarethatreadsandrunscode.WebbrowserscontainaJavaScriptinterpreter,whichweusetorunourJavaScriptthroughoutthisbook.
jQueryAJavaScriptlibrarythatprovidesmanyusefulmethodsformodifyingandworkingwithDOMelementsonawebpage.
key-valuepairApairmadeupofastring(calledakey)thatismatchedupwithaparticularvalue(whichcanbeanytypeofvalue).Key-valuepairsgoinsideJavaScriptobjects,andtheyareusedtodefineanobject’spropertiesandmethods.
keywordAwordwithaspecialmeaninginJavaScript(forexample,for,return,orfunction).Keywordscan’tbeusedasvariablenames.
libraryAcollectionofJavaScriptcodethatwecanloadintoourwebpagestoprovideadditionalfunctionsandmethods.InthisbookweusethejQuerylibrary,whichgivesusfunctionsandmethodsforworkingwiththeDOMmoreeasily.
loopAwaytoexecuteapieceofcodemultipletimes.
methodAfunctionthatisapropertyofanobject.
nullAspecialvaluethatcanbeusedtoindicatethatavariableispurposelyleftempty.
objectAsetofkey-valuepairs.EachkeyisastringthatcanbepairedwithanyJavaScriptvalue.Youcanthenusethekeytoretrievewhatevervalueit’spairedwithintheobject.
object-orientedprogrammingAstyleofprogrammingthattakesadvantageofobjectsandmethodstoorganizethecodeandrepresentthemostimportantfeaturesoftheprogram.
programminglanguageAlanguagethatprogrammerscanusetotellcomputerswhattodo.JavaScriptisoneprogramminglanguage,buttherearemanyothers.
propertyAnameforakey-valuepairinanobject.
prototypeApropertyofaconstructor.Anymethodsaddedtoaconstructor’sprototypewillbeavailabletoallobjectscreatedbythatconstructor.
returnTheactofleavingafunctionandreturningtothecodethatcalledthefunction.Afunctionreturnswhenitreachestheendofitsbodyorwhenitreachesareturnkeyword(whichcanbeusedtoleaveafunctionearly).Whenafunctionreturns,itoutputsareturnvalue(ifnoparticularreturnvalueisspecified,itsimplyreturnstheemptyvalueundefined).
selectorstring
AstringthatrepresentsoneormoreHTMLelements.WecanpassthisstringtojQuery’s$functiontoselectthoseelements.
stringAlistofcharacterssurroundedbyquotes,usedtorepresenttextincomputerprograms.
syntaxHowkeywords,punctuation,andothercharactersarecombinedtomakeworkingJavaScriptprograms.
tagAmarkerusedtocreateHTMLelements.Allelementsbeginwithastarttag,andmostendwithanendtag.Thesetagsdeterminewhattypeofelementiscreated,andthestarttagcanincludeattributesfortheelement.
texteditorAcomputerprogramusedtowriteandeditplaintext,withoutanyspecialformattinglikefontstyleorcolor.Agoodtexteditorishelpfulforwritingprograms,whicharewritteninplaintext.
undefinedAvaluethatJavaScriptuseswhensomethinglikeapropertyorvariabledoesn’thaveanyparticularvalueassignedtoit.
variableAwayofgivingaJavaScriptvalueaname.Afteryouassignavaluetoavariable,youcanusethevariablenamelatertoretrievethevalue.
whitespaceInvisiblecharacterslikespaces,newlines,andtabs.
UpdatesVisithttp://www.nostarch.com/javascriptforkidsforupdates,errata,andotherinformation.
MoreSmartBooksforCuriousKids!
PYTHONFORKIDSAPlayfulIntroductiontoProgrammingbyJASONR.BRIGGSDEC2012,344PP.,$34.95ISBN978-1-59327-407-8fullcolor
RUBYWIZARDRYAnIntroductiontoProgrammingforKidsbyERICWEINSTEIN
DEC2014,360PP.,$29.95ISBN978-1-59327-566-2twocolor
LAURENIPSUMAStoryAboutComputerScienceandOtherImprobableThingsbyCARLOSBUENODEC2014,192PP.,$16.95ISBN978-1-59327-574-7fullcolor
SURVIVE!INSIDETHEHUMANBODY,VOL.1TheDigestiveSystembyGOMDORICO.andHYUN-DONGHAN
OCT2013,184PP.,$17.95ISBN978-1-59327-471-9fullcolor
ELOQUENTJAVASCRIPT,2NDEDITIONAModernIntroductiontoProgrammingbyMARIJNHAVERBEKE
DEC2014,400PP.,$39.95ISBN978-1-59327-584-6
THEMANGAGUIDETODATABASESbyMANATAKAHASHI,SHOKO
AZUMA,andTREND-PROCO.,LTD.JAN2009,224PP.,$19.95ISBN978-1-59327-190-9800.420.7240or415.863.9900|[email protected]|www.nostarch.com
IndexANOTEONTHEDIGITALINDEX
Alinkinanindexentryisdisplayedasthesectiontitleinwhichthatentryappears.Becausesomesectionshavemultipleindexmarkers,itisnotunusualforanentrytohaveseverallinkstothesamesection.Clickingonanylinkwilltakeyoudirectlytotheplaceinthetextinwhichthemarkerappears.
Symbols!(not),WhatIsJavaScript?
"(doublequotationmark),+=(plus-equals)and–=(minus-equals),CreatingObjects
#(idinselectorstrings),ReplacingtheHeadingTextUsingjQuery
$(jQueryfunction),ReplacingtheHeadingTextUsingjQuery
(seealsojQuery)
&&(and),ChangingStringstoAllCapitalorAllLowercaseLetters,Combininglogicaloperators
'(singlequotationmark),Strings
()(parentheses),NumbersandOperators,GettingaSingleCharacterfromaString,CallingaFunction
*(multiplication),NumbersandOperators
*=(multiplyandassign),+=(plus-equals)and–=(minus-equals),ProgrammingChallenges
+(addition),NumbersandOperators,JoiningStrings,ProgrammingChallenges,CreatingaPrompt
withstrings,JoiningStrings,ProgrammingChallenges,CreatingaPrompt
++(increment),AgeinSeconds
+=(addandassign),IncrementingandDecrementing,KeepingTrackofOwedMoney
,(comma),PassingMultipleArgumentstoaFunction
-(subtraction),NumbersandOperators
--(decrement),AgeinSeconds
-=(subtractandassign),IncrementingandDecrementing
.(period),KeysWithoutQuotes(seedotnotation)
/(division),NumbersandOperators
/=(divideandassign),+=(plus-equals)and–=(minus-equals)
:(colon),CreatingObjects
;(semicolon),DataTypesandVariables,PreventingInfiniteLoops
<(lessthan),GreaterThan
=(assignment),Variables
==(doubleequals),EqualTo
===(exactlyequals),EqualTo,Chainingif...elseStatements
>(greaterthan),Combininglogicaloperators
[](squarebrackets),FindingtheLengthofaString,WhyShouldYouCareAboutArrays?,CreatinganArray,AccessinganArray’sElements,MixingDataTypesinanArray,KeysWithoutQuotes
accessingacharacterfromastringwith,FindingtheLengthofaString
accessingelementsfromanarraywith,CreatinganArray,MixingDataTypesinanArray
accessingvaluesinobjectswith,KeysWithoutQuotes
addingelementstoanarraywith,AccessinganArray’sElements
creatinganarraywith,WhyShouldYouCareAboutArrays?
{}(curlybrackets),Objects,AccessingValuesinObjects
||(or),&&(and),Combininglogicaloperators
Aaddandassign(+=)operator,IncrementingandDecrementing,KeepingTrackofOwedMoney
addition,NumbersandOperators,JoiningStrings,ProgrammingChallenges,CreatingaPrompt
withstrings,JoiningStrings,ProgrammingChallenges,CreatingaPrompt
alertmethod,UsingconfirmtoAskaYesorNoQuestion
and(&&)operator,ChangingStringstoAllCapitalorAllLowercaseLetters,Combininglogicaloperators
animation,CallingCodeMultipleTimeswithsetInterval,MovingAcrossthePage,AnimatingtheSizeofaSquare,AnimatingtheSizeofaSquare,BouncingaBall!
withcanvas,MovingAcrossthePage,AnimatingtheSizeofaSquare,AnimatingtheSizeofaSquare,BouncingaBall!
bouncingball,BouncingaBall!
changingsize,AnimatingtheSizeofaSquare
movinghorizontally,MovingAcrossthePage
randombee,AnimatingtheSizeofaSquare
withsetInterval,CallingCodeMultipleTimeswithsetInterval
appendjQuerymethod,CreatingNewElementswithjQuery,DrawingtheCars
arccontextmethod,FillingPaths
arguments,forfunctions,PassingArgumentsintoFunctions,Glossary
arrays,Arrays,WhyShouldYouCareAboutArrays?,CreatinganArray,AccessinganArray’s
Elements,MixingDataTypesinanArray,WorkingwithArrays,FindingtheLengthofanArray,AddingElementstoanArray,RemovingElementsfromanArray,RemovingElementsfromanArray,JoiningMultipleArrays,FindingtheIndexofanElementinanArray,TurninganArrayintoaString,AccessingValuesinObjects,CombiningArraysandObjects,forLoops,Glossary
accessing,CreatinganArray
addingelementsto,FindingtheLengthofanArray,RemovingElementsfromanArray
anddatatypes,MixingDataTypesinanArray
combiningmultiple,RemovingElementsfromanArray
combiningwithobjects,CombiningArraysandObjects
convertingtoastring,FindingtheIndexofanElementinanArray
creating,WhyShouldYouCareAboutArrays?
findingindexofelementin,JoiningMultipleArrays
findinglengthof,WorkingwithArrays
loopingthroughelementsof,forLoops
modifying,AccessinganArray’sElements
removingelementsfrom,AddingElementstoanArray
vs.objects,AccessingValuesinObjects
assigningvalues,Variables
attributes,HTML,AddingLinkstoYourHTML,Glossary
BbeginPathcontextmethod,DrawingLinesorPaths
block-levelHTMLelements,ThepElement
body,ifStatements,whileLoops,PreventingInfiniteLoops,Functions
ofacontrolstructure,ifStatements,whileLoops,PreventingInfiniteLoops
ofafunction,Functions
bodyelement,AFullHTMLDocument
Booleans,DataTypesandVariables,ChangingStringstoAllCapitalorAllLowercaseLetters,ChangingStringstoAllCapitalorAllLowercaseLetters,Combininglogicaloperators,EmbeddingJavaScriptinHTML,CreatingaPrompt,Glossary
comparingnumberswith,Combininglogicaloperators
foryes-or-noanswers,CreatingaPrompt
inconditionalstatements,EmbeddingJavaScriptinHTML
logicaloperators,ChangingStringstoAllCapitalorAllLowercaseLetters
brackets,FindingtheLengthofaString,Objects,AccessingValuesinObjects
curly,Objects,AccessingValuesinObjects
square,FindingtheLengthofaString(seesquarebrackets)
breakkeyword,HandlingthePlayer’sInput
Ccalling,FindingtheLengthofanArray,CallingaFunction,PassingArgumentsintoFunctions,Glossary
functions,CallingaFunction,PassingArgumentsintoFunctions,Glossary
methods,FindingtheLengthofanArray
camelcase,NamingVariables,Glossary
canvaselement,TheCanvasElement,TheCanvasElement,SelectingandSavingthecanvasElement,DrawingMultipleSquares,DrawingRectangleOutlines,DrawingLinesorPaths,DrawingLinesorPaths,FillingPaths,MakingThingsMoveontheCanvas,MovingAcrossthePage,ClearingtheCanvas,AnimatingtheSizeofaSquare,AnimatingtheSizeofaSquare,BouncingaBall!,CSS
animating,MakingThingsMoveontheCanvas,MovingAcrossthePage,AnimatingtheSizeofaSquare,AnimatingtheSizeofaSquare,BouncingaBall!
bouncingball,BouncingaBall!
changingsize,AnimatingtheSizeofaSquare
movinghorizontally,MovingAcrossthePage
randombee,AnimatingtheSizeofaSquare
circlesandarcs,FillingPaths
clearing,ClearingtheCanvas
colors,DrawingMultipleSquares
creating,TheCanvasElement
linesandpaths,DrawingLinesorPaths,DrawingLinesorPaths
drawing,DrawingLinesorPaths
filling,DrawingLinesorPaths
rectanglesandsquares,SelectingandSavingthecanvasElement,DrawingRectangleOutlines
drawing,SelectingandSavingthecanvasElement
outlining,DrawingRectangleOutlines
resources,CSS
CascadingStyleSheets(CSS),CSS
chainingif...elsestatements,Chainingif...elseStatements
chainingjQueryanimations,ChainingjQueryAnimations
Chrome,webbrowserandconsole,WritingSomeJavaScript
clearIntervalfunction,CallingCodeMultipleTimeswithsetInterval
clearRectcontextmethod,MovingAcrossthePage
clearTimeoutfunction,DelayingCodewithsetTimeout
clickevents,RespondingtoUserActions
coercion,CreatingaPrompt
collisiondetection,MovingtheBall,CheckingforCollisionsandAddingtheHead
colon(:),CreatingObjects
comma(,),PassingMultipleArgumentstoaFunction
comments,Syntax,UpdatingtheGameState,Glossary
concatmethod,RemovingElementsfromanArray
condition(ofacontrolstructure),ifStatements,Chainingif...elseStatements,whileLoops,PreventingInfiniteLoops
inforloops,PreventingInfiniteLoops
inifstatements,ifStatements
inif...elsestatements,Chainingif...elseStatements
inwhileloops,whileLoops
conditionals,ConditionalsandLoops,EmbeddingJavaScriptinHTML,EmbeddingJavaScriptinHTML,ifStatements,LeavingaFunctionEarlywithreturn,Glossary
ifstatements,EmbeddingJavaScriptinHTML
if...elsestatements,EmbeddingJavaScriptinHTML,ifStatements,LeavingaFunctionEarlywithreturn
confirmfunction,CreatingaPrompt
console,WritingSomeJavaScript,CreatinganArray,ExploringObjectsintheConsole,EmbeddingJavaScriptinHTML,TheGameCode,TheCarConstructorfunction,AddingthekeydownEventHandler
callingconstructorsin,TheCarConstructorfunction
exploringobjectsin,ExploringObjectsintheConsole
findingerrorswith,TheGameCode
loggingvaluesto,EmbeddingJavaScriptinHTML
typingin,CreatinganArray
viewingoutputfromkeyboardeventswith,AddingthekeydownEventHandler
console.logmethod,EmbeddingJavaScriptinHTML,UsingconfirmtoAskaYesorNoQuestion,CallingaFunction
vs.alert,UsingconfirmtoAskaYesorNoQuestion
constructors,SharingaMethodBetweenMultipleObjects,Glossary
controlstructures,ConditionalsandLoops,Glossary
(seealsoconditionals;loops)
coordinates,browser,RespondingtoClicks
CSS(CascadingStyleSheets),CSS
cssjQuerymethod,DrawingtheCars
curlybrackets,Objects,AccessingValuesinObjects
Ddata,DataTypesandVariables,Glossary
decrementing,AgeinSeconds,Glossary
dialogs,CreatingaHangmanGame,Glossary
divideandassign(/)operator,+=(plus-equals)and–=(minus-equals)
division,NumbersandOperators
documentobjectmodel(DOM),TheDOMandjQuery,Glossary
document.getElementByIdDOMmethod,UsingidtoIdentifyElements,TheCanvasElement
DOM(documentobjectmodel),TheDOMandjQuery,Glossary
DOMtree,TheDOMandjQuery
dotnotation,KeysWithoutQuotes,AddingValuestoObjects,CombiningArraysandObjects,Object-OrientedProgramming,Object-OrientedProgramming
accessingobjectkeyswith,CombiningArraysandObjects
addingkeystoobjectswith,AddingValuestoObjects
addingmethodstoobjectswith,Object-OrientedProgramming
addingpropertiestoobjectswith,Object-OrientedProgramming
doubleequals(==)operator,EqualTo
doublequotationmark("),+=(plus-equals)and–=(minus-equals),CreatingObjects
drawingcontext(forcanvas),SelectingandSavingthecanvasElement
Eelements,HTML,TagsandElements,Glossary
elsekeyword,ifStatements,Chainingif...elseStatements
emelement,WhitespaceinHTMLandBlock-LevelElements
endtags,HTML,TagsandElements,Glossary
equalto(===)operator,EqualTo,Chainingif...elseStatements
errors,TheGameCode
eventhandlers,RespondingtoUserActions,DesigningtheGame,PickingRandomNumbers,Glossary
eventobject,RespondingtoUserActions,TheClickHandler
exactlyequals(===)operator,EqualTo,Chainingif...elseStatements
execute,WritingSomeJavaScript,Glossary
FfadeInjQuerymethod,ChainingjQueryAnimations
fadeOutjQuerymethod,CreatingNewElementswithjQuery
fadeTojQuerymethod,ProgrammingChallenges
false(Booleanvalue),DataTypesandVariables,ChangingStringstoAllCapitalorAllLowercaseLetters
(seealsoBooleans)
fillcontextmethod,DrawingLinesorPaths,ANewcircleFunction
fillRectcontextmethod,TheCanvasElement,DrawingLinesorPaths,ClearingtheCanvas,DefiningthescoreVariable,BuildingtheBlockConstructor
fillStylecontextproperty,DrawingMultipleSquares,DrawingtheBee,DefiningthescoreVariable,WritingthedrawScoreFunction,BuildingtheBlockConstructor
fillTextcontextmethod,DisplayingtheScore,SettingtheTextBaseline
FindtheBuriedTreasure!game,FindtheBuriedTreasure!,FindtheBuriedTreasure!,DesigningtheGame,CreatingtheWebPagewithHTML,PickingRandomNumbers,TheClickHandler,TellingthePlayerHowCloseTheyAre,TellingthePlayerHowCloseTheyAre,TellingthePlayerHowCloseTheyAre
calculatingdistances,TheClickHandler
clickhandler,PickingRandomNumbers
codefor,TellingthePlayerHowCloseTheyAre
creatingwebpage,DesigningtheGame
design,FindtheBuriedTreasure!
displayinghints,TellingthePlayerHowCloseTheyAre
randomizingtreasurelocation,CreatingtheWebPagewithHTML
wincondition,TellingthePlayerHowCloseTheyAre
floormethod,UsingMath.random(),ProgrammingChallenges
fontcontextproperty,SettingtheTextBaseline
forloops,PreventingInfiniteLoops
functionkeyword,PassingMultipleArgumentstoaFunction
(seealsofunctions)
functions,Functions,CallingaFunction,CallingaFunction,PassingArgumentsintoFunctions,PassingArgumentsintoFunctions,PassingMultipleArgumentstoaFunction,PassingMultipleArgumentstoaFunction,UsingFunctionstoSimplifyCode,LeavingaFunctionEarlywithreturn,LeavingaFunctionEarlywithreturn,UsingreturnMultipleTimesInsteadofif...elseStatements,Glossary,Glossary,Glossary
arguments,PassingArgumentsintoFunctions,PassingMultipleArgumentstoaFunction
calling,CallingaFunction,PassingArgumentsintoFunctions,Glossary
leavingearly,LeavingaFunctionEarlywithreturn
returningvaluesfrom,CallingaFunction,PassingMultipleArgumentstoaFunction,Glossary
shorthand,UsingreturnMultipleTimesInsteadofif...elseStatements
simplifyingcodewith,UsingFunctionstoSimplifyCode
vs.if...elsestatements,LeavingaFunctionEarlywithreturn
Ggames,programming,MeetJavaScript,AudioProgramming
(seealsoFindtheBuriedTreasure!game;Hangmangame;Snakegame)
getContextcanvasmethod,TheCanvasElement
getElementById,UsingidtoIdentifyElements,TheCanvasElement
GoogleChrome,webbrowserandconsole,WritingSomeJavaScript
graphicalprogramming,MeetJavaScript
greaterthan(>)operator,Combininglogicaloperators
Hh1element,TagsandElements
Hangmangame,CreatingaHangmanGame,WhyUsealertInsteadofconsole.log?,DesigningtheGameLoop,CodingtheGameLoop,CodingtheGameLoop,HandlingthePlayer’sInput,UpdatingtheGameState,UpdatingtheGameState,ProgrammingChallenges,ProgrammingChallenges,ProgrammingChallenges
choosingarandomword,DesigningtheGameLoop
codefor,UpdatingtheGameState
creatingwithfunctions,ProgrammingChallenges
design,WhyUsealertInsteadofconsole.log?
displayingplayer’sprogress,CodingtheGameLoop
drawing,ProgrammingChallenges,ProgrammingChallenges
guesses,ProgrammingChallenges
hangman,ProgrammingChallenges
respondingtoplayerinput,CodingtheGameLoop
updatinggamestate,HandlingthePlayer’sInput
wincondition,UpdatingtheGameState
headelement,AFullHTMLDocument
heightattribute,CreatingtheWebPagewithHTML,TheCanvasElement
hidejQuerymethod,ChainingjQueryAnimations
hrefattribute,LinkAttributes
HTML,TheBasicsofHTML,TagsandElements,AFullHTMLDocument,AFullHTMLDocument,AddingLinkstoYourHTML,TheDOMandjQuery,MoreJavaScript,Glossary,Glossary
attributes,AddingLinkstoYourHTML,Glossary
elements,TagsandElements,Glossary
hierarchy,AFullHTMLDocument
nesting,AFullHTMLDocument
htmlelement,AFullHTMLDocument,ThemousemoveEvent
hyperlinks,TheBasicsofHTML,HTMLHierarchy
Iidattribute,UsingidtoIdentifyElements,ReplacingtheHeadingTextUsingjQuery
ifstatements,EmbeddingJavaScriptinHTML
if...elsestatements,EmbeddingJavaScriptinHTML,ifStatements,LeavingaFunctionEarlywithreturn
imgelement,DesigningtheGame,PickingRandomNumbers,DrawingtheCars
incrementing,AgeinSeconds,Glossary
indexes,inarrays,CreatinganArray,AccessinganArray’sElements,MixingDataTypesinanArray,JoiningMultipleArrays,UsingMath.random(),Glossary
anddatatypes,MixingDataTypesinanArray
changingelementswith,AccessinganArray’sElements
finding,JoiningMultipleArrays
withstrings,UsingMath.random()
indexOfmethod,JoiningMultipleArrays
infiniteloops,CountingSheepwithawhileloop,Glossary
inlineHTMLelements,WhitespaceinHTMLandBlock-LevelElements
innerHTMLproperty,UsingidtoIdentifyElements
interactiveprogramming,InteractiveProgramming
intervalID,CallingCodeMultipleTimeswithsetInterval,UsingsetIntervaltoAnimatetheGame,EndingtheGame,PuttingItAllTogether
Jjoinmethod,FindingtheIndexofanElementinanArray,ProgrammingChallenges
jQuery,TheDOMandjQuery,UsingjQuerytoWorkwiththeDOMTree,UsingjQuerytoWorkwiththeDOMTree,ReplacingtheHeadingTextUsingjQuery,CreatingNewElementswithjQuery,CreatingNewElementswithjQuery,ControllingAnimationswiththeKeyboard,ReactingtotheKeyboard,Glossary
$function,ReplacingtheHeadingTextUsingjQuery
animatingelementswith,CreatingNewElementswithjQuery
creatingnewelementswith,CreatingNewElementswithjQuery
keyboardevents,respondingwith,ControllingAnimationswiththeKeyboard,ReactingtotheKeyboard
loadingonpage,UsingjQuerytoWorkwiththeDOMTree
replacingpagetextwith,UsingjQuerytoWorkwiththeDOMTree
Kkey-valuepairs(inobjects),Objects,CreatingObjects,Object-OrientedProgramming,Glossary
keyCodeeventproperty,AddingthekeydownEventHandler,SettingtheSnake’sDirectionwiththeKeyboard
keydownevent,ControllingAnimationswiththeKeyboard,ReactingtotheKeyboard,SettingtheSnake’sDirectionwiththeKeyboard
keys(inobjects),Objects,CreatingObjects,CreatingObjects,AddingValuestoObjects,Object-OrientedProgramming
adding,AddingValuestoObjects
andquotationmarks,CreatingObjects
keywords,NumbersandOperators,Glossary
Llengthproperty,JoiningStrings,WorkingwithArrays,CreatingaRandomInsultGenerator,ExploringObjectsintheConsole
onarrays,WorkingwithArrays,CreatingaRandomInsultGenerator,ExploringObjectsintheConsole
onstrings,JoiningStrings
lessthan(<)operator,GreaterThan
libraries,UsingjQuerytoWorkwiththeDOMTree,Glossary
lineTocontextmethod,DrawingLinesorPaths
lineWidthcontextproperty,DrawingRectangleOutlines,DrawingtheBee
links,TheBasicsofHTML,HTMLHierarchy
literals,Objects
logs,EmbeddingJavaScriptinHTML
loops,ConditionalsandLoops,whileLoops,PreventingInfiniteLoops,Glossary
forloops,PreventingInfiniteLoops
whileloops,whileLoops
MMath.floor,UsingMath.random(),ProgrammingChallenges
Math.PI,DrawingArcsandCircles
Math.random,UsingMath.random()
Math.sqrt,UsingthePythagoreanTheorem
mathematicaloperators,NumbersandOperators
methods,CreatinganArray,FindingtheLengthofanArray,Object-OrientedProgramming,AddingMethodstoObjects,AddingMethodstoObjects,Glossary
addingtoobjects,Object-OrientedProgramming
andthis,AddingMethodstoObjects
calling,FindingtheLengthofanArray
sharingbetweenobjects,AddingMethodstoObjects
mousemoveevent,ThemousemoveEvent,ProgrammingChallenges
moveTocontextmethod,DrawingLinesorPaths
multiplication,NumbersandOperators
multiplyandassign(*=)operator,+=(plus-equals)and–=(minus-equals),ProgrammingChallenges
musicprogramming,MeetJavaScript,AudioProgramming
Nnewkeyword,SharingaMethodBetweenMultipleObjects,DrawingtheCars
Node.js,CSS
not(!)operator,||(or)
nullvalue,DoubleEquals,CreatingaPrompt,Glossary
numbers,DataTypesandVariables,CreatinganArray,KeysWithoutQuotes
Oobject-orientedprogramming,Object-OrientedProgramming,Glossary
Object.keysmethod,AccessingValuesinObjects,StoringInformationAboutYourMovies
objects,Objects,Objects,KeysWithoutQuotes,AccessingValuesinObjects,AddingValuestoObjects,CombiningArraysandObjects,ExploringObjectsintheConsole,ExploringObjectsintheConsole,Object-OrientedProgramming,Object-OrientedProgramming,SharingaMethodBetweenMultipleObjects,CustomizingObjectswithPrototypes,Glossary
accessingvaluesin,KeysWithoutQuotes
addingkeysto,AddingValuestoObjects
addingmethodsto,Object-OrientedProgramming
addingvaluesto,AccessingValuesinObjects
combiningwitharrays,CombiningArraysandObjects
creating,Objects,Object-OrientedProgramming
customizingwithprototypes,CustomizingObjectswithPrototypes
exploringwiththeconsole,ExploringObjectsintheConsole
withconstructors,SharingaMethodBetweenMultipleObjects
offsetjQuerymethod,AnimatingElementswithsetInterval,ThemousemoveEvent,DrawingtheCars
offsetXandoffsetYeventproperties,TheClickHandler
operators,NumbersandOperators
or(||)operator,&&(and),Combininglogicaloperators
Ppelement,TagsandElements
pageXandpageYeventproperties,RespondingtoUserActions,ThemousemoveEvent
parentheses,(),NumbersandOperators,GettingaSingleCharacterfromaString,CallingaFunction
period(.),KeysWithoutQuotes(seedotnotation)
pi(π),DrawingArcsandCircles
plaintext,TheBasicsofHTML
popmethod,AddingElementstoanArray,FindingYourWayHome
promptmethod,CreatingaHangmanGame,ReplacingtheHeadingTextUsingtheDOM
properties,WorkingwithArrays,ExploringObjectsintheConsole,Object-OrientedProgramming,Glossary
prototypeproperty,CustomizingObjectswithPrototypes,TheBallConstructor
prototypes,ExploringObjectsintheConsole,CustomizingObjectswithPrototypes,TheBallConstructor
pseudocode,WhyUsealertInsteadofconsole.log?,TheStructureoftheGame
pushmethod,FindingtheLengthofanArray,FindingYourWayHome
Pythagoreantheorem,CalculatingtheDistanceBetweentheClickandtheTreasure
Qqueue(datastructure),GoinginReversewithpop
quotationmarks,+=(plus-equals)and–=(minus-equals),CreatingObjects
Rradians,FillingPaths
randomnumbergeneration,withMath.random,UsingMath.random()
returnkeyword,ReturningValuesfromFunctions,UsingFunctionstoSimplifyCode,Glossary
returningvaluesfromfunctions,CallingaFunction,PassingMultipleArgumentstoaFunction,Glossary
Sscriptelement,ConditionalsandLoops,UsingjQuerytoWorkwiththeDOMTree
selectorstrings,ReplacingtheHeadingTextUsingjQuery,Glossary
semicolons,DataTypesandVariables,PreventingInfiniteLoops
setIntervalfunction,CallingCodeMultipleTimeswithsetInterval,CallingCodeMultipleTimeswithsetInterval,MovingAcrossthePage,ChangingtheCoordinatewithanOffsetValue,BouncingtheBall,ReactingtotheKeyboard,UsingsetIntervaltoAnimatetheGame,MovingtheApple
andSnakegame,UsingsetIntervaltoAnimatetheGame,MovingtheApple
bouncingball,BouncingtheBall
movingtext,CallingCodeMultipleTimeswithsetInterval
randombee,ChangingtheCoordinatewithanOffsetValue
withcanvas,MovingAcrossthePage
withkeyboardinput,ReactingtotheKeyboard
setTimeoutfunction,InteractiveProgramming
shiftmethod,RemovingElementsfromanArray
showjQuerymethod,ChainingjQueryAnimations
singlequotationmark,Strings
slicemethod,GettingaSingleCharacterfromaString
slideDownjQuerymethod,ChainingjQueryAnimations
slideUpjQuerymethod,ChainingjQueryAnimations
Snakegame,MakingaSnakeGame:Part1,TheStructureoftheGame,SettingUpKeyboardControl,CreatingtheHTML,DefiningthescoreVariable,DisplayingtheScore,EndingtheGame,MakingaSnakeGame:Part2,BuildingtheBlockConstructor,AddingthedrawSquareMethod,AddingtheequalMethod,AddingtheequalMethod,CreatingtheSnake,DrawingtheSnake,EatingtheApple,SettingtheSnake’sDirectionwiththeKeyboard,AddingthesetDirectionMethod,DrawingtheApple,MovingtheApple
apple,AddingthesetDirectionMethod,DrawingtheApple
creating,AddingthesetDirectionMethod
moving,DrawingtheApple
codefor,MovingtheApple
collisiondetection,AddingtheequalMethod,EatingtheApple
design,TheStructureoftheGame
displayingtext,DisplayingtheScore
drawing,BuildingtheBlockConstructor,AddingthedrawSquareMethod
circle,AddingthedrawSquareMethod
square,BuildingtheBlockConstructor
endingthegame,EndingtheGame,AddingtheequalMethod
gamegrid,CreatingtheHTML,DefiningthescoreVariable,MakingaSnakeGame:Part2
addingborder,DefiningthescoreVariable
creatingBlock,MakingaSnakeGame:Part2
settingup,CreatingtheHTML
gameplay,MakingaSnakeGame:Part1
HTMLcode,SettingUpKeyboardControl
snake,CreatingtheSnake,DrawingtheSnake,SettingtheSnake’sDirectionwiththeKeyboard
creating,CreatingtheSnake
moving,DrawingtheSnake
settingdirectionof,SettingtheSnake’sDirectionwiththeKeyboard
squarebrackets,[],FindingtheLengthofaString,WhyShouldYouCareAboutArrays?,CreatinganArray,AccessinganArray’sElements,MixingDataTypesinanArray,KeysWithoutQuotes
accessingacharacterfromastringwith,FindingtheLengthofaString
accessingelementsfromanarraywith,CreatinganArray,MixingDataTypesinanArray
accessingvaluesinobjectswith,KeysWithoutQuotes
addingelementstoanarraywith,AccessinganArray’sElements
creatinganarraywith,WhyShouldYouCareAboutArrays?
squareroot,UsingthePythagoreanTheorem
srcattribute,UsingjQuerytoWorkwiththeDOMTree,CreatingtheWebPagewithHTML
stack(datastructure),GoinginReversewithpop
starttag,TagsandElements,Glossary
statements,DataTypesandVariables
strings,DataTypesandVariables,+=(plus-equals)and–=(minus-equals),JoiningStrings,JoiningStrings,FindingtheLengthofaString,GettingaSingleCharacterfromaString,CuttingUpStrings,FindingtheIndexofanElementinanArray,Objects,CreatingObjects,KeysWithoutQuotes,UsingforLoopswithArraysandStrings,HandlingthePlayer’sInput,Glossary
accessingsinglecharacterfrom,FindingtheLengthofaString
asobjectkeys,Objects,CreatingObjects,KeysWithoutQuotes
changingcaseof,CuttingUpStrings
findinglengthof,JoiningStrings
joining,JoiningStrings
loopingthrougheachcharacterof,UsingforLoopswithArraysandStrings,HandlingthePlayer’sInput
slicing,GettingaSingleCharacterfromaString
turningarraysinto,FindingtheIndexofanElementinanArray
strokecontextmethod,DrawingLinesorPaths,ANewcircleFunction
strokeRectcontextmethod,DrawingRectangleOutlines,ChangingtheCoordinatewithanOffsetValue,BouncingtheBall
strokeStylecontextproperty,DrawingRectangleOutlines,DrawingtheBee
strongelement,WhitespaceinHTMLandBlock-LevelElements
SublimeText,TheBasicsofHTML
subtractandassign(-=)operator,IncrementingandDecrementing
subtraction,NumbersandOperators
SVG,SVGUsingRaphaël
syntax,Syntax,Glossary
syntaxhighlighting,TextEditors
Ttags,HTML,TagsandElements,Glossary
texteditors,TheBasicsofHTML,Glossary
textjQuerymethod,TellingthePlayerHowCloseTheyAre
textAligncontextproperty,SettingtheTextBaseline
textBaselinecontextproperty,SettingtheTextBaseline,WritingthedrawScoreFunction
thiskeyword,AddingMethodstoObjects,TheCarConstructorfunction,AddingadrawMethodtotheCarPrototype
timeoutID,DelayingCodewithsetTimeout
titleattribute,LinkAttributes
toLowerCasemethod,CuttingUpStrings
toUpperCasemethod,CuttingUpStrings
true(Booleanvalue),DataTypesandVariables,ChangingStringstoAllCapitalorAllLowercaseLetters
(seealsoBooleans)
Uundefinedvalue,NumbersandOperators,DoubleEquals,SettingorChangingElementsinanArray,CallingaFunction,Glossary
unshiftmethod,AddingElementstoanArray
Vvalues(inobjects),Objects,CreatingObjects,CreatingObjects,KeysWithoutQuotes,AccessingValuesinObjects,Object-OrientedProgramming
accessing,KeysWithoutQuotes
adding,AccessingValuesinObjects
datatypeof,CreatingObjects
varkeyword,NumbersandOperators,Variables,NamingVariables
variables,NumbersandOperators,NamingVariables,NamingVariables,AgeinSeconds,DoubleEquals,Arrays,Glossary
creatingwithmath,NamingVariables
increasinganddecreasingvaluesof,AgeinSeconds
naming,NamingVariables
undefinedandnullfor,DoubleEquals
vs.arrays,Arrays
Wwebbrowsers,MeetJavaScript
whileloops,whileLoops
whitespace,ThepElement,WhitespaceinHTMLandBlock-LevelElements,Glossary
widthattribute,CreatingtheWebPagewithHTML,TheCanvasElement
JavaScriptforKids:APlayfulIntroductiontoProgrammingNickMorganCopyright©2014JavaScriptforKids.
Allrightsreserved.Nopartofthisworkmaybereproducedortransmittedinanyformorbyanymeans,electronicormechanical,includingphotocopying,recording,orbyanyinformationstorageorretrievalsystem,withoutthepriorwrittenpermissionofthecopyrightownerandthepublisher.
1817161514123456789
ISBN-10:1-59327-408-4
ISBN-13:978-1-59327-408-5
Publisher:WilliamPollockProductionEditor:RileyHoffmanCoverIllustration:TinaSalamehIllustrator:MiranLipovačaDevelopmentalEditors:WilliamPollockandSephKramerTechnicalReviewer:AngusCrollCopyeditor:RachelMonaghanCompositor:RileyHoffmanProofreader:PaulaL.Fleming
Forinformationondistribution,translations,orbulksales,pleasecontactNoStarchPress,Inc.directly:
NoStarchPress,Inc.
2458thStreet,SanFrancisco,CA94103
phone:415.863.9900;[email protected]
www.nostarch.com
LibraryofCongressControlNumber:2014953113
NoStarchPressandtheNoStarchPresslogoareregisteredtrademarksofNoStarchPress,Inc.Otherproductandcompanynamesmentionedhereinmaybethetrademarksoftheirrespectiveowners.Ratherthanuseatrademarksymbolwitheveryoccurrenceofatrademarkedname,weareusingthenamesonlyinaneditorialfashionandtothebenefitofthetrademarkowner,withnointentionofinfringementofthetrademark.
Theinformationinthisbookisdistributedonan“AsIs”basis,withoutwarranty.Whileeveryprecautionhasbeentakeninthepreparationofthiswork,neithertheauthornorNoStarchPress,Inc.shallhaveanyliabilitytoanypersonorentitywithrespecttoanylossordamagecausedorallegedtobecauseddirectlyorindirectlybytheinformationcontainedinit.
NoStarchPress
2014-12-02T10:57:26-08:00