Beginning-JavaScript-5th-Edition.pdf -
-
Upload
khangminh22 -
Category
Documents
-
view
7 -
download
0
Transcript of Beginning-JavaScript-5th-Edition.pdf -
CONTENTSINTRODUCTION
WHOTHISBOOKISFORWHATTHISBOOKCOVERSWHATYOUNEEDTOUSETHISBOOKCONVENTIONSSOURCECODEERRATAP2P.WROX.COM
CHAPTER1:INTRODUCTIONTOJAVASCRIPTANDTHEWEBINTRODUCTIONTOJAVASCRIPTWHEREDOMYSCRIPTSGO?YOURFIRSTSIMPLEJAVASCRIPTPROGRAMWRITINGMOREJAVASCRIPTABRIEFLOOKATBROWSERSANDCOMPATIBILITYPROBLEMSSUMMARY
CHAPTER2:DATATYPESANDVARIABLESTYPESOFDATAINJAVASCRIPTVARIABLES—STORINGDATAINMEMORYUSINGDATA—CALCULATIONSANDBASICSTRINGMANIPULATIONDATATYPECONVERSIONARRAYSSUMMARYEXERCISES
CHAPTER3:DECISIONSANDLOOPSDECISIONMAKING—THEIFANDSWITCHSTATEMENTSLOOPING—THEFORANDWHILESTATEMENTSSUMMARYEXERCISES
CHAPTER4:FUNCTIONSANDSCOPECREATINGYOUROWNFUNCTIONSSCOPEANDLIFETIMEFUNCTIONSASVALUESSUMMARY
www.allitebooks.com
EXERCISESCHAPTER5:JAVASCRIPT—ANOBJECT-BASEDLANGUAGE
OBJECT-BASEDPROGRAMMINGJAVASCRIPT’SNATIVEOBJECTTYPESCREATINGYOUROWNCUSTOMOBJECTSCREATINGNEWTYPESOFOBJECTS(REFERENCETYPES)SUMMARYEXERCISES
CHAPTER6:STRINGMANIPULATIONADDITIONALSTRINGMETHODSREGULAREXPRESSIONSTHESTRINGOBJECTUSINGTHEREGEXPOBJECT’SCONSTRUCTORSUMMARYEXERCISES
CHAPTER7:DATE,TIME,ANDTIMERSWORLDTIMETIMERSINAWEBPAGESUMMARYEXERCISES
CHAPTER8:PROGRAMMINGTHEBROWSERINTRODUCTIONTOTHEBROWSER’SOBJECTSDETERMININGTHEUSER’SBROWSERSUMMARYEXERCISES
CHAPTER9:DOMSCRIPTINGTHEWEBSTANDARDSTHEDOCUMENTOBJECTMODELMANIPULATINGTHEDOMSUMMARYEXERCISES
CHAPTER10:EVENTSTYPESOFEVENTSCONNECTINGCODETOEVENTSTHESTANDARDEVENTMODELEVENTHANDLINGINOLDVERSIONSOFINTERNETEXPLORER
www.allitebooks.com
WRITINGCROSS-BROWSERCODENATIVEDRAGANDDROPSUMMARYEXERCISES
CHAPTER11:HTMLFORMS:INTERACTINGWITHTHEUSERHTMLFORMSTRADITIONALFORMOBJECTPROPERTIESANDMETHODSHTML5FORMOBJECTPROPERTIESANDMETHODSSUMMARYEXERCISES
CHAPTER12:JSONXMLJSONSUMMARYEXERCISES
CHAPTER13:DATASTORAGEBAKINGYOURFIRSTCOOKIECREATINGACOOKIEGETTINGACOOKIE’SVALUECOOKIELIMITATIONSCOOKIESECURITYANDIEWEBSTORAGESUMMARYEXERCISES
CHAPTER14:AJAXWHATISAJAX?USINGTHEXMLHTTPREQUESTOBJECTCREATINGASIMPLEAJAXMODULEVALIDATINGFORMFIELDSWITHAJAXTHINGSTOWATCHOUTFORSUMMARYEXERCISES
CHAPTER15:HTML5MEDIAAPRIMERSCRIPTINGMEDIASUMMARY
www.allitebooks.com
EXERCISESCHAPTER16:JQUERY
GETTINGJQUERYjQUERY’SAPISUMMARYEXERCISES
CHAPTER17:OTHERJAVASCRIPTLIBRARIESDIGGINGINTOMODERNIZRDIVINGINTOPROTOTYPEDELVINGINTOMOOTOOLSSUMMARYEXERCISES
CHAPTER18:COMMONMISTAKES,DEBUGGING,ANDERRORHANDLINGD’OH!ICAN’TBELIEVEIJUSTDIDTHAT:SOMECOMMONMISTAKESERRORHANDLINGDEBUGGINGSUMMARYEXERCISES
APPENDIXA:ANSWERSTOEXERCISESCHAPTER2CHAPTER3CHAPTER4CHAPTER5CHAPTER6CHAPTER7CHAPTER8CHAPTER9CHAPTER10CHAPTER11CHAPTER12CHAPTER13CHAPTER14CHAPTER15CHAPTER16CHAPTER17CHAPTER18
www.allitebooks.com
APPENDIXB:JAVASCRIPTCOREREFERENCEBROWSERREFERENCERESERVEDWORDSJAVASCRIPTOPERATORSJAVASCRIPTSTATEMENTSTOP-LEVELPROPERTIESANDFUNCTIONSJAVASCRIPTCOREOBJECTS
APPENDIXC:W3CDOMREFERENCEDOMCOREOBJECTSHTMLDOMOBJECTSDOMEVENTMODELANDOBJECTSMISCELLANEOUSEVENTS
APPENDIXD:LATIN-1CHARACTERSETTITLEPAGECOPYRIGHTDEDICATIONCREDITSABOUTTHEAUTHORSACKNOWLEDGMENTSADVERTEULA
www.allitebooks.com
ListofIllustrationsChapter1
Figure1.1
Figure1.2
Figure1.3
Figure1.4
Chapter2
Figure2.1
Figure2.2
Figure2.3
Figure2.4
Figure2.5
Figure2.6
Figure2.7
Figure2.8
Figure2.9
Figure2.10
Figure2.11
Chapter3
Figure3.1
Figure3.2
Figure3.3
Figure3.4
Figure3.5
Figure3.6
Figure3.7
Figure3.8
Figure3.9
Figure3.10
Figure3.11
Figure3.12
www.allitebooks.com
Chapter4
Figure4.1
Figure4.2
Chapter5
Figure5.1
Figure5.2
Figure5.3
Figure5.4
Figure5.5
Figure5.6
Chapter6
Figure6.1
Figure6.2
Figure6.3
Figure6.4
Figure6.5
Figure6.6
Figure6.7
Figure6.8
Figure6.9
Figure6.10
Chapter7
Figure7.1
Figure7.2
Figure7.3
Chapter8
Figure8.1
Figure8.2
Figure8.3
Figure8.4
Chapter9
Figure9.1
www.allitebooks.com
Figure9.2
Figure9.3
Figure9.4
Figure9.5
Figure9.6
Figure9.7
Figure9.8
Figure9.9
Figure9.10
Figure9.11
Chapter10
Figure10.1
Figure10.2
Figure10.3
Figure10.4
Figure10.5
Figure10.6
Figure10.7
Figure10.8
Figure10.9
Chapter11
Figure11.1
Figure11.2
Figure11.3
Figure11.4
Figure11.5
Figure11.6
Figure11.7
Figure11.8
Figure11.9
Figure11.10
Chapter13
www.allitebooks.com
Figure13.1
Figure13.2
Figure13.3
Figure13.4
Figure13.5
Figure13.6
Figure13.7
Figure13.8
Figure13.9
Figure13.10
Figure13.11
Figure13.12
Figure13.13
Figure13.14
Figure13.15
Figure13.16
Figure13.17
Figure13.18
Figure13.19
Figure13.20
Chapter14
Figure14.1
Figure14.2
Figure14.3
Figure14.4
Figure14.5
Figure14.6
Figure14.7
Chapter15
Figure15.1
Figure15.2
Figure15.3
www.allitebooks.com
Figure15.4
Figure15.5
Figure15.6
Figure15.7
Chapter17
Figure17.1
Figure17.2
Chapter18
Figure18.1
Figure18.2
Figure18.3
Figure18.4
Figure18.5
Figure18.6
Figure18.7
Figure18.8
Figure18.9
Figure18.10
Figure18.11
Figure18.12
Figure18.13
Figure18.14
Figure18.15
Figure18.16
Figure18.17
Figure18.18
Figure18.19
Figure18.20
Figure18.21
Figure18.22
Figure18.23
Figure18.24
INTRODUCTIONJAVASCRIPTISASCRIPTINGLANGUAGEthatenablesyoutoenhancestaticwebapplicationsbyprovidingdynamic,personalized,andinteractivecontent.Thisimprovestheexperienceofvisitorstoyoursiteandmakesitmorelikelythattheywillvisitagain.Youmusthaveseentheflashydrop-downmenus,movingtext,andchangingcontentthatarenowwidespreadonwebsites—theyareenabledthroughJavaScript.Supportedbyallthemajorbrowsers,JavaScriptisthelanguageofchoiceontheweb.Itcanevenbeusedoutsidewebapplications—toautomateadministrativetasks,forexample.
ThisbookaimstoteachyouallyouneedtoknowtostartexperimentingwithJavaScript:whatitis,howitworks,andwhatyoucandowithit.Startingfromthebasicsyntax,you’llmoveontolearnhowtocreatepowerfulwebapplications.Don’tworryifyou’veneverprogrammedbefore—thisbookwillteachyouallyouneedtoknow,stepbystep.You’llfindthatJavaScriptcanbeagreatintroductiontotheworldofprogramming:withtheknowledgeandunderstandingthatyou’llgainfromthisbook,you’llbeabletomoveontolearnnewerandmoreadvancedtechnologiesintheworldofcomputing.
WHOTHISBOOKISFORTogetthemostoutofthisbook,you’llneedtohaveanunderstandingofHTML,CSS,andhowtocreateastaticwebpage.Youdon’tneedtohaveanyprogrammingexperience.
Thisbookwillalsosuityouifyouhavesomeprogrammingexperiencealreadyandwouldliketoturnyourhandtowebprogramming.Youwillknowafairamountaboutcomputingconcepts,butmaybenotasmuchaboutwebtechnologies.
Alternatively,youmayhaveadesignbackgroundandknowrelativelylittleaboutthewebandcomputingconcepts.Foryou,JavaScriptwillbeacheapandrelativelyeasyintroductiontotheworldofprogrammingandwebapplicationdevelopment.
Whoeveryouare,Ihopethatthisbooklivesuptoyourexpectations.
WHATTHISBOOKCOVERSYou’llbeginbylookingatexactlywhatJavaScriptis,andtakingyourfirststepswiththeunderlyinglanguageandsyntax.You’lllearnallthefundamentalprogrammingconcepts,includingdataanddatatypes,andstructuringyourcodetomakedecisionsinyourprogramsortoloopoverthesamepieceofcodemanytimes.
Onceyou’recomfortablewiththebasics,you’llmoveontooneofthekeyideasinJavaScript—theobject.You’lllearnhowtotakeadvantageoftheobjectsthatarenativetotheJavaScriptlanguage,suchasfunctions,dates,andstrings,andfindouthowtheseobjectsenableyoutomanagecomplexdataandsimplifyyourprograms.Next,you’llseehowyoucanuseJavaScripttomanipulateanddetectobjectsmadeavailabletoyouinthebrowseranddetectthebrowsers.
Fromhere,you’llmoveontomoreadvancedtopics,suchaswritingcodetodynamicallymanipulateelementswithinawebpageandexecutingcodewhencertainthingshappenwithinyourpage.You’llalsolearnhowtoscriptformsandothercontrols.Usingthisknowledge,youcanstarttocreatetrulyprofessional-lookingapplicationsthatenableyoutointeractwiththeuser.
You’llthenlearnhowtostoredatawithinthebrowserandcommunicatedirectlywithaserver.You’llalsolearnhowtowritecodeforthenewHTML5mediaelements,andwriteyourowncustomuserinterfaceforthem.
You’llexploresomeofthetimesavingJavaScriptframeworkssuchasjQuery,Modernizr,Prototype,andMooToolsandseehowtheyworkandhowtheycanhelpyoucreatesophisticatedJavaScriptpoweredapplications.
Finally,you’lllookatcommonsyntaxandlogicalerrors,howyoucanspotthem,andhowtousetheJavaScriptdebuggersforChrome,InternetExplorer,Firefox,Safari,andOperatoaidyouwiththistask.Also,youneedtoexaminehowtohandletheerrorsthatslipthroughthenet,andensurethatthesedonotdetractfromtheexperienceoftheenduserofyourapplication.
Allthenewconceptsintroducedinthisbookwillbeillustratedwithpracticalexamples,whichenableyoutoexperimentwithJavaScriptandbuildonthetheorythatyouhavejustlearned.
You’llfindfourappendixesattheendofthebook.AppendixAprovidessolutionstotheexercisesincludedattheendofmostchaptersthroughoutthebook.Theremainingappendixescontainthereferencematerialthatyourauthorshopeyoufindusefulandinformational.AppendixBcontainstheJavaScriptlanguage’scorereference.AppendixCcontainsacompleteW3CDOMCorereference—aswellasinformationontheHTMLDOMandDOMlevel2Eventmodel.AppendixDcontainsthedecimalandhexadecimalcharactercodesfortheLatin-1characterset.
WHATYOUNEEDTOUSETHISBOOKBecauseJavaScriptisatext-basedtechnology,allyoureallyneedtocreatedocumentscontainingJavaScriptisatexteditor.Anywilldo.
Also,inordertotryoutthecodeinthisbook,youwillneedawebbrowserthatsupportsamodernversionofJavaScript.Ideally,thismeansthelatestversionsofChrome,InternetExplorer,Firefox,Safari,andOpera.Thebookhasbeenextensivelytestedwiththesebrowsers.However,thecodeshouldworkinanymodernwebbrowser.Wherethereareexceptions,theywillbeclearlynoted.
CONVENTIONSTohelpyougetthemostfromthetextandkeeptrackofwhat’shappening,we’veusedanumberofconventionsthroughoutthebook.
TRYITOUT
TheTryItOutisanexerciseyoushouldworkthrough,followingthetextinthebook.
1. Itusuallyconsistsofasetofsteps.
2. Eachstephasanumber.
3. Followthestepswithyourcopyofthedatabase.
AsyouworkthrougheachTryItOut,thecodeyou’vetypedwillbeexplainedindetail.
WARNINGBoxeslikethisoneholdimportant,not-to-beforgotteninformationthatisdirectlyrelevanttothesurroundingtext.
NOTETips,hints,tricks,andasidestothecurrentdiscussionareoffsetandplacedinitalicslikethis.
Asforstylesinthetext:
Wehighlightinitalictypenewtermsandimportantwordswhenweintroducethem.
Weshowkeyboardstrokeslikethis:Ctrl+A.
Weshowfilenames,URLs,andcodewithinthetextlikeso:
persistence.properties.
Wepresentcodeintwodifferentways:
Importantcodeincodeexamplesishighlightedwithagraybackground.Thegrayhighlightingisnotusedforcodethat’slessimportantinthe
presentcontext,orthathasbeenshownbefore.
SOURCECODEAsyouworkthroughtheexamplesinthisbook,youmaychooseeithertotypeinallthecodemanuallyortousethesource-codefilesthataccompanythebook.Allofthesourcecodeusedinthisbookisavailablefordownloadatwww.wrox.com.Onceatthesite,simplylocatethebook’stitle(eitherbyusingtheSearchboxorbyusingoneofthetitlelists)andclicktheDownloadCodelinkonthebook’sdetailpagetoobtainallthesourcecodeforthebook.
NOTEBecausemanybookshavesimilartitles,youmayfinditeasiesttosearchbyISBN;thisbook’sISBNis978-1-118-90333-9.
Onceyoudownloadthecode,justdecompressitwithyourfavoritecompressiontool.Alternately,youcangotothemainWroxcodedownloadpageatwww.wrox.com/dynamic/books/download.aspxtoseethecodeavailableforthisbookandallotherWroxbooks.
Youcanalsoviewtheexamplespresentedinthisbookathttp://beginningjs.com.
www.allitebooks.com
ERRATAWemakeeveryefforttoensurethattherearenoerrorsinthetextorinthecode.However,nooneisperfect,andmistakesdooccur.Ifyoufindanerrorinoneofourbooks,likeaspellingmistakeorfaultypieceofcode,wewouldbeverygratefulforyourfeedback.Bysendinginerrata,youmaysaveanotherreaderhoursoffrustration,andatthesametimeyouwillbehelpingusprovideevenhigher-qualityinformation.
Tofindtheerratapageforthisbook,gotowww.wrox.comandlocatethetitleusingtheSearchboxoroneofthetitlelists.Then,onthebookdetailspage,clicktheBookErratalink.OnthispageyoucanviewallerratathathavebeensubmittedforthisbookandpostedbyWroxeditors.Acompletebooklist,includinglinkstoeachbook’serrata,isalsoavailableatwww.wrox.com/misc-pages/booklist.shtml.
Ifyoudon’tspot“your”errorontheBookErratapagegotowww.wrox.com/contact/techsupport.shtmlandcompletetheformtheretosendustheerroryouhavefound.We’llchecktheinformationand,ifappropriate,postamessagetothebook’serratapageandfixtheprobleminsubsequenteditionsofthebook.
P2P.WROX.COMForauthorandpeerdiscussion,jointheP2Pforumsatp2p.wrox.com.Theforumsareaweb-basedsystemonwhichyoucanpostmessagesrelatingtoWroxbooksandrelatedtechnologiesandinteractwithotherreadersandtechnologyusers.Theforumsofferasubscriptionfeaturetoe-mailyoutopicsofinterestofyourchoosingwhennewpostsaremadetotheforums.Wroxauthors,editors,otherindustryexperts,andyourfellowreadersarepresentontheseforums.
Athttp://p2p.wrox.comyouwillfindanumberofdifferentforumsthatwillhelpyounotonlyasyoureadthisbook,butalsoasyoudevelopyourownapplications.Tojointheforums,justfollowthesesteps:
1. Gotop2p.wrox.comandclicktheRegisterlink.
2. ReadthetermsofuseandclickAgree.
3. Completetherequiredinformationtojoinaswellasanyoptionalinformationyouwishtoprovide,andclickSubmit.
4. Youwillreceiveane-mailwithinformationdescribinghowtoverifyyouraccountandcompletethejoiningprocess.
NOTEYoucanreadmessagesintheforumswithoutjoiningP2P,butinordertopostyourownmessages,youmustjoin.
Onceyoujoin,youcanpostnewmessagesandrespondtomessagesotheruserspost.Youcanreadmessagesatanytimeontheweb.Ifyouwouldliketohavenewmessagesfromaparticularforume-mailedtoyou,clicktheSubscribetothisForumiconbytheforumnameintheforumlisting.
FormoreinformationabouthowtousetheWroxP2P,besuretoreadtheP2PFAQsforanswerstoquestionsabouthowtheforumsoftwareworks,aswellasmanycommonquestionsspecifictoP2PandWroxbooks.ToreadtheFAQs,clicktheFAQlinkonanyP2Ppage.
1IntroductiontoJavaScriptandtheWebWHATYOUWILLLEARNINTHISCHAPTER:
AddingJavaScripttoyourwebpages
ReferencingexternalJavaScriptfiles
Changingthebackgroundcolorofawebpage
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Inthisintroductorychapter,youlookatwhatJavaScriptis,whatitcandoforyou,andwhatyouneedinordertouseit.Withthesefoundationsinplace,youwillseethroughouttherestofthebookhowJavaScriptcanhelpyoutocreatepowerfulwebapplicationsforyourwebsite.
Theeasiestwaytolearnsomethingisbyactuallydoingit,sothroughoutthebookyoucreateanumberofusefulexampleprogramsusingJavaScript.Thisprocessstartsinthischapter,bytheendofwhichyouwillhavecreatedyourfirstpieceofJavaScriptcode.
INTRODUCTIONTOJAVASCRIPTInthissectionyoutakeabrieflookatwhatJavaScriptis,whereitcamefrom,howitworks,andwhatsortsofusefulthingsyoucandowithit.
WhatIsJavaScript?Havingboughtthisbook,youareprobablyalreadywellawarethatJavaScriptissomesortofcomputerlanguage,butwhatisacomputerlanguage?Putsimply,acomputerlanguageisaseriesofinstructionsthattellthecomputertodosomething.Thatsomethingcanbeoneofawidevarietyofthings,includingdisplayingtext,movinganimage,oraskingtheuserforinformation.Normally,theinstructions,orwhatistermedcode,areprocessedfromthetoplinedownward.Thissimplymeansthatthecomputerlooksatthecodeyou’vewritten,worksoutwhatactionyouwantittotake,andthentakesthataction.Theactofprocessingthecodeiscalledrunningorexecutingit.
InnaturalEnglish,hereareinstructions,orcode,youmightwritetomakeacupofinstantcoffee:
1. Putcoffeecrystalsincup.
2. Fillkettlewithwater.
3. Putkettleontoboil.
4. Hasthekettleboiled?Ifso,thenpourwaterintocup;otherwise,continuetowait.
5. Drinkcoffee.
You’dstartrunningthiscodefromthefirstline(instruction1),andthencontinuetothenext(instruction2),thenthenext,andsoonuntilyoucametotheend.Thisisprettymuchhowmostcomputerlanguageswork,JavaScriptincluded.However,onsomeoccasionsyoumightchangetheflowofexecutionorevenskipoversomecode,butyouseemoreofthisinChapter3.
JavaScriptisaninterpretedlanguageratherthanacompiledlanguage.Whatismeantbythetermsinterpretedandcompiled?
Well,toletyouinonasecret,yourcomputerdoesn’treallyunderstandJavaScriptatall.ItneedssomethingtointerprettheJavaScriptcodeandconvertitintosomethingthatitunderstands;henceitisaninterpretedlanguage.Computersunderstandonlymachinecode,whichisessentiallyastringofbinarynumbers(thatis,astringofzerosandones).AsthebrowsergoesthroughtheJavaScript,itpassesittoaspecialprogramcalledaninterpreter,whichconvertstheJavaScripttothemachinecodeyourcomputerunderstands.It’sabitlikehavingatranslatortranslateEnglishtoSpanish,forexample.TheimportantpointtonoteisthattheconversionoftheJavaScripthappensatthetimethecodeisrun;ithastoberepeatedeverytimethishappens.JavaScriptisnottheonlyinterpretedlanguage;othersexist,includingPHPandRuby.
Thealternativecompiledlanguageisoneinwhichtheprogramcodeisconvertedtomachinecodebeforeit’sactuallyrun,andthisconversionhastobedoneonlyonce.The
programmerusesacompilertoconvertthecodethathewrotetomachinecode,andthismachinecodeisrunbytheprogram’suser.CompiledlanguagesincludeC#,Java,andmanyothers.Usingareal-worldanalogy,it’sabitlikehavingaSpanishtranslatorverballytellyouinEnglishwhataSpanishdocumentsays.Unlessyouchangethedocument,youcanuseitwithoutretranslationasmuchasyoulike.
Perhapsthisisagoodplacetodispelawidespreadmyth:JavaScriptisnotthescriptversionoftheJavalanguage.Infact,althoughtheysharethesamename,that’svirtuallyalltheydoshare.ParticularlygoodnewsisthatJavaScriptismuch,mucheasiertolearnandusethanJava.Infact,languageslikeJavaScriptaretheeasiestofalllanguagestolearn,buttheyarestillsurprisinglypowerful.
JavaScriptandtheWebFormostofthisbookyoulookatJavaScriptcodethatrunsinsideawebpageloadedintoabrowser.Allyouneedtocreatethesewebpagesisatexteditor—forexample,WindowsNotepad—andawebbrowser,suchasChrome,Firefox,orInternetExplorer(IE),withwhichyoucanviewyourpages.ThesebrowserscomeequippedwithJavaScriptinterpreters(morecommonlyknownasJavaScriptengines).
NOTEThroughoutthisbook,weusetheterms“IE”and“InternetExplorer”interchangeablywhenreferringtoMicrosoft’sInternetExplorerbrowser.
Infact,theJavaScriptlanguagefirstbecameavailableinNetscape’sNavigator2.Initially,itwascalledLiveScript,butbecauseJavawasthehottechnologyofthetime,NetscapedecidedthatJavaScriptsoundedmoreexciting.WhenJavaScriptreallytookoff,MicrosoftdecidedtoadditsowndialectofJavaScript,calledJScript,toInternetExplorer3.
In1997,JavaScriptwasstandardizedbyEcmaInternational,amembership-basednon-profitorganization,andrenamedtoECMAScript.Today’sbrowsermakerslooktotheECMAScriptstandardtoimplementtheJavaScriptenginesincludedintheirrespectivebrowsers,butthatdoesn’tnecessarilymeanthatallbrowserssupportthesamefeatures.JavaScriptsupportamongtoday’sbrowsersiscertainlymoreunifiedthanithaseverbeen,butasyouseeinfuturechapters,developersstillhavetocopewitholder,andinmanycasesnon-standard,JavaScriptimplementations.
TheECMAScriptstandardcontrolsvariousaspectsofthelanguageandhelpsensurethatdifferentversionsofJavaScriptarecompatible.However,althoughEcmasetsstandardsfortheactuallanguage,itdoesn’tspecifyhowit’susedinparticularhosts.Byhost,wemeanhostingenvironment;inthisbook,thatisthewebbrowser.OtherhostingenvironmentsincludePDFfiles,webservers,andmany,manyotherplaces.Inthisbook,wediscussonlyitsusewithinthewebbrowser.TheorganizationthatsetsthestandardsforwebpagesistheWorldWideWebConsortium(W3C).ItnotonlysetsstandardsforHTMLandCSS,butalsoforhowJavaScriptinteractswithwebpagesinsideawebbrowser.Youlearnmuchmoreaboutthisinlaterchaptersofthebook.Initially,you’lllookattheessentialsofJavaScriptbeforethemoreadvancedstuff.Intheappendicesofthisbook,you’llfindusefulguidestotheJavaScriptlanguageandhowitinteractswith
thewebbrowser.
ThemajorityofthewebpagescontainingJavaScriptthatyoucreateinthisbookcanbestoredonyourharddriveandloadeddirectlyintoyourbrowserfromtheharddriveitself,justasyou’dloadanynormalfile(suchasatextfile).However,thisisnothowwebpagesareloadedwhenyoubrowsewebsitesontheInternet.TheInternetisreallyjustonegreatbignetworkconnectingcomputers.AccesstowebsitesisaspecialserviceprovidedbyparticularcomputersontheInternet;thecomputersprovidingthisserviceareknownaswebservers.
Basically,thejobofawebserveristoholdlotsofwebpagesonitsharddrive.Whenabrowser,usuallyonadifferentcomputer,requestsawebpagecontainedonthatwebserver,thewebserverloadsitfromitsownharddriveandthenpassesthepagebacktotherequestingcomputerviaaspecialcommunicationsprotocolcalledHypertextTransferProtocol(HTTP).Thecomputerrunningthewebbrowserthatmakestherequestisknownastheclient.Thinkoftheclient/serverrelationshipasabitlikeacustomer/shopkeeperrelationship.Thecustomergoesintoashopandsays,“Givemeoneofthose.”Theshopkeeperservesthecustomerbyreachingfortheitemrequestedandpassingitbacktothecustomer.Inawebsituation,theclientmachinerunningthewebbrowserislikethecustomer,andthewebserverprovidingthepagerequestedisliketheshopkeeper.
Whenyoutypeanaddressintothewebbrowser,howdoesitknowwhichwebservertogetthepagefrom?Well,justasshopshaveaddresses,say,45CentralAvenue,Sometownsville,sodowebservers.Webserversdon’thavestreetnames;instead,theyhaveInternetprotocol(IP)addresses,whichuniquelyidentifythemontheInternet.Theseconsistoffoursetsofnumbers,separatedbydots(forexample,127.0.0.1).
Ifyou’veeversurfedtheNet,you’reprobablywonderingwhatonearthwe’retalkingabout.Surelywebservershavenicewww.somewebsite.comnames,notIPaddresses?Infact,thewww.somewebsite.comnameisthe“friendly”namefortheactualIPaddress;it’sawholeloteasierforushumanstoremember.OntheInternet,thefriendlynameisconvertedtotheactualIPaddressbycomputerscalleddomainnameservers,whichyourInternetserviceproviderwillhavesetupforyou.
WhatCanJavaScriptDoforMe?JavaScriptisprimarilyusedtointeractwithusers.That’saratherbroadstatement,solet’sbreak“interactwithusers”intotwocategories:userinputvalidationandenhancement.
JavaScriptwasoriginallycreatedforvalidatingforminput.Forexample,ifyouhadaformthattakesauser’screditcarddetailsinpreparationforononlinepurchaseofgoods,you’dwanttomakesurehehadactuallyfilledinthosedetailsbeforeyousentthegoods.Youmightalsowanttocheckthatthedatabeingenteredisofthecorrecttype,suchasanumberforhisageratherthantext.
Thankstotheadvancesmadeintoday’sJavaScriptengines,JavaScriptisusedformuch,muchmorethaninput-relatedtasks.Infact,advancedJavaScript-drivenapplicationscanbecreatedthatrivalthespeedandfunctionalityofconventionaldesktopapplications.ExamplesofsuchapplicationsincludeGoogleMaps,GoogleCalendar,andevenfull-fledgedproductivitysoftwaresuchasMicrosoft’sOfficeWebApps.Theseapplications
providearealservice.Inmostoftheseapplications,JavaScriptonlypowerstheuserinterface,withtheactualdataprocessingbeingdoneontheserver.Buteventhen,JavaScriptcouldbeusedontheserverifusedwithaJavaScript-basedprocessingengine(onesuchenvironmentiscalledNode).
ToolsNeededtoCreateJavaScriptWebApplicationsThegreatnewsisthatlearningJavaScriptrequiresnoexpensivesoftwarepurchases;youcanlearnJavaScriptforfreeonanyPCorMac.Thissectiondiscusseswhattoolsareavailableandhowtoobtainthem.
DevelopmentToolsAllthatyouneedtogetstartedwritingJavaScriptcodeforwebapplicationsisasimpletexteditor,suchasNotepadforWindowsorTextEditforMacOSX.Youcanalsouseoneofthemanyadvancedtexteditorsthatprovidelinenumbering,colorcoding,searchandreplace,andsoon.Herearejustafew:
Notepad2(Windows):www.flos-freeware.ch/notepad2.html
WebMatrix(Windows):www.microsoft.com/web/webmatrix/
Brackets(Cross-Platform):brackets.io
SublimeText(Cross-Platform):www.sublimetext.com
SublimeTextisnotfreesoftware,butitdoeshaveatime-limitedevaluation.Ifyoutryitandlikeit,pleasesupportthedevelopersofthatapplication.
YoumightalsopreferaproperHTMLeditor;you’llneedonethatenablesyoutoedittheHTMLsourcecode,becausethat’swhereyouneedtoaddyourJavaScript.Anumberofverygoodtoolsspecificallyaimedatdevelopingweb-basedapplications,suchasAdobe’sDreamweaver,arealsoavailable.However,thisbookconcentratesonJavaScriptratherthananyspecificdevelopmenttool.Whenitcomestolearningthebasics,it’softenbesttowritethecodebyhandratherthanrelyonatooltodoitforyou.Thishelpsyouunderstandthefundamentalsofthelanguagebeforeyouattemptthemoreadvancedlogicthatisbeyondatool’scapability.Whenyouhaveagoodunderstandingofthebasics,youcanusetoolsastimesaverssothatyoucanspendtimeonthemoreadvancedandmoreinterestingcoding.
Onceyoubecomemoreproficient,youmayfindthatawebpageeditormakeslifeeasierbyinclusionoffeaturessuchascheckingthevalidityofyourcode,color-codingimportantJavaScriptwords,andmakingiteasiertoviewyourpagesbeforeloadingthemintoawebbrowser.Manyother,equallygood,freewebpageeditorsareavailable.AGooglesearchonwebeditingsoftwarewillbringbackalonglistofsoftwareyoucanuse.
Asyouwritewebapplicationsofincreasingcomplexity,you’llfindusefultoolsthathelpyouspotandsolveerrors.Errorsincodearewhatprogrammerscallbugs,thoughwhenourprogramsgowrong,weprefertocallthem“unexpectedadditionalfeatures.”Veryusefulinsolvingbugsaredevelopmenttoolscalleddebuggers.Debuggersletyoumonitorwhatishappeninginyourcodeasit’srunning.InChapter18,youtakeanin-depthlookat
bugsanddebuggerdevelopmenttools.
WebBrowsersInadditiontosoftwarethatletsyoueditwebpages,you’llalsoneedabrowsertoviewyourwebpages.It’sbesttodevelopyourJavaScriptcodeonthesortsofbrowsersyouexpectvisitorstousetoaccessyourwebsite.Youseelaterinthechapterthatalthoughbrowsersaremuchmorestandardsbased,differencesexistinhowtheyviewwebpagesandtreatJavaScriptcode.AlltheexamplesprovidedinthisbookhavebeentestedonChrome,IE9-11,Firefox,Safari,andOpera.Whereverapieceofcodedoesnotworkonanyofthesebrowsers,anotetothiseffectismadeinthetext.
Ifyou’rerunningWindows,you’llalmostcertainlyhaveIEinstalled.Ifnot,atriptowindows.microsoft.com/en-us/internet-explorer/download-iewillgetyouthelatestversionforyourversionofWindows.
YoucanfindChromeatwww.google.com/chrome,andyoucandownloadFirefoxatwww.getfirefox.com.
Bydefault,mostbrowsershaveJavaScriptsupportenabled,butitispossibletodisablethisfunctionalityinallbrowsersexceptFirefox.SobeforeyoustartonyourfirstJavaScriptexamplesinthenextsection,youshouldchecktomakesureJavaScriptisenabledinyourbrowser.
TodothisinChrome,youwanttomodifytheJavaScriptsettingsinContentSettings,asshowninFigure1.1.Youcanaccessthesesettingsbynavigatingtochrome://settings/contentorbyfollowingtheseinstructions:
1. GototheSettingsoptioninthemenu.
2. Clickthe“Showadvancedsettings…”link.
3. UnderPrivacy,clickthe“Contentsettings…”button.
Figure1.1
ItishardertoturnoffscriptinginInternetExplorer.ChooseInternetOptionsfromthemenu(thegeariconintheupper-rightcorner),clicktheSecuritytab,andcheckwhethertheInternetorLocalintranetoptionshavecustomsecuritysettings.Ifeitherofthemdoes,clicktheCustomLevelbuttonandscrolldowntotheScriptingsection.CheckthatActiveScriptingissettoEnable.
Afinalpointtonoteishowtoopenthecodeexamplesinyourbrowser.Forthisbook,yousimplyneedtoopenthefileonyourharddriveinwhichanexampleisstored.Youcandothisinanumberofways,buttheeasiestistojustdouble-clickthefile.
WHEREDOMYSCRIPTSGO?InsertingJavaScriptintoawebpageismuchlikeinsertinganyotherHTMLcontent;youusetagstomarkthestartandendofyourscriptcode.Theelementyouusetodothisis<script/>.Thistellsthebrowserthatthefollowingchunkoftext,boundedbytheclosing</script>tag,isnotHTMLtobedisplayed,butratherscriptcodetobeprocessed.Thechunkofcodesurroundedbythe<script>and</script>tagsiscalledascriptblock.Here’sanexample:
<script>
//JavaScriptgoeshere
</script>
Basically,whenthebrowserspots<script>tags,insteadoftryingtodisplaythecontainedtexttotheuser,itusesthebrowser’sJavaScriptenginetorunthecode’sinstructions.Ofcourse,thecodemightgiveinstructionsaboutchangestothewaythepageisdisplayedorwhatisshowninthepage,butthetextofthecodeitselfisnevershowntotheuser.
Youcanputthe<script/>elementinsidetheheader(betweenthe<head>and</head>tags)orinsidethebody(betweenthe<body>and</body>tags)oftheHTMLpage.However,althoughyoucanputthemoutsidetheseareas—forexample,beforethe<html>tagorafterthe</html>tag—thisisnotpermittedinthewebstandardsandsoisconsideredbadpractice.Today’sJavaScriptdeveloperstypicallyaddtheir<script/>elementsdirectlybeforethe</body>tag.
The<script/>elementhasatypeattributethattellsthebrowserwhattypeoftextiscontainedwithintheelement.ForJavaScript,thebestpracticeistoomitthetypeattribute(browsersautomaticallyassumethatany<script/>elementwithoutatypeattributeisJavaScript).Weusedtoalwayssetthetypeattributetotext/javascript,butwiththeintroductionoftheHTML5specification,itisnolongerconsideredgoodpracticetodoso.Onlyincludethetypeattributeifthe<script/>elementcontainssomethingotherthanJavaScript.
NOTEThe<script/>elementcanbeusedformorethanjustJavaScript.SomeJavaScript-basedtemplatingenginesuse<script/>elementstocontainsnippetsofHTML.
LinkingtoanExternalJavaScriptFileThe<script/>elementhasanotherarrowinitsquiver:thecapabilitytospecifythattheJavaScriptcodeisnotinsidethewebpage,butinsideaseparatefile.Youshouldgiveanyexternalfilesthefileextension.js.Thoughit’snotcompulsory,itdoesmakeiteasierforyoutoworkoutwhatiscontainedineachofyourfiles.
TolinktoanexternalJavaScriptfile,youneedtocreatea<script/>elementasdescribedearlieranduseitssrcattributetospecifythelocationoftheexternalfile.Forexample,imagineyou’vecreatedafilecalledMyCommonFunctions.jstowhichyouwanttolink,
www.allitebooks.com
andthefileisinthesamedirectoryasyourwebpage.The<script/>elementwouldlooklikethis:
<scriptsrc="MyCommonFunctions.js"></script>
Thewebbrowserwillreadthiscodeandincludethefilecontentsaspartofyourwebpage.Whenlinkingtoexternalfiles,youmustnotputanycodewithintheopeningandclosing<script>tags;forexample,thefollowingwouldbeinvalid:
<scriptsrc="MyCommonFunctions.js">
varmyVariable;
if(myVariable==1){
//dosomething
}
</script>
It’simportanttonotethatanopening<script>tagmustbeaccompaniedbyaclosing</script>tag.Youcannotusetheself-closingsyntaxfoundinXML.Therefore,thefollowingisinvalid:
<scriptsrc="MyCommonFunctions.js"/>
Generally,youusethe<script/>elementtoloadlocalfiles(thoseonthesamecomputerasthewebpageitself).However,youcanloadexternalfilesfromawebserverbyspecifyingthewebaddressofthefile.Forexample,ifyourfilewascalledMyCommonFunctions.jsandwasloadedonawebserverwiththedomainnamewww.mysite.com,the<script/>elementwouldlooklikethis:
<scriptsrc="http://www.mysite.com/MyCommonFunctions.js"></script>
Linkingtoanexternalfileiscommonwhenincorporatingwell-knownJavaScriptlibrariesintoawebpage.TheservershostingtheselibrariesarereferredtoasContentDeliveryNetworks,orCDNs.CDNsarerelativelysafe,butbewareoflinkingtoexternalfilesiftheyarecontrolledbyotherpeople.Itwouldgivethosepeopletheabilitytocontrolandchangeyourwebpage,soyouneedtobeverysureyoutrustthem!
AdvantagesofUsinganExternalFileThebiggestadvantageofexternalfilesiscodereuse.SayyouwriteacomplexbitofJavaScriptthatperformsageneralfunctionyoumightneedinlotsofpages.Ifyouincludethecodeinline(withinthewebpageratherthanviaanexternalfile),youneedtocutandpastethecodeintoeachwebpagethatusesit.Thisisfineaslongasyouneverneedtochangethecode,buttherealityisyouprobablywillneedtochangeorimprovethecodeatsomepoint.Ifyou’vecutandpastedthecodeto30differentwebpages,you’llneedtoupdateitin30differentplaces.Quiteaheadache!Byusingoneexternalfileandincludingitinallthepagesthatneedit,youneedtoupdatethecodeonlyonceandallthe30pagesareupdatedinstantly.Somucheasier!
Anotheradvantageofusingexternalfilesisthatthebrowserwillcachethem,muchasitdoeswithimagessharedbetweenpages.Ifyourfilesarelarge,thiscouldsavedownloadtimeandalsoreducebandwidthusage.
YOURFIRSTSIMPLEJAVASCRIPTPROGRAMEnoughtalkaboutthesubjectofJavaScript;let’swritesome!We’llstartwithasimpleexamplethatchangesthebackgroundcolorofthewebpage.
TRYITOUTPaintingthePageRed
ThisisasimpleexampleofusingJavaScripttochangethebackgroundcolorofthebrowser.Inyourtexteditor,typethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="utf-8"/>
<title>Chapter1,Example1</title>
</head>
<bodybgcolor="white">
<p>Paragraph1</p>
<script>
document.bgColor="red";
</script>
</body>
</html>
Savethepageasch1_example1.htmltoaconvenientplaceonyourharddrive,andloaditintoyourwebbrowser.YoushouldseearedwebpagewiththetextParagraph1inthetop-leftcorner.Butwait—don’tyousetthe<body>tag’sBGCOLORattributetowhite?Okay,let’slookatwhat’sgoingonhere.
Thepageiscontainedwithin<html>and</html>tags.Thisblockcontainsa<body>element.Whenyoudefinetheopening<body>tag,youuseHTMLtosetthepage’sbackgroundcolortowhite:
<bodybgcolor="white">
ThenyouletthebrowserknowthatyournextlinesofcodeareJavaScriptcodebyusingthe<script>starttag:
<script>
Everythingfromhereuntiltheclosetag,</script>,isJavaScriptandistreatedassuchbythebrowser.Withinthisscriptblock,youuseJavaScripttosetthedocument’sbackgroundcolortored:
document.bgColor="red";
Whatyoumightcallthepageisknownasthedocumentforthepurposeofscriptinginawebpage.Thedocumenthaslotsofproperties,includingitsbackgroundcolor,bgColor.Youcanreferencepropertiesofthedocumentbywritingdocument,
followedbyadot,followedbythepropertyname.Don’tworryabouttheuseofdocumentatthemoment;youlookatitingreaterdepthlaterinthebook.
NotethattheprecedinglineofcodeisanexampleofaJavaScriptstatement.Everylineofcodebetweenthe<script>and</script>tagsiscalledastatement,althoughsomestatementsmayrunontomorethanoneline.
You’llalsoseethatthere’sasemicolon(;)attheendoftheline.YouuseasemicoloninJavaScripttoindicatetheendofastatement.Inpractice,JavaScriptisveryrelaxedabouttheneedforsemicolons,andwhenyoustartanewline,JavaScriptwillusuallybeabletoworkoutwhetheryoumeantostartanewlineofcode.However,forgoodcodingpractice,youshoulduseasemicolonattheendofstatementsofcode,andasingleJavaScriptstatementshouldfitontoonelineratherthancontinueontotwoormorelines.Moreover,you’llfindsomesituationsinwhichyoumustincludeasemicolon,whichyou’llcometolaterinthebook.
Finally,totellthebrowsertostopinterpretingyourtextasJavaScriptandstartinterpretingitasHTML,youusethescriptclosetag:
</script>
You’venowlookedathowthecodeworks,butyouhaven’tlookedattheorderinwhichitworks.Whenthebrowserloadsinthewebpage,thebrowsergoesthroughit,renderingittagbytagfromtoptobottomofthepage.Thisprocessiscalledparsing.Thewebbrowserstartsatthetopofthepageandworksitswaydowntothebottomofthepage.Thebrowsercomestothe<body>tagfirstandsetsthedocument’sbackgroundtowhite.Thenitcontinuesparsingthepage.WhenitcomestotheJavaScriptcode,itisinstructedtochangethedocument’sbackgroundtored.
WRITINGMOREJAVASCRIPTThefirstexampleletyoudipyourtoesintotheJavaScriptwaters.We’llwriteafewmoreJavaScriptprogramstodemonstratethewebpageflowandoneofthemanywaystodisplayaresultinthebrowser.
TRYITOUTWayThingsFlow
Let’sextendthepreviousexampletodemonstratetheparsingofawebpageinaction.Typethefollowingintoyourtexteditor:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="utf-8"/>
<title>Chapter1,Example2</title>
</head>
<bodybgcolor="white">
<p>Paragraph1</p>
<script>
//scriptblock1
alert("FirstScriptBlock");
</script>
<p>Paragraph2</p>
<script>
//scriptblock2
alert("SecondScriptBlock");
</script>
<p>Paragraph3</p>
</body>
</html>
Savethefiletoyourharddriveasch1_example2.htmlandthenloaditintoyourbrowser.Whenyouloadthepage,youshouldseethefirstparagraph,Paragraph1,followedbyamessageboxdisplayedbythefirstscriptblock.ThebrowserhaltsitsparsinguntilyouclicktheOKbutton.AsyouseeinFigure1.2,thepagebackgroundiswhite,assetinthe<body>tag,andonlythefirstparagraphisdisplayed.
Figure1.2
ClicktheOKbutton,andtheparsingcontinues.Thebrowserdisplaysthesecondparagraph,andthesecondscriptblockisreached,whichchangesthebackgroundcolortored.Anothermessageboxisdisplayedbythesecondscriptblock,asshowninFigure1.3.
Figure1.3
ClickOK,andagaintheparsingcontinues,withthethirdparagraph,Paragraph3,beingdisplayed.Thewebpageiscomplete,asshowninFigure1.4.
Figure1.4
Thefirstpartofthepageisthesameasinourearlierexample.Thebackgroundcolorforthepageissettowhiteinthedefinitionofthe<body>tag,andthenaparagraphiswrittentothepage:
<bodybgcolor="white">
<p>Paragraph1</p>
Thefirstnewsectioniscontainedinthefirstscriptblock:
<script>
//scriptblock1
alert("FirstScriptBlock");
</script>
Thisscriptblockcontainstwolines,bothofwhicharenewtoyou.Thefirstline
//Scriptblock1
isjustacomment,solelyforyourbenefit.Thebrowserrecognizesanythingonalineafteradoubleforwardslash(//)tobeacommentanddoesnotdoanythingwithit.Itisusefulforyouasaprogrammerbecauseyoucanaddexplanationstoyourcodethatmakeiteasiertorememberwhatyouweredoingwhenyoucomebacktoyourcodelater.
Thealert()functioninthesecondlineofcodeisalsonewtoyou.Beforelearningwhatitdoes,youneedtoknowwhatafunctionis.
FunctionsaredefinedmorefullyinChapter4,butfornowyouneedonlythinkofthemaspiecesofJavaScriptcodethatyoucanusetodocertaintasks.Ifyouhaveabackgroundinmath,youmayalreadyhavesomeideaofwhatafunctionis:ittakessomeinformation,processesit,andgivesyouaresult.Afunctionmakeslifeeasier
foryouasaprogrammerbecauseyoudon’thavetothinkabouthowthefunctiondoesthetask—youcanjustconcentrateonwhenyouwantthetaskdone.
Inparticular,thealert()functionenablesyoutoalertorinformtheuseraboutsomethingbydisplayingamessagebox.Themessagetobegiveninthemessageboxisspecifiedinsidetheparenthesesofthealert()functionandisknownasthefunction’sparameter.
Themessageboxdisplayedbythealert()functionismodal.Thisisanimportantconcept,whichyou’llcomeacrossagain.Itsimplymeansthatthemessageboxwon’tgoawayuntiltheuserclosesitbyclickingtheOKbutton.Infact,parsingofthepagestopsatthelinewherethealert()functionisusedanddoesn’trestartuntiltheuserclosesthemessagebox.Thisisquiteusefulforthisexample,becauseitenablesyoutodemonstratetheresultsofwhathasbeenparsedsofar:Thepagecolorhasbeensettowhite,andthefirstparagraphhasbeendisplayed.
WhenyouclickOK,thebrowsercarriesonparsingdownthepagethroughthefollowinglines:
<p>Paragraph2</p>
<script>
//scriptblock2
document.bgColor="red";
alert("SecondScriptBlock");
</script>
Thesecondparagraphisdisplayed,andthesecondblockofJavaScriptisrun.Thefirstlineofthescriptblockcodeisanothercomment,sothebrowserignoresthis.Yousawthesecondlineofthescriptcodeinthepreviousexample—itchangesthebackgroundcolorofthepagetored.Thethirdlineofcodeisthealert()function,whichdisplaysthesecondmessagebox.ParsingisbroughttoahaltuntilyouclosethemessageboxbyclickingOK.
Whenyouclosethemessagebox,thebrowsermovesontothenextlinesofcodeinthepage,displayingthethirdparagraphand,finally,endingthewebpage:
<p>Paragraph3</p>
</body>
</html>
Anotherimportantpointraisedbythisexampleisthedifferencebetweensettingpropertiesofthepage,suchasbackgroundcolor,viaHTMLanddoingthesamethingusingJavaScript.ThemethodofsettingpropertiesusingHTMLisstatic:AvaluecanbesetonlyonceandneverchangedagainbymeansofHTML.SettingpropertiesusingJavaScriptenablesyoutodynamicallychangetheirvalues.Thetermdynamicreferstosomethingthatcanbechangedandwhosevalueorappearanceisnotsetinstone.
Thisexampleisjustthat,anexample.Inpractice,ifyouwantthepage’sbackgroundtobered,simplysetthebackgroundcolorwithCSS(don’tusethebgcolorattributeinpractice).WhereyouwanttouseJavaScriptiswhereyouwanttoaddsomesortofintelligenceorlogictothepage.Forexample,iftheuser’sscreenresolutionis
TRYITOUTDisplayingResultsinaWebPageInthisfinalexample,youdiscoverhowtowriteinformationdirectlytoawebpageusingJavaScript.Thisprovesmoreusefulwhenyou’rewritingtheresultsofacalculationortextyou’vecreatedusingJavaScript,asyouseeinthenextchapter.Fornow,you’lljustwrite“HelloWorld!”toablankpageusingJavaScript:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="utf-8"/>
<title>Chapter1,Example3</title>
</head>
<body>
<pid="results"></p>
<script>
document.getElementById("results").innerHTML="Hello
World!";
</script>
</body>
</html>
Savethepageasch1_example3.htmltoaconvenientplaceonyourharddrive.Nowloaditintoyourwebbrowserandyou’llseeHelloWorld!inthepage.AlthoughitwouldbeeasiertouseHTMLtodothesamething,thistechniquewillproveusefulinlaterchapters.
Thefirstpartofthepageisthesameasinourearlierexamples,butthingsstarttochangewhenyoureachthisline:
<pid="results"></p>
You’llnoticethe<p/>elementhasbeengivenanIDusingtheidattribute.ThisIDmustbeuniqueinthewebpage,becauseitisusedbyJavaScripttoidentifythespecificHTMLelementinthefollowingline:
document.getElementById("results").innerHTML="HelloWorld!";
Don’tworryifthisseemscomplexatthemoment;youlearnmoreabouthowthisworksinlaterchapters.Basically,thecodeissaying,“GetmetheelementwiththeIDofresultsandsettheHTMLinsidethatelementtoHelloWorld!”
It’simportantinthatthecodeaccessingtheparagraphisaftertheactual<p/>element.Otherwise,thecodewouldbeattemptingtoaccessaparagraphbeforeitexistedinthepageandwouldthrowanerror.
www.allitebooks.com
ABRIEFLOOKATBROWSERSANDCOMPATIBILITYPROBLEMSIntheprecedingexampleyousawthatbyusingJavaScriptyoucanchangeawebpage’sdocumentbackgroundcolorusingthebgColorpropertyofthedocument.TheexampleworkedregardlessofwhatbrowseryouusedbecausetheyallsupportadocumentwithabgColorproperty.Youcansaythattheexampleiscross-browsercompatible.However,it’snotalwaysthecasethatthepropertyorlanguagefeatureavailableinonebrowserwillbeavailableinanotherbrowser.Thisisevensometimesthecasebetweenversionsofthesamebrowser.
Oneofthemainheadachesinvolvedincreatingweb-basedJavaScriptisthedifferencesbetweendifferentwebbrowsers,thelevelofHTMLandCSStheysupport,andthefunctionalitytheirJavaScriptenginescanhandle.EachnewreleaseofanybrowserseesnewandexcitingfeaturesaddedtoitsHTML,CSS,andJavaScriptsupport.Thegoodnewsisthattoamuchgreaterextentthaneverbefore,browsercreatorsarecomplyingwithstandardssetbyorganizationssuchasEcmaandtheW3C.
Whichbrowsersyouwanttosupportreallycomesdowntothebrowsersyouthinkthemajorityofyourwebsite’svisitors—thatis,youruserbase—willbeusing.Thisbookisaimedatstandards-compliantbrowsers,suchasChrome,IE9+,Firefox,Safari,andOpera.
Ifyouwantyourwebsitetobeprofessional,youneedtosomehowdealwitholderbrowsers.Youcouldmakesureyourcodeisbackwardcompatible—thatis,itonlyusesfeaturesavailableinolderbrowsers.However,youmaydecidethatit’ssimplynotworthlimitingyourselftothefeaturesofolderbrowsers.Inthiscaseyouneedtomakesureyourpagesdegradegracefully.Inotherwords,makesurethatalthoughyourpageswon’tworkinolderbrowsers,theywillfailinawaythatmeanstheuseriseitherneverawareofthefailureorisalertedtothefactthatcertainfeaturesonthewebsitearenotcompatiblewithhisorherbrowser.Thealternativetodegradinggracefullyisforyourcodetoraiselotsoferrormessages,causestrangeresultstobedisplayedonthepage,andgenerallymakeyoulooklikeanidiotwhodoesn’tknowwhathe’sdoing!
Sohowdoyoumakeyourwebpagesdegradegracefully?YoucandothisbyusingJavaScripttodeterminewhichbrowserthewebpageisrunninginafterithasbeenpartiallyorcompletelyloaded.Youcanusethisinformationtodeterminewhatscriptstorunoreventoredirecttheusertoanotherpagewrittentomakebestuseofherparticularbrowser.Inlaterchapters,youseehowtofindoutwhatfeaturesthebrowsersupportsandtakeappropriateactionsothatyourpagesworkacceptablyonasmanybrowsersaspossible.
SUMMARYAtthispoint,youshouldhaveafeelforwhatJavaScriptisandwhatitcando.Inparticular,thisbriefintroductioncoveredthefollowing:
Youlookedintotheprocessthebrowserfollowswheninterpretingyourwebpage.Itgoesthroughthepageelementbyelement(parsing)andactsuponyourHTMLtagsandJavaScriptcodeasitcomestothem.
Unlikemanyprogramminglanguages,JavaScriptrequiresjustatexteditortostartcreatingcode.SomethinglikeWindowsNotepadisfineforgettingstarted,thoughmoreextensivetoolswillprovevaluableonceyougetmoreexperience.
JavaScriptcodeisembeddedintothewebpageitself,alongwiththeHTML.Itsexistenceismarkedoutbytheuseof<script/>elements.AswithHTML,thescriptexecutesfromthetopofthepageandworksdowntothebottom,interpretingandexecutingthecodestatementbystatement.
2DataTypesandVariablesWHATYOUWILLLEARNINTHISCHAPTER:
Representingdataincode
Storingdatainmemory
Makingcalculations
Convertingdata
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Oneofthemainusesofcomputersistoprocessanddisplayinformation.Byprocessing,wemeantheinformationismodified,interpreted,orfilteredinsomewaybythecomputer.Forexample,onanonlinebankingwebsite,acustomermayrequestdetailsofallmoneypaidoutfromhisaccountinthepastmonth.Herethecomputerwouldretrievetheinformation,filteroutanyinformationnotrelatedtopaymentsmadeinthepastmonth,andthendisplaywhat’sleftinawebpage.Insomesituations,informationisprocessedwithoutbeingdisplayed,andatothertimes,informationisobtaineddirectlywithoutbeingprocessed.Forexample,inabankingenvironment,regularpaymentsmaybeprocessedandtransferredelectronicallywithoutanyhumaninteractionordisplay.
Incomputing,informationisreferredtoasdata.Datacomesinallsortsofforms,suchasnumbers,text,dates,andtimes,tomentionjustafew.Inthischapter,youlookspecificallyathowJavaScripthandlesdatasuchasnumbersandtext.Anunderstandingofhowdataishandledisfundamentaltoanyprogramminglanguage.
InthischapteryoustartbylookingatthevarioustypesofdataJavaScriptcanprocess.Thenyoulookathowyoucanstorethisdatainthecomputer’smemorysoyoucanuseitagainandagaininthecode.Finally,youseehowtouseJavaScripttomanipulateandprocessthedata.
TYPESOFDATAINJAVASCRIPTDatacancomeinmanydifferentforms,ortypes.You’llrecognizesomeofthedatatypesthatJavaScripthandlesfromtheworldoutsideofprogramming—forexample,numbersandtext.Otherdatatypesarealittlemoreabstractandareusedtomakeprogrammingeasier;oneexampleistheobjectdatatype,whichyouwon’tseeindetailuntilChapter5.
Someprogramminglanguagesarestronglytyped.Intheselanguages,wheneveryouuseapieceofdata,youneedtoexplicitlystatewhatsortofdatayouaredealingwith,anduseofthatdatamustfollowstrictrulesapplicabletoitstype.Forexample,inastronglytypedlanguageyoucan’taddanumberandaword.
JavaScript,ontheotherhand,isaweaklytypedlanguageandalotmoreforgivingabouthowyouusedifferenttypesofdata.Whenyoudealwithdata,youoftendon’tneedtospecifytype;JavaScriptwillworkthatoutforitself.Furthermore,whenyouareusingdifferenttypesofdataatthesametime,JavaScriptwillworkoutbehindthesceneswhatitisyou’retryingtodo.
GivenhoweasygoingJavaScriptisaboutdata,whytalkaboutdatatypesatall?Whynotjustcuttothechaseandstartusingdatawithoutworryingaboutitstype?
Firstofall,althoughJavaScriptisverygoodatworkingoutwhatdatait’sdealingwith,onoccasionit’llgetthingswrongoratleastnotdowhatyouwantittodo.Inthesesituations,youneedtomakeitexplicittoJavaScriptwhatsortofdatatypeyouintendedandhowitshouldbeused.Todothat,youfirstneedtoknowalittlebitaboutdatatypes.
Asecondreasonisthatdatatypesenableyoutousedataeffectivelyinyourcode.Thethingsthatyoucandowithdataandtheresultsyou’llgetdependonthetypeofdatabeingused,evenifyoudon’texplicitlyspecifywhattypeitis.Forexample,althoughtryingtomultiplytwonumbersmakessense,doingthesamethingwithtextdoesn’t.Also,theresultofaddingnumbersisverydifferentfromtheresultofaddingtext.Withnumbersyougetthesum,butwithtextyougetonebigpieceoftextconsistingoftheotherpiecesjoinedtogether.
Let’stakeabrieflookatsomeofthemorecommonlyuseddatatypes:numerical,text,andboolean.Youseehowtousethemlaterinthechapter.
NumericalDataNumericaldatacomesintwoforms:
Wholenumbers,suchas145,whicharealsoknownasintegers.ThesenumberscanbepositiveornegativeandcanspanaverywiderangeinJavaScript:–253to253.
Fractionalnumbers,suchas1.234,whicharealsoknownasfloating-pointnumbers.Likeintegers,theycanbepositiveornegative,andtheyalsohaveamassiverange.
Insimpleterms,unlessyou’rewritingspecializedscientificapplications,you’renotgoingtofaceproblemswiththesizeofnumbersavailableinJavaScript.Also,althoughyoucantreatintegersandfloating-pointnumbersdifferentlywhenitcomestostoringthem,
JavaScriptactuallytreatsthembothasfloating-pointnumbers.Itkindlyhidesthedetailfromyousoyougenerallydon’tneedtoworryaboutit.Oneexceptioniswhenyouwantanintegerbutyouhaveafloating-pointnumber,inwhichcaseyou’llroundthenumbertomakeitaninteger.Youtakealookatroundingnumberslaterinthischapter.
TextDataAnothertermforoneormorecharactersoftextisastring.YoutellJavaScriptthattextistobetreatedastextandnotascodesimplybyenclosingitinsidequotationmarks(").Forexample,"HelloWorld"and"A"areexamplesofstringsthatJavaScriptwillrecognize.Youcanalsousethesinglequotationmarks('),so'HelloWorld'and'A'arealsoexamplesofstringsthatJavaScriptwillrecognize.However,youmustendthestringwiththesamequotationmarkthatyoustarteditwith.Therefore,"A'isnotavalidJavaScriptstring,andneitheris'HelloWorld".
Whatifyouwantastringwithasinglequotationmarkinthemiddle,sayastringlikePeterO'Toole?Ifyouencloseitindoublequotes,you’llbefine,so"PeterO'Toole"isrecognizedbyJavaScript.However,'PeterO'Toole'willproduceanerror.ThisisbecauseJavaScriptthinksthatyourtextstringisPeterO(thatis,ittreatsthemiddlesinglequoteasmarkingtheendofthestring)andfallsoverwonderingwhattheToole'is.
AnotherwayaroundthisistotellJavaScriptthatthemiddle'ispartofthetextandisnotindicatingtheendofthestring.Youdothisbyusingthebackslashcharacter(\),whichhasspecialmeaninginJavaScriptandisreferredtoasanescapecharacter.Thebackslashtellsthebrowserthatthenextcharacterisnottheendofthestring,butpartofthetext.So'PeterO\'Toole'willworkasplanned.
Whatifyouwanttouseadoublequoteinsideastringenclosedindoublequotes?Well,everythingjustsaidaboutthesinglequotestillapplies.So'Hello"Paul"'works,but"Hello"Paul""won’t.However,"Hello\"Paul\""willwork.
JavaScripthasalotofotherspecialcharacters,whichcan’tbetypedinbutcanberepresentedusingtheescapecharacterinconjunctionwithothercharacterstocreateescapesequences.TheseworkmuchthesameasinHTML.Forexample,morethanonespaceinarowisignoredinHTML,soaspaceisrepresentedbytheterm .Similarly,inJavaScriptyou’llfindinstanceswhereyoucan’tuseacharacterdirectlybutmustuseanescapesequence.Thefollowingtabledetailssomeofthemoreusefulescapesequences.
ESCAPESEQUENCES
CHARACTERREPRESENTED
\b Backspace\f Formfeed\n Newline\r Carriagereturn\t Tab\' Singlequote\" Doublequote\\ Backslash\xNN NNisahexadecimalnumberthatidentifiesacharacterintheLatin-
1characterset.
Theleastobviousoftheseisthelast,whichrepresentsindividualcharactersbytheircharacternumberintheLatin-1charactersetratherthanbytheirnormalappearance.Let’spickanexample:Sayyouwantedtoincludethecopyrightsymbol(©)inyourstring.Whatwouldyourstringneedtolooklike?Theansweris"\xA9PaulWilton".
Similarly,youcanrefertocharactersusingtheirUnicodeescapesequence.Thesearewritten\uNNNN,whereNNNNreferstotheUnicodenumberforthatparticularcharacter.Forexample,torefertothecopyrightsymbolusingthismethod,youusethestring\u00A9.
BooleanDataTheuseofyesorno,positiveornegative,andtrueorfalseiscommonplaceinthephysicalworld.Theideaoftrueandfalseisalsofundamentaltodigitalcomputers;theydon’tunderstandmaybes,onlytrueandfalse.Infact,theconceptof“yesorno”issousefulithasitsowndatatypeinJavaScript:thebooleandatatype.Thebooleantypehastwopossiblevalues:trueforyesandfalseforno.
ThepurposeofbooleandatainJavaScriptisjustthesameasintheworldoutsideprogramming:itenablesyoutoanswerquestionsandmakedecisionsbasedontheanswer.Forexample,ifyouareasked,“IsthisbookaboutJavaScript?”youwouldhopefullyanswer,“Yesitis,”oryoumightalsosay,“That’strue.”Similarly,youmightsay,“Ifit’sfalsethatthesubjectofthebookisJavaScript,thenputitdown.”Hereyouhaveabooleanlogicstatement(namedafteritsinventorGeorgeBoole),whichasksaquestionandthendoessomethingbasedonwhethertheansweristrueorfalse.InJavaScript,youcanusethesamesortofbooleanlogictogiveyourprogramsdecision-makingabilities.Youtakeamoredetailedlookatbooleanlogicinthenextchapter.
VARIABLES—STORINGDATAINMEMORYDatacanbestoredeitherpermanentlyortemporarily.
Youwillwanttokeepimportantdata,suchasthedetailsofaperson’sbankaccount,inapermanentstore.Forexample,whenMs.Bloggstakestendollarsorpoundsoreurosoutofheraccount,youwanttodeductthemoneyfromheraccountandkeepapermanentrecordofthenewbalance.Informationlikethismightbestoredinsomethingcalledadatabase.
However,inothercasesyoudon’twanttopermanentlystoredata,butsimplywanttokeepatemporarynoteofit.Let’slookatanexample.SayMs.BloggshasaloanfromBigBankInc.,andshewantstofindouthowmuchisstilloutstandingonthisloan.Shegoestotheonlinebankingpageforloansandclicksalinktofindouthowmuchsheowes.Thisisdatathatwillbestoredpermanentlysomewhere.However,supposeyoualsoprovideafacilityforincreasingloanrepaymentstopayofftheloanearly.IfMs.Bloggsentersanincreasedrepaymentamountintothetextboxonthewebpage,youmightwanttoshowhowmuchsoonertheloanwillbepaid.Thiswillinvolveafewpossiblycomplexcalculations,sotomakeiteasier,youwanttowritecodethatcalculatestheresultinseveralstages,storingtheresultateachstageasyougoalong,beforeprovidingafinalresult.Afteryou’vedonethecalculationanddisplayedtheresults,there’snoneedtopermanentlystoretheresultsforeachstage,soratherthanuseadatabase,youneedtousesomethingcalledavariable.Whyisitcalledavariable?Well,perhapsbecauseavariablecanbeusedtostoretemporarydatathatcanbealtered,orvaried.
Anotherbonusofvariablesisthatunlikepermanentstorage,whichmightbesavedtodiskormagnetictape,variablesareheldinthecomputer’smemory.Thismeansthatitismuch,muchfastertostoreandretrievethedata.
Sowhatmakesvariablesgoodplacesfortemporarilystoringyourdata?Well,variableshavealimitedlifetime.Whenyourvisitorsclosethepageormovetoanewone,yourvariablesarelost,unlessyoutakesomestepstosavethemsomewhere.
Yougiveeachvariableanamesothatyoucanrefertoitelsewhereinyourcode.Thesenamesmustfollowcertainrules.
AswithmuchofJavaScriptcode,variablenamesarecasesensitive.Forexample,myVariableisnotthesameasmyvariable.You’llfindthatthisisaveryeasywayforerrorstoslipintoyourcode,evenwhenyoubecomeanexpertatJavaScript.
Also,youcan’tusecertainnamesandcharactersforyourvariablenames.Namesyoucan’tusearecalledreservedwords.ReservedwordsarewordsthatJavaScriptkeepsforitsownuse(forexample,thewordvarorthewordwith).Certaincharactersarealsoforbiddeninvariablenames:forexample,theampersand(&)andthepercentsign(%).Youareallowedtousenumbersinyourvariablenames,butthenamesmustnotbeginwithnumbers.So101myVariableisnotokay,butmyVariable101is.Let’slookatsomemoreexamples.
Invalidnamesinclude:
with
99variables
my%Variable
theGood&theBad
Validnamesinclude:
myVariable99
myPercent_Variable
the_Good_and_the_Bad
Youmaywanttouseanamingconventionforyourvariables(forexample,onethatdescribeswhatsortofdatayouplantoholdinthevariable).Youcannotateyourvariablesinlotsofdifferentways—nonearerightorwrong,butit’sbesttostickwithoneofthem.
Today,theconventionmostJavaScriptdevelopersuseistosimplygivetheirvariablesdescriptivenames.Forexample,avariableforaperson’sfirstnamewouldbecalledfirstName;hisaccountnumberwouldbeaccountNumber.However,aslongasthenamesyouusemakesenseandareusedconsistently,itreallydoesn’tmatterwhatconventionyouchoose.
CreatingVariablesandGivingThemValuesBeforeyoucanuseavariable,youshoulddeclareitsexistencetotheJavaScriptengineusingthevarkeyword.Thiswarnstheenginethatitneedstoreservesomememoryinwhichtostoreyourdatalater.TodeclareanewvariablecalledmyFirstVariable,writethefollowing:
varmyFirstVariable;
Notethatthesemicolonattheendofthelineisnotpartofthevariablename,butinsteadisusedtoindicatetoJavaScripttheendofastatement.ThislineisanexampleofaJavaScriptstatement.
Oncedeclared,youcanuseavariabletostoreanytypeofdata.Asmentionedearlier,manyotherprogramminglanguages(calledstronglytypedlanguages)requireyoutodeclarenotonlythevariable,butalsothetypeofdatathatwillbestored,suchasnumbersortext.However,JavaScriptisaweaklytypedlanguage;youdon’tneedtolimityourselftowhattypeofdataavariablecanhold.
Youputdataintoyourvariables,aprocesscalledassigningvaluestoyourvariables,byusingtheequalssign(=).Forexample,ifyouwantyourvariablenamedmyFirstVariabletoholdthenumber101,youwouldwritethis:
myFirstVariable=101;
Theequalssignhasaspecialnamewhenusedtoassignvaluestoavariable;it’scalledtheassignmentoperator.
TRYITOUTDeclaringVariablesLet’slookatanexampleinwhichavariableisdeclared,storesomedatainit,andfinally,accessitscontents.You’llalsoseethatvariablescanholdanytypeofdata,andthatthetypeofdatabeingheldcanbechanged.Forexample,youcanstartbystoringtextandthenchangetostoringnumberswithoutJavaScripthavinganyproblems.Typethefollowingcodeintoyourtexteditorandsaveitasch2 _ example1.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example1</title>
</head>
<body>
<script>
varmyFirstVariable;
myFirstVariable="Hello";
alert(myFirstVariable);
myFirstVariable=54321;
alert(myFirstVariable);
</script>
</body>
</html>
Assoonasyouloadthisintoyourwebbrowser,itshouldshowanalertboxwith“Hello”init,asshowninFigure2.1.ThisisthecontentofthevariablemyFirstVariableatthatpointinthecode.
Figure2.1
ClickOKandanotheralertboxappearswith54321init,asshowninFigure2.2.ThisisthenewvalueyouassignedtothevariablemyFirstVariable.
Figure2.2
Withinthescriptblock,youfirstdeclareyourvariable:
varmyFirstVariable;
Currently,itsvalueistheundefinedvaluebecauseyou’vedeclaredonlyitsexistencetotheJavaScriptengine,notanyactualdata.Itmaysoundodd,butundefinedisanactualprimitivevalueinJavaScript,anditenablesyoutodocomparisons.(For
www.allitebooks.com
example,youcanchecktoseewhetheravariablecontainsanactualvalueorwhetherithasnotyetbeengivenavalue,thatis,whetheritisundefined.)However,inthenextlineyouassignmyFirstVariableastringvalue,namelythevalueHello:
myFirstVariable="Hello";
Hereyouhaveassignedthevariablealiteralvalue(thatis,apieceofactualdataratherthandataobtainedbyacalculationorfromanothervariable).Almostanywherethatyoucanusealiteralstringornumber,youcanreplaceitwithavariablecontainingnumberorstringdata.Youseeanexampleofthisinthenextlineofcode,whereyouuseyourvariablemyFirstVariableinthealert()functionthatyousawinthepreviouschapter:
alert(myFirstVariable);
Thiscausesthefirstalertboxtoappear.Nextyoustoreanewvalueinyourvariable,thistimeanumber:
myFirstVariable=54321;
ThepreviousvalueofmyFirstVariableislostforever.ThememoryspaceusedtostorethevalueisfreedupautomaticallybyJavaScriptinaprocesscalledgarbagecollection.WheneverJavaScriptdetectsthatthecontentsofavariablearenolongerusable,suchaswhenyouallocateanewvalue,itperformsthegarbagecollectionprocessandmakesthememoryavailable.Withoutthisautomaticgarbagecollectionprocess,moreandmoreofthecomputer’smemorywouldbeconsumed,untileventuallythecomputerwouldrunoutandthesystemwouldgrindtoahalt.However,garbagecollectionisnotalwaysasefficientasitshouldbeandmaynotoccuruntilanotherpageisloaded.
Justtoprovethatthenewvaluehasbeenstored,usethealert()functionagaintodisplaythevariable’snewcontents:
alert(myFirstVariable);
AssigningVariableswiththeValueofOtherVariablesYou’veseenthatyoucanassignavariablewithanumberorstring,butcanyouassignavariablewiththedatastoredinsideanothervariable?Theanswerisyes,veryeasily,andinexactlythesamewayasgivingavariablealiteralvalue.Forexample,ifyouhavedeclaredthetwovariablesmyVariableandmyOtherVariableandhavegiventhevariablemyOtherVariablethevalue22,likethis:
varmyVariable;
varmyOtherVariable;
myOtherVariable=22;
youcanusethefollowinglinetoassignmyVariablethesamevalueasmyOtherVariable(thatis,22):
myVariable=myOtherVariable;
TRYITOUTAssigningVariablestheValuesofOtherVariablesLet’slookatanotherexample,thistimeassigningvariablesthevaluesofothervariables.
1. Typethefollowingcodeintoyourtexteditorandsaveitasch2_example2.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example2</title>
</head>
<body>
<script>
varstring1="Hello";
varstring2="Goodbye";
alert(string1);
alert(string2);
string2=string1;
alert(string1);
alert(string2);
string1="Nowforsomethingdifferent";
alert(string1);
alert(string2);
</script>
</body>
<html>
2. Loadthepageintoyourbrowser,andyou’llseeaseriesofsixalertboxesappear.
3. ClickOKoneachalertboxtoseethenextalert.Thefirsttwoshowthevaluesofstring1andstring2—HelloandGoodbye,respectively.Thenyouassignstring2thevaluethat’sinstring1.Thenexttwoalertboxesshowthecontentsofstring1andstring2;thistimebothareHello.
4. Finally,youchangethevalueofstring1.Notethatthevalueofstring2remainsunaffected.Thefinaltwoalertboxesshowthenewvalueofstring1(Nowforsomethingdifferent)andtheunchangedvalueofstring2(Hello).
Thefirstthingyoudointhescriptblockisdeclareyourtwovariables:string1andstring2.However,noticethatyouhaveassignedthemvaluesatthesametimethatyouhavedeclaredthem.Thisisashortcut,calledinitializing,thatsavesyoutyping
toomuchcode:
varstring1="Hello";
varstring2="Goodbye";
Notethatyoucanusethisshortcutwithalldatatypes,notjuststrings.Inthenexttwolinesyouusethealert()functiontoshowthecurrentvalueofeachvariabletotheuser:
alert(string1);
alert(string2);
Thenyouassignstring2thevaluethat’scontainedinstring1.Toprovethattheassignmenthasreallyworked,youagainusethealert()functiontoshowtheuserthecontentsofeachvariable:
string2=string1;
alert(string1);
alert(string2);
Next,yousetstring1toanewvalue:
string1="Nowforsomethingdifferent";
Thisleavesstring2withitscurrentvalue,demonstratingthatstring2hasitsowncopyofthedataassignedtoitfromstring1inthepreviousstep.Youseeinlaterchaptersthatthisisnotalwaysthecase.However,asageneralrule,basicdatatypes,suchastextandnumbers,arealwayscopiedwhenassigned,whereasmorecomplexdatatypes,liketheobjectsyoucomeacrossinChapter5,areactuallysharedandnotcopied.Forexample,ifyouhaveavariablewiththestringHelloandassignfiveothervariablesthevalueofthisvariable,younowhavetheoriginaldataandfiveindependentcopiesofthedata.However,ifitwasanobjectratherthanastringandyoudidthesamething,you’dfindyoustillhaveonlyonecopyofthedata,butthatsixvariablesshareit.Changingthedatausinganyofthesixvariablenameswouldchangeitforallthevariables.
Finally,youusethealert()functiontoshowthecurrentvaluesofeachvariable:
alert(string1);
alert(string2);
USINGDATA—CALCULATIONSANDBASICSTRINGMANIPULATIONYou’veseenhowtodeclarevariablesandhowtheycanstoreinformation,butsofaryouhaven’tdoneanythingreallyusefulwiththisknowledge—sojustwhywouldyouwanttousevariablesatall?
Whatvariablesenableyoutodoistemporarilyholdinformationthatyoucanuseforprocessinginmathematicalcalculations,inbuildinguptextmessages,orinprocessingwordsthattheuserhasentered.VariablesarealittlebitliketheMemoryStorebuttonontheaveragepocketcalculator.Sayyouwereaddingupyourfinances.Youmightfirstaddupallthemoneyyouneededtospend,andthenstoreitintemporarymemory.Afteryouhadaddedupallyourmoneycomingin,youcoulddeducttheamountstoredinthememorytofigureouthowmuchwouldbeleftover.Youcanusevariablesinasimilarway:Youcanfirstgainthenecessaryuserinputandstoreitinvariables,andthenyoucandoyourcalculationsusingthevaluesobtained.
Inthissectionyouseehowyoucanputthevaluesstoredinvariablestogooduseinbothnumber-crunchingandtext-basedoperations.
NumericalCalculationsJavaScripthasarangeofbasicmathematicalcapabilities,suchasaddition,subtraction,multiplication,anddivision.Eachofthebasicmathfunctionsisrepresentedbyasymbol:plus(+),minus(−),star(*),andforwardslash(/),respectively.Thesesymbolsarecalledoperatorsbecausetheyoperateonthevaluesyougivethem.Inotherwords,theyperformsomecalculationoroperationandreturnaresult.Youcanusetheresultsofthesecalculationsalmostanywhereyou’duseanumberoravariable.
Imagineyouwerecalculatingthetotalvalueofitemsonashoppinglist.Youcouldwritethiscalculationasfollows:
Totalcostofshopping=10+5+5
Or,ifyouactuallycalculatethesum,it’s:
Totalcostofshopping=20
Nowlet’sseehowtodothisinJavaScript.Inactualfact,itisverysimilarexceptthatyouneedtouseavariabletostorethefinaltotal:
vartotalCostOfShopping;
totalCostOfShopping=10+5+5;
alert(totalCostOfShopping);
First,youdeclareavariable,totalCostOfShopping,toholdthetotalcost.
Inthesecondline,youhavethecode10+5+5.Thispieceofcodeisknownasanexpression.WhenyouassignthevariabletotalCostOfShoppingthevalueofthisexpression,JavaScriptautomaticallycalculatesthevalueoftheexpression(20)andstores
itinthevariable.NoticethattheequalssigntellsJavaScripttostoretheresultsofthecalculationinthetotalCostOfShoppingvariable.Thisiscalledassigningthevalueofthecalculationtothevariable,whichiswhythesingleequalssign(=)iscalledtheassignmentoperator.
Finally,youdisplaythevalueofthevariableinanalertbox.
Theoperatorsforsubtractionandmultiplicationworkinexactlythesameway.Divisionisalittledifferent.
TRYITOUTCalculationsLet’stakealookatanexampleusingthedivisionoperatortoseehowitworks.
1. Enterthefollowingcodeandsaveitasch2_example3.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example3</title>
</head>
<body>
<script>
varfirstNumber=15;
varsecondNumber=10;
varanswer;
answer=15/10;
alert(answer);
alert(15/10);
answer=firstNumber/secondNumber;
alert(answer);
</script>
</body>
</html>
2. Loadthisintoyourwebbrowser.Youshouldseeasuccessionofthreealertboxes,eachcontainingthevalue1.5.Thesevaluesaretheresultsofthreecalculations.
3. Thefirstthingyoudointhescriptblockisdeclareyourthreevariablesandassignthefirsttwoofthemvaluesthatyou’llbeusinglater:
varfirstNumber=15;
varsecondNumber=10;
varanswer;
4. Next,yousettheanswervariabletotheresultsofthecalculationoftheexpression15/10.Youshowthevalueofthisvariableinanalertbox:
answer=15/10;
alert(answer);
Thisexampledemonstratesonewayofdoingthecalculation,butinrealityyou’dalmostneverdoitthisway.
Todemonstratethatyoucanuseexpressionsinplacesyou’dusenumbersorvariables,youshowtheresultsofthecalculationof15/10directlybyincludingitinthealert()function:
alert(15/10);
Finally,youdothesamecalculation,butthistimeusingthetwovariables:firstNumber,whichwassetto15,andsecondNumber,whichwassetto10.YouhavetheexpressionfirstNumber/secondNumber,theresultofwhichyoustoreinyouranswervariable.Then,toproveithasallworked,youshowthevaluecontainedinanswerbyusingyourfriendthealert()function:
answer=firstNumber/secondNumber;
alert(answer);
You’lldomostcalculationsthethirdway(thatis,usingvariables,ornumbersandvariables,andstoringtheresultinanothervariable).Thereasonforthisisthatifthecalculationusedliteralvalues(actualvalues,suchas15/10),thenyoumightaswellprogramintheresultofthecalculation,ratherthanforceJavaScripttocalculateitforyou.Forexample,ratherthanwriting15/10,youmightaswelljustwrite1.5.Afterall,themorecalculationsyouforceJavaScripttodo,thesloweritwillbe,thoughadmittedlyjustonecalculationwon’ttaxittoomuch.
Anotherreasonforusingtheresultratherthanthecalculationisthatitmakescodemorereadable.Whichwouldyouprefertoreadincode:1.5*45–56/67+2.567or69.231?Stillbetter,avariablenamed,forexample,pricePerKG,makescodeeveneasiertounderstandforsomeonenotfamiliarwithit.
IncrementandDecrementOperatorsAnumberofoperationsusingthemathoperatorsaresocommonlyusedthattheyhavebeengiventheirownoperators.Thetwoyou’llbelookingatherearetheincrementanddecrementoperators,whicharerepresentedbytwoplussigns(++)andtwominussigns(−−),respectively.Basically,alltheydoisincreaseordecreaseavariable’svaluebyone.Youcouldusethenormal+and−operatorstodothis,forexample:
myVariable=myVariable+1;
myVariable=myVariable−1;
NOTEYoucanassignavariableanewvaluethatistheresultofanexpressioninvolvingitspreviousvalue.
However,usingtheincrementanddecrementoperatorsshortensthisto:
myVariable++;
myVariable−−;
Theresultisthesame—thevalueofmyVariableisincreasedordecreasedbyone—butthecodeisshorter.Whenyouarefamiliarwiththesyntax,thisbecomesveryclearandeasytoread.
Rightnow,youmaywellbethinkingthattheseoperatorssoundasusefulasapokeintheeye.However,inChapter3,whenyoulookathowyoucanrunthesamecodeanumberoftimes,you’llseethattheseoperatorsareveryusefulandwidelyused.Infact,the++operatorissowidelyusedithasacomputerlanguagenamedafterit:C++.ThejokehereisthatC++isoneupfromC.(Well,that’sprogrammerhumorforyou!)
Aswellasplacingthe++or−−afterthevariable,youcanalsoplaceitbefore,likeso:
++myVariable;
−−myVariable;
Whenthe++and−−areusedontheirown,astheyusuallyare,itmakesnodifferencewheretheyareplaced,butitispossibletousethe++and−−operatorsinanexpressionalongwithotheroperators.Forexample:
myVar=myNumber++−20;
Thiscodetakes20awayfrommyNumberandthenincrementsthevariablemyNumberbyonebeforeassigningtheresulttothevariablemyVar.Ifinsteadyouplacethe++beforeandprefixitlikethis:
myVar=++myNumber−20;
myNumberisfirstincrementedbyone,andthenmyNumberhas20subtractedfromit.It’sasubtledifference,butinsomesituationsaveryimportantone.Takethefollowingcode:
myNumber=1;
myVar=(myNumber++*10+1);
WhatvaluewillmyVarcontain?Well,becausethe++ispostfixed(it’safterthemyNumbervariable),itwillbeincrementedafterward.Sotheequationreads:MultiplymyNumberby10plus1andthenincrementmyNumberbyone.
myVar=1*10+1=11
Thenadd1tomyNumbertoget12,butdothisafterthevalue11hasbeenassignedtomyVar.Nowtakealookatthefollowingcode:
myNumber=1;
myVar=++myNumber*10+1;
ThistimemyNumberisincrementedbyonefirst,thentimes10andplus1:
myVar=2*10+1=21
Asyoucanimagine,suchsubtletycaneasilybeoverlookedandleadtobugsincode;therefore,it’susuallybesttoavoidthissyntax.
Beforegoingon,thisseemstobeagoodplacetointroduceanotheroperator:+=.Youcanusethisoperatorasashortcutforincreasingthevalueheldbyavariablebyasetamount.Forexample,
myVar+=6;
doesexactlythesamethingas:
myVar=myVar+6;
Youcanalsodothesamethingforsubtractionandmultiplication,asshownhere:
myVar−=6;
myVar*=6;
whichisequivalentto:
myVar=myVar−6;
myVar=myVar*6;
OperatorPrecedenceYou’veseenthatsymbolsthatperformsomefunction—like+,whichaddstwonumbers,and−,whichsubtractsonenumberfromanother—arecalledoperators.Unlikepeople,notalloperatorsarecreatedequal;somehaveahigherprecedence—thatis,theygetdealtwithsooner.Aquicklookatasimpleexamplewillhelpdemonstratethispoint:
varmyVariable;
myVariable=1+1*2;
alert(myVariable);
Ifyouweretotypethis,whatresultwouldyouexpectthealertboxtoshowasthevalueofmyVariable?Youmightexpectthatbecause1+1=2and2*2=4,theansweris4.Actually,you’llfindthatthealertboxshows3asthevaluestoredinmyVariableasaresultofthecalculation.Sowhatgives?Doesn’tJavaScriptaddupright?
Well,youprobablyalreadyknowthereasonfromyourunderstandingofmathematics.ThewayJavaScriptdoesthecalculationistofirstcalculate1*2=2,andthenusethisresultintheaddition,sothatJavaScriptfinishesoffwith1+2=3.
Why?Because*hasahigherprecedencethan+.The=symbol,alsoanoperator(calledtheassignmentoperator),hasthelowestprecedence—italwaysgetsleftuntillast.
The+and−operatorshaveanequalprecedence,sowhichonegetsdonefirst?Well,JavaScriptworksfromlefttoright,soifoperatorswithequalprecedenceexistinacalculation,theygetcalculatedintheorderinwhichtheyappearwhengoingfromlefttoright.Thesameappliesto*and/,whicharealsoofequalprecedence.
TRYITOUTFahrenheittoCentigrade
Takealookataslightlymorecomplexexample—aFahrenheittocentigradeconverter.(CentigradeisanothernamefortheCelsiustemperaturescale.)Typethiscodeandsaveitasch2_example4.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example4</title>
</head>
<body>
<script>
//Equationis°C=5/9(°F-32).
vardegFahren=prompt("EnterthedegreesinFahrenheit",50);
vardegCent;
degCent=5/9*(degFahren-32);
alert(degCent);
</script>
</body>
</html>
Ifyouloadthepageintoyourbrowser,youshouldseeapromptbox,likethatshowninFigure2.3,thatasksyoutoenterthedegreesinFahrenheittobeconverted.Thevalue50isalreadyfilledinbydefault.
Figure2.3
Ifyouleaveitat50andclickOK,analertboxwiththenumber10initappears.Thisrepresents50degreesFahrenheitconvertedtocentigrade.
Reloadthepageandtrychangingthevalueinthepromptboxtoseewhatresultsyouget.Forexample,changethevalueto32andreloadthepage.Thistimeyoushould
see0appearinthebox.
Becauseit’sstillafairlysimpleexample,there’snocheckingofdatainput,soit’llletyouenterabcasthedegreesFahrenheit.Later,inthe“DataTypeConversion”sectionofthischapter,youseehowtospotinvalidcharactersposingasnumericdata.
TRYITOUTSecurityIssueswithInternetExplorerWhenloadingthepagetoInternetExplorer(IE),youmayseethesecuritywarningissueshowninFigure2.4,andthepromptwindowdoesn’tappear.
Figure2.4
Ifitdoesyou’llneedtochangeIE’ssecuritysettingstoallowactivecontentfromyourcomputer.Todothis:
1. OpenIEandselectthe“Internetoptions”menufromtheToolsmenu,asshowninFigure2.5.
2. ClicktheAdvancedtabandthenscrolldowntotheSecuritysection.Checkthe“AllowactivecontenttoruninfilesonMyComputer”option,asshowninFigure2.6.
3. ClicktheOKbuttonontheInternetOptionsdialogboxandcloseInternetExplorer.OpenExample4fromthe“FahrenheittoCentigrade”TryItOutagain,andtheexamplewillnowwork.
www.allitebooks.com
Figure2.6
Thefirstlineofthescriptblockisacomment,becauseitstartswithtwoforwardslashes(//).ItcontainstheequationforconvertingFahrenheittemperaturestocentigradeandisintheexamplecodesolelyforreference:
//Equationis°C=5/9(°F-32).
YourtaskistorepresentthisequationinJavaScriptcode.Youstartbydeclaringyourvariables,degFahrenanddegCent:
vardegFahren=prompt(“EnterthedegreesinFahrenheit”,50);
vardegCent;
InsteadofinitializingthedegFahrenvariabletoaliteralvalue,yougetavaluefromtheuserusingtheprompt()function.Theprompt()functionworksinasimilarwaytoanalert()function,exceptthataswellasdisplayingamessage,italsocontainsatextboxinwhichtheusercanenteravalue.ItisthisvaluethatwillbestoredinsidethedegFahrenvariable.Thevaluereturnedisatextstring,butthiswillbeimplicitlyconvertedbyJavaScripttoanumberwhenyouuseitasanumber,asdiscussedinthesection“DataTypeConversion”laterinthischapter.
Youpasstwopiecesofinformationtotheprompt()function:
Thetexttobedisplayed—usuallyaquestionthatpromptstheuserforinput
Thedefaultvaluethatiscontainedintheinputboxwhenthepromptdialogboxfirstappears
Thesetwopiecesofinformationmustbespecifiedinthegivenorderandseparatedbyacomma.Ifyoudon’twantadefaultvaluetobecontainedintheinputboxwhenthepromptboxopens,useanemptystring("")forthesecondpieceofinformation.
Asyoucanseeintheprecedingcode,thetextis“EnterthedegreesinFahrenheit,”andthedefaultvalueintheinputboxis50.
NextinthescriptblockcomestheequationrepresentedinJavaScript.YoustoretheresultoftheequationinthedegCentvariable.YoucanseethattheJavaScriptlooksverymuchliketheequationyouhaveinthecomment,exceptyouusedegFahreninsteadof°F,anddegCentratherthan°C:
degCent=5/9*(degFahren-32);
Thecalculationoftheexpressionontheright-handsideoftheequalssignraisesanumberofimportantpoints.First,justasinmath,theJavaScriptequationisreadfromlefttoright,atleastforthebasicmathfunctionslike+,-,andsoon.Secondly,asyousawearlier,justasthereisprecedenceinmath,thereisprecedenceinJavaScript.
Startingfromtheleft,firstJavaScriptworksout5/9=.5556(approximately).Thenitcomestothemultiplication,butwait…thelastbitofyourequation,degFahren–32,isinparentheses.ThisraisestheorderofprecedenceandcausesJavaScripttocalculatetheresultofdegFahren–32beforedoingthemultiplication.Forexample,whendegFahrenissetto50,(degFahren-32)=(50–32)=18.NowJavaScriptdoesthemultiplication,.5556*18,whichisapproximately10.
Whatifyoudidn’tusetheparentheses?Thenyourcodewouldbe:
degCent=5/9*degFahren-32;
Thecalculationof5/9remainsthesame,butthenJavaScriptwouldhavecalculatedthemultiplication,5/9*degFahren.Thisisbecausethemultiplicationtakesprecedenceoverthesubtraction.WhendegFahrenis50,thisequatesto5/9*50=27.7778.Finally,JavaScriptwouldhavesubtractedthe32,leavingtheresultas–4.2221;nottheansweryouwant!
Finally,inyourscriptblock,youdisplaytheanswerusingthealert()function:
alert(degCent);
ThatconcludesabrieflookatbasiccalculationswithJavaScript.However,inChapter5youlookattheMathobject,whichenablesyoutodomorecomplexcalculations.
BasicStringOperations
Inanearliersection,youlookedatthetextorstringdatatype,aswellasnumericaldata.Justasnumericaldatahasassociatedoperators,stringshaveoperatorstoo.Thissectionintroducessomebasicstringmanipulationtechniquesusingsuchoperators.StringsarecoveredinmoredepthinChapter5,andadvancedstringhandlingiscoveredinChapter6.
Onethingyou’llfindyourselfdoingagainandagaininJavaScriptisjoiningtwostringstomakeonestring—aprocesstermedconcatenation.Forexample,youmaywanttoconcatenatethetwostrings"Hello"and"Paul"tomakethestring"HelloPaul".Sohowdoyouconcatenate?Easy!Usethe+operator.Recallthatwhenappliedtonumbers,the+operatoraddsthemup,butwhenusedinthecontextoftwostrings,itjoinsthem:
varconcatString="Hello"+"Paul";
ThestringnowstoredinthevariableconcatStringis"HelloPaul".Noticethatthelastcharacterofthestring"Hello"isaspace—ifyouleftthisout,yourconcatenatedstringwouldbe"HelloPaul".
TRYITOUTConcatenatingStringsLet’slookatanexampleusingthe+operatorforstringconcatenation.
1. Typethefollowingcodeandsaveitasch2_example5.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example5</title>
</head>
<body>
<script>
vargreetingString="Hello";
varmyName=prompt("Pleaseenteryourname","");
varconcatString;
document.write(greetingString+""+myName+"<br/>");
concatString=greetingString+""+myName;
document.write(concatString);
</script>
</body>
</html>
2. Ifyouloaditintoyourwebbrowser,youshouldseeapromptboxaskingforyourname.
3. EnteryournameandclickOK.Youshouldseeagreetingandyournamedisplayedtwiceonthewebpage.
Youstartthescriptblockbydeclaringthreevariables.Yousetthefirstvariable,greetingString,toastringvalue.Thesecondvariable,myName,isassignedto
whateverisenteredbytheuserinthepromptbox.Youdonotinitializethethirdvariable,concatString,here.Itwillbeusedtostoretheresultoftheconcatenationthatyou’lldolaterinthecode.
vargreetingString="Hello";
varmyName=prompt("Pleaseenteryourname","");
varconcatString;
Inthepreviouschapter,yousawhowthewebpagewasrepresentedbytheconceptofadocumentandthatithadanumberofdifferentproperties,suchasbgColor.YoucanalsousedocumenttowritetextandHTMLdirectlyintothepageitself.Youdothisbyusingtheworddocument,followedbyadot,andthenwrite().Youthenusedocument.write()muchasyoudothealert()function,inthatyouputthetextthatyouwantdisplayedinthewebpageinsidetheparenthesesfollowingthewordwrite.Don’tworrytoomuchaboutthishere,though,becauseitisallexplainedindetailinlaterchapters.However,younowmakeuseofdocument.write()inyourcodetowritetheresultofanexpressiontothepage:
document.write(greetingString+""+myName+"<br/>");
TheexpressionwrittentothepageistheconcatenationofthevalueofthegreetingStringvariable,aspace(""),thevalueofthemyNamevariable,andtheHTML<br/>element,whichcausesalinebreak.Forexample,ifyouenterJeremyintothepromptbox,thevalueofthisexpressionwillbeasfollows:
HelloJeremy<br/>
Inthenextlineofcodeisasimilarexpression.ThistimeitisjusttheconcatenationofthevalueinthevariablegreetingString,aspace,andthevalueinthevariablemyName.YoustoretheresultofthisexpressioninthevariableconcatString.Finally,youwritethecontentsofthevariableconcatStringtothepageusingdocument.write():
concatString=greetingString+""+myName;
document.write(concatString);
MixingNumbersandStringsWhatifyouwanttomixtextandnumbersinanexpression?Aprimeexampleofthiswouldbeinthetemperatureconverteryousawearlier.Intheexample,youjustdisplaythenumberwithouttellingtheuserwhatitactuallymeans.Whatyoureallywanttodoisdisplaythenumberwithdescriptivetextwrappedaroundit,suchas“Thevalueconvertedtodegreescentigradeis10.”
Mixingnumbersandtextisactuallyveryeasy.Youcansimplyjointhemusingthe+operator.JavaScriptisintelligentenoughtoknowthatwhenbothastringandanumberareinvolved,you’renottryingtodonumericalcalculations,butratherthatyouwanttotreatthenumberasastringandjoinittothetext.Forexample,tojointhetextMyageisandthenumber101,youcouldsimplydothefollowing:
alert("Myageis"+101);
Thiswouldproduceanalertboxwith“Myageis101”insideit.
TRYITOUTMakingtheTemperatureConverterUser-FriendlyYoucantryoutthistechniqueofconcatenatingstringsandnumbersinthetemperature-converterexample.Yououtputsomeexplanatorytext,alongwiththeresultoftheconversioncalculation.Thechangesthatyouneedtomakeareverysmall,soloadch2_example4.htmlintoyourtexteditorandchangethefollowingline.Thensaveitasch2_example6.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example6</title>
</head>
<body>
<script>
//Equationis°C=5/9(°F-32).
vardegFahren=prompt("EnterthedegreesinFahrenheit",50);
vardegCent;
degCent=5/9*(degFahren-32);
alert(degFahren+"\xB0Fahrenheitis"+degCent+"\xB0
centigrade");
</script>
</body>
</html>
Loadthepageintoyourwebbrowser.ClickOKinthepromptboxtosubmitthevalue50,andthistimeyoushouldseetheboxshowninFigure2.7.
Figure2.7
Thisexampleisidenticaltoch2 _ example4.html,exceptforoneline:
alert(degFahren+"\xB0Fahrenheitis"+degCent+"\xB0centigrade");
Sowewilljustlookatthislinehere.Youcanseethatthealert()functioncontainsanexpression.Let’slookatthatexpressionmoreclosely.
FirstisthevariabledegFahren,whichcontainsnumericaldata.Youconcatenatethattothestring"\xBOFahrenheitis“.JavaScriptrealizesthatbecauseyouareaddinganumberandastring,youwanttojointhemintoonestringratherthantryingtotaketheirsum,andsoitautomaticallyconvertsthenumbercontainedindegFahrentoastring.YounextconcatenatethisstringtothevariabledegCent,containingnumericaldata.AgainJavaScriptconvertsthevalueofthisvariabletoastring.Finally,youconcatenatetothestring"\xBOcentigrade".
Notealsotheescapesequenceusedtoinsertthedegreecharacterintothestrings.You’llrememberfromearlierinthechapterthatyoucanuse\xNNtoinsertspecialcharactersnotavailabletotypeindirectly.(NNisahexadecimalnumberrepresentingacharacterfromtheLatin-1charactertable.)SowhenJavaScriptspots\xB0inastring,insteadofshowingthosecharactersitdoesalookuptoseewhatcharacterisrepresentedbyB0andshowsthatinstead.
Somethingtobeawareofwhenusingspecialcharactersisthattheyarenotnecessarilycross-platform–compatible.Althoughyoucanuse\xNNforacertaincharacteronaWindowscomputer,youmayfindyouneedtouseadifferentcharacteronaMacoraUnixmachine.
YoulookatmorestringmanipulationtechniquesinChapter5—youseehowtosearchstringsandinsertcharactersinthemiddleofthem,andinChapter6youseesomeverysophisticatedstringtechniques.
DATATYPECONVERSIONAsyou’veseen,ifyouaddastringandanumber,JavaScriptmakesthesensiblechoiceandconvertsthenumbertoastring,thenconcatenatesthetwo.Usually,JavaScripthasenoughsensetomakedatatypeconversionslikethiswheneveritneedsto,butinsomesituationsyouneedtoconvertthetypeofapieceofdatayourself.Forexample,youmaybegivenapieceofstringdatathatyouwanttothinkofasanumber.Thisisespeciallylikelyifyouareusingformstocollectdatafromtheuser.Anyvaluesinputbytheuseraretreatedasstrings,eventhoughtheymaycontainnumericaldata,suchastheuser’sage.
Whyischangingthetypeofthedatasoimportant?Considerasituationinwhichyoucollecttwonumbersfromtheuserusingaformandwanttocalculatetheirsum.Thetwonumbersareavailabletoyouasstrings,forexample"22"and"15".Whenyoutrytocalculatethesumofthesevaluesusing"22"+"15"yougettheresult"2215",becauseJavaScriptthinksyouaretryingtoconcatenatetwostringsratherthantryingtofindthesumoftwonumbers.Toaddtothepossibleconfusion,theorderalsomakesadifference.So:
1+2+"abc"
resultsinastringcontaining"3abc",whereas:
"abc"+1+2
wouldresultinthestringcontaining"abc12".
Inthissectionyoulookattwoconversionfunctionsthatconvertstringstonumbers:parseInt()andparseFloat().
Let’stakeparseInt()first.Thisfunctiontakesastringandconvertsittoaninteger.Thenameisalittleconfusingatfirst—whyparseInt()ratherthanconvertToInt()?Themainreasonforthenamecomesfromthewaythatthefunctionworks.Itactuallygoesthrough(thatis,parses)eachcharacterofthestringyouaskittoconvertandseesifit’savalidnumber.Ifitisvalid,parseInt()usesittobuildupthenumber;ifitisnotvalid,thecommandsimplystopsconvertingandreturnsthenumberithasconvertedsofar.
Forexample,ifyourcodeisparseInt("123"),JavaScriptwillconvertthestring"123"tothenumber123.ForthecodeparseInt("123abc"),JavaScriptwillalsoreturnthenumber123.WhentheJavaScriptenginegetstothelettera,itassumesthenumberhasendedandgives123astheintegerversionofthestring"123abc".
TheparseFloat()functionworksinthesamewayasparseInt(),exceptthatitreturnsfloating-pointnumbers—fractionalnumbers—andthatadecimalpointinthestring,whichitisconverting,isconsideredtobepartoftheallowablenumber.
TRYITOUTConvertingStringstoNumbers
Let’slookatanexampleusingparseInt()andparseFloat().Enterthefollowing
codeandsaveitasch2_example7.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example7</title>
</head>
<body>
<script>
varmyString="56.02degreescentigrade";
varmyInt;
varmyFloat;
document.write("\""+myString+"\"is"+parseInt(myString,
10)+
"asaninteger"+"<br/>");
myInt=parseInt(myString,10);
document.write("\""+myString+
"\"whenconvertedtoanintegerequals"+myInt+"
<br/>");
myFloat=parseFloat(myString);
document.write("\""+myString+
"\"whenconvertedtoafloatingpointnumberequals"+
myFloat);
</script>
</body>
</html>
Loaditintoyourbrowser,andyou’llseethreelineswritteninthewebpage,asshowninFigure2.8.
Figure2.8
Yourfirsttaskinthescriptblockistodeclaresomevariables.ThevariablemyStringisdeclaredandinitializedtothestringyouwanttoconvert.Youcouldjustaseasilyhaveusedthestringdirectlyinthisexampleratherthanstoringitinavariable,butinpracticeyou’llfindthatyouusevariablesmoreoftenthanliteralvalues.YoualsodeclarethevariablesmyIntandmyFloat,whichwillholdtheconvertednumbers:
varmyString="56.02degreescentigrade";
varmyInt;
varmyFloat;
Next,youwritetothepagetheconvertedintegervalueofmyStringdisplayedinsideauser-friendlysentenceyoubuildupusingstringconcatenation.Noticethatyouusetheescapesequence\"todisplayquotes(")aroundthestringyouareconverting:
document.write("\""+myString+"\"is"+parseInt(myString,10)+
"asaninteger"+"<br/>");
Asyoucansee,youcanuseparseInt()andparseFloat()inthesameplacesyouwoulduseanumberitselforavariablecontaininganumber.Infact,inthislinetheJavaScriptengineisdoingtwoconversions.First,itconvertsmyStringtoaninteger,becausethat’swhatyouaskedforbyusingparseInt().Thenitautomaticallyconvertsthatintegernumberbacktoastring,soitcanbeconcatenatedwiththeotherstringstomakeupyoursentence.Alsonotethatonlythe56partofthemyStringvariable’svalueisconsideredavalidnumberwhenyou’redealingwithintegers.Anythingafterthe6isconsideredinvalidandisignored.
Noticethesecondvalue,thenumber10,thatispassedtoparseInt().Thisiscalledtheradix,anditdetermineshowthestringisparsedintoanumber.Bypassingthenumber10,youtelltheparseInt()functiontoconvertthenumberusingtheBase10numbersystem.Base10isourcommonnumbersystem,butyoucanuseparseInt()toconvertnumberstobinary(Base2),hex(Base16),andothernumbersystems.Forexample,parseInt(10,2)convertsthenumber10usingthebinarynumbersystem,resultinginthenumber2.Alwaysspecifytheradix!Withoutit,JavaScriptguesseswhatnumbersystemtouse,andyoucouldencounterunexpectedresults.
Next,youdothesameconversionofmyStringusingparseInt(),butthistimeyoustoretheresultinthemyIntvariable.Onthefollowinglineyouusetheresultinsometextyoudisplaytotheuser:
myInt=parseInt(myString,10);
document.write("\""+myString+
"\"whenconvertedtoanintegerequals"+myInt+"<br/>");
Again,thoughmyIntholdsanumber,theJavaScriptinterpreterknowsthat+,whenastringandanumberareinvolved,meansyouwantthemyIntvalueconvertedtoastringandconcatenatedtotherestofthestringsoitcanbedisplayed.
Finally,youuseparseFloat()toconvertthestringinmyStringtoafloating-pointnumber,whichyoustoreinthevariablemyFloat.Thistimethedecimalpointisconsideredtobeavalidpartofthenumber,soit’sanythingafterthe2thatisignored.Againyouusedocument.write()towritetheresulttothewebpageinsideauser-
www.allitebooks.com
friendlystring:
myFloat=parseFloat(myString);
document.write("\""+myString+
"\"whenconvertedtoafloatingpointnumberequals"+myFloat);
DealingwithStringsThatWon’tConvertSomestringssimplyarenotconvertibletonumbers,suchasstringsthatdon’tcontainanynumericaldata.Whathappensifyoutrytoconvertthesestrings?Asalittleexperiment,trychangingtheprecedingexamplesothatmyStringholdssomethingthatisnotconvertible.Forexample,changetheline
varmyString="56.02degreescentigrade";
to
varmyString="I'manamenotanumber";
Nowreloadthepageinyourbrowserandyoushouldseewhat’sshowninFigure2.9.
Figure2.9
Youcanseethatintheplaceofthenumbersyougotbefore,yougetNaN.Whatsortofnumberisthat?Well,it’sNotaNumberatall!
IfyouuseparseInt()orparseFloat()withanystringthatisemptyordoesnotstartwithatleastonevaliddigit,yougetNaN,meaningNotaNumber.
NaNisactuallyaspecialvalueinJavaScript.Ithasitsownfunction,isNaN(),whichcheckswhethersomethingisNaNornot.Forexample,
myVar1=isNaN("Hello");
willstorethevaluetrueinthevariablemyVar1,because"Hello"isnotanumber,whereas
myVar2=isNaN("34");
willstorethevaluefalseinthevariablemyVar2,because34canbeconvertedsuccessfullyfromastringtoanumberbytheisNaN()function.
InlaterchaptersyouseehowyoucanusetheisNaN()functiontocheckthevalidityofstringsasnumbers,somethingthatprovesinvaluablewhendealingwithuserinput.
ARRAYSNowwe’regoingtolookatanewconcept—somethingcalledanarray.Anarrayissimilartoanormalvariable,inthatyoucanuseittoholdanytypeofdata.However,ithasoneimportantdifference,whichyouseeinthissection.
Asyouhavealreadyseen,anormalvariablecanonlyholdonepieceofdataatatime.Forexample,youcansetmyVariabletobeequalto25likeso:
myVariable=25;
andthengoandsetittosomethingelse,say35:
myVariable=35;
However,whenyousetthevariableto35,thefirstvalueof25islost.ThevariablemyVariablenowholdsjustthenumber35.
Thefollowingtableillustratesthevariable:
VARIABLENAME VALUEmyVariable 35
Thedifferencebetweensuchanormalvariableandanarrayisthatanarraycanholdmorethanoneitemofdataatthesametime.Forexample,youcoulduseanarraywiththenamemyArraytostoreboththenumbers25and35.Eachplacewhereapieceofdatacanbestoredinanarrayiscalledanelement.
Howdoyoudistinguishbetweenthesetwopiecesofdatainanarray?Yougiveeachpieceofdataanindexvalue.Torefertothatpieceofdata,youencloseitsindexvalueinsquarebracketsafterthenameofthearray.Forexample,anarraycalledmyArraycontainingthedata25and35couldbeillustratedusingthefollowingtable:
ELEMENTNAME VALUEmyArray[0] 25
myArray[1] 35
Noticethattheindexvaluesstartat0andnot1.Whyisthis?Surely1makesmoresense—afterall,wehumanstendtosaythefirstitemofdata,followedbytheseconditem,andsoon.Computersstartfrom0,andthinkofthefirstitemasthezeroitem,thesecondasthefirstitem,andsoon.Confusing,butyou’llsoongetusedtothis.
Arrayscanbeveryusefulbecauseyoucanstoreasmany(withinthelimitsofthelanguage,whichspecifiesamaximumoftwotothepowerof32elements)orasfewitemsofdatainanarrayasyouwant.Also,youdon’thavetosayupfronthowmanypiecesofdatayouwanttostoreinanarray.
Sohowdoyoucreateanarray?Thisisslightlydifferentfromdeclaringanormalvariable.Tocreateanewarray,youneedtodeclareavariablenameandtellJavaScriptthatyouwantittobeanewarrayusingthenewkeywordandtheArray()function.Forexample,
youcoulddefinethearraymyArraylikethis:
varmyArray=newArray();
Notethat,aswitheverythinginJavaScript,thecodeiscase-sensitive,soifyoutypearray()ratherthanArray(),thecodewon’twork.UsingthenewoperatorisexplainedinChapter5.
Today’sJavaScriptdeveloperscreatearrayslikethis:
varmyArray=[];
Thisusesanarrayliteraltocreatethearray.ItisfunctionallythesameasusingnewArray(),butitrequireslesstyping.Thereisnorightorwrongwaytocreateanarray,butfortheremainderofthisbook,weusethearrayliteraltocreatearrays.
Aswithnormalvariables,youcanalsodeclareyourvariablefirst,andthentellJavaScriptyouwantittobeanarray.Forexample:
varmyArray;
myArray=[];
Youhaveseenhowtodeclareanewarray,buthowdoyoustoreyourpiecesofdatainsideit?Youcandothiswhenyoudefineyourarraybyincludingyourdatainsidethesquarebrackets,witheachpieceofdataseparatedbyacomma.Forexample:
varmyArray=["Paul",345,"John",112,"Bob",99];
Herethefirstitemofdata,"Paul",willbeputinthearraywithanindexof0.Thenextpieceofdata,345,willbeputinthearraywithanindexof1,andsoon.ThismeansthattheelementwiththenamemyArray[0]containsthevalue"Paul",theelementwiththenamemyArray[1]containsthevalue345,andsoon.
Youdon’thavetoprovideanarray’sdatawhenyoufirstcreatethearray.Forexample,youcouldalsowritetheprecedinglinelikethis:
varmyArray=[];
myArray[0]="Paul";
myArray[1]=345;
myArray[2]="John";
myArray[3]=112;
myArray[4]="Bob";
myArray[5]=99;
Youuseeachelementnameasyouwouldavariable,assigningthemwithvalues.Youlearnthismethodofdeclaringthevaluesofarrayelementsinthefollowing“TryItOut”section.
Obviously,inthisexamplethefirstwayofdefiningthedataitemsismucheasier.However,therewillbesituationsinwhichyouwanttochangethedatastoredinaparticularelementinanarrayafterthedataitemshavebeendeclared.Inthatcaseyouwillhavetousethelattermethodofdefiningthevaluesofthearrayelements.
You’llalsospotfromtheprecedingexamplethatyoucanstoredifferentdatatypesinthe
samearray.JavaScriptisveryflexibleastowhatyoucanputinanarrayandwhereyoucanputit.
TRYITOUTAnArrayInthisexample,youcreateanarraytoholdsomenames,andyouusethesecondmethoddescribedintheprecedingsectiontostorethesepiecesofdatainthearray.Youthendisplaythedatatotheuser.Typethiscodeandsaveitasch2_example8.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example8</title>
</head>
<body>
<script>
varmyArray=[];
myArray[0]="Jeremy";
myArray[1]="Paul";
myArray[2]="John";
document.write("myArray[0]="+myArray[0]+"<br/>");
document.write("myArray[2]="+myArray[2]+"<br/>");
document.write("myArray[1]="+myArray[1]+"<br/>");
myArray[1]="Mike";
document.write("myArray[1]changedto"+myArray[1]);
</script>
</body>
</html>
Ifyouloadthisintoyourwebbrowser,youshouldseeawebpagethatlookssomethingliketheoneshowninFigure2.10.
Figure2.10
Thefirsttaskinthescriptblockistodeclareavariableandinitializeitasanarray:
varmyArray=[];
Nowthatyouhaveyourarraydefined,youcanstoresomedatainit.Eachtimeyoustoreanitemofdatawithanewindex,JavaScriptautomaticallycreatesanewstoragespaceforit.RememberthatthefirstelementwillbeatmyArray[0].
Takeeachadditiontothearrayinturnandseewhat’shappening.Beforeyouaddanything,yourarrayisempty.Thenyouaddanarrayelementwiththefollowingline:
myArray[0]="Jeremy";
Yourarraynowlookslikethis:
INDEX DATASTORED0 Jeremy
Thenyouaddanotherelementtothearray,thistimewithanindexof1:
myArray[1]="Paul";
Yourarraynowlookslikethis:
INDEX DATASTORED0 Jeremy1 Paul
Finally,youaddanotherelementtothearraywithanindexof2:
myArray[2]="John";
Yourarraynowlookslikethis:
INDEX DATASTORED0 Jeremy1 Paul2 John
Next,youuseaseriesofdocument.write()functionstoinsertthevaluesthateachelementofthearraycontainsintothewebpage.Herethearrayisoutoforderjusttodemonstratethatyoucanaccessitthatway:
document.write("myArray[0]="+myArray[0]+"<br/>");
document.write("myArray[2]="+myArray[2]+"<br/>");
document.write("myArray[1]="+myArray[1]+"<br/>");
Youcantreateachparticularpositioninanarrayasifit’sastandardvariable,soyoucanuseittodocalculations,transferitsvaluetoanothervariableorarray,andsoon.However,ifyoutrytoaccessthedatainsideanarraypositionbeforeyouhavedefinedit,you’llgetundefinedasavalue.
Finally,youchangedthevalueofthesecondarraypositionto"Mike".Youcouldhavechangedittoanumberbecause,justaswithnormalvariables,youcanstoreanydatatypeatanytimeineachindividualdatapositioninanarray:
myArray[1]="Mike";
Nowyourarray’scontentslooklikethis:
INDEX DATASTORED0 Jeremy1 Mike2 John
Justtoshowthatthechangeyoumadehasworked,youusedocument.write()todisplaythesecondelement’svalue:
document.write("myArray[1]changedto"+myArray[1]);
AMulti-DimensionalArraySupposeyouwanttostoreacompany’spersonnelinformationinanarray.Youmighthavedatasuchasnames,ages,addresses,andsoon.Onewaytocreatesuchanarraywouldbetostoretheinformationsequentially—thefirstnameinthefirstelementofthearray,thenthecorrespondingageinthenextelement,theaddressinthethird,thenextnameinthefourthelement,andsoon.Yourarraycouldlooksomethinglikethis:
INDEX DATASTORED0 Name11 Age12 Address13 Name24 Age25 Address26 Name37 Age38 Address3
Thiswouldwork,butthereisaneatersolution:usingamulti-dimensionalarray.Uptonowyouhavebeenusingsingle-dimensionarrays.Inthesearrayseachelementisspecifiedbyjustoneindex—thatis,onedimension.So,takingtheprecedingexample,youcanseeName1isatindex0,Age1isatindex1,andsoon.
Amulti-dimensionalarrayisonewithtwoormoreindexesforeachelement.Forexample,thisishowyourpersonnelarraycouldlookasatwo-dimensionalarray:
INDEX 0 1 20 Name1 Name2 Name31 Age1 Age2 Age32 Address1 Address2 Address3
Youseehowtocreatesuchmulti-dimensionalarraysinthefollowing“TryItOut”section.
TRYITOUTATwo-DimensionalArrayThisexampleillustrateshowyoucancreatesuchamulti-dimensionalarrayinJavaScriptcodeandhowyoucanaccesstheelementsofthisarray.Typethiscodeandsaveitasch2_example9.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Example9</title>
</head>
<body>
<script>
varpersonnel=[];
personnel[0]=[];
personnel[0][0]="Name0";
personnel[0][1]="Age0";
personnel[0][2]="Address0";
personnel[1]=[];
personnel[1][0]="Name1";
personnel[1][1]="Age1";
personnel[1][2]="Address1";
personnel[2]=[];
personnel[2][0]="Name2";
personnel[2][1]="Age2";
personnel[2][2]="Address2";
document.write("Name:"+personnel[1][0]+"<br/>");
document.write("Age:"+personnel[1][1]+"<br/>");
document.write("Address:"+personnel[1][2]);
</script>
</body>
</html>
Ifyouloaditintoyourwebbrowser,you’llseethreelineswrittenintothepage,whichrepresentthename,age,andaddressofthepersonwhosedetailsarestoredinthepersonnel[1]elementofthearray,asshowninFigure2.11.
Figure2.11
Thefirstthingtodointhisscriptblockisdeclareavariable,personnel,andtellJavaScriptthatyouwantittobeanewarray:
varpersonnel=[];
Thenyoudosomethingnew;youtellJavaScriptyouwantindex0ofthepersonnelarray,thatis,theelementpersonnel[0],tobeanothernewarray:
personnel[0]=[];
Sowhat’sgoingon?Well,thetruthisthatJavaScriptdoesn’tactuallysupportmulti-
dimensionalarrays,onlysingleones.However,JavaScriptenablesyoutofakemulti-dimensionalarraysbycreatinganarrayinsideanotherarray.Sowhattheprecedinglineisdoingiscreatinganewarrayinsidetheelementwithindex0ofyourpersonnelarray.
Inthenextthreelines,youputvaluesintothenewlycreatedpersonnel[0]array.JavaScriptmakesiteasytodothis:Youjuststatethenameofthearray,personnel[0],followedbyanotherindexinsquarebrackets.Thefirstindex(0)belongstothepersonnelarray;thesecondindexbelongstothepersonnel[0]array:
personnel[0][0]="Name0";
personnel[0][1]="Age0";
personnel[0][2]="Address0";
Aftertheselinesofcode,yourarraylookslikethis:
INDEX 00 Name01 Age02 Address0
Thenumbersatthetop,atthemomentjust0,refertothepersonnelarray.Thenumbersgoingdowntheside,0,1,and2,areactuallyindicesforthenewpersonnel[0]arrayinsidethepersonnelarray.
Forthesecondperson’sdetails,yourepeattheprocess,butthistimeyouareusingthepersonnelarrayelementwithindex1:
personnel[1]=[];
personnel[1][0]="Name1";
personnel[1][1]="Age1";
personnel[1][2]="Address1";
Nowyourarraylookslikethis:
INDEX 0 10 Name0 Name11 Age0 Age12 Address0 Address1
Youcreateathirdperson’sdetailsinthenextfewlines.Youarenowusingtheelementwithindex2insidethepersonnelarraytocreateanewarray:
personnel[2]=[];
personnel[2][0]="Name2";
personnel[2][1]="Age2";
personnel[2][2]="Address2";
Thearraynowlookslikethis:
INDEX 0 1 20 Name0 Name1 Name21 Age0 Age1 Age22 Address0 Address1 Address2
Youhavenowfinishedcreatingyourmulti-dimensionalarray.Youendthescriptblockbyaccessingthedataforthesecondperson(Name1,Age1,Address1)anddisplayingitinthepagebyusingdocument.write().Asyoucansee,accessingthedataisverymuchthesameasstoringit.Youcanusethemulti-dimensionalarrayanywhereyouwoulduseanormalvariableorsingle-dimensionarray.
document.write("Name:"+personnel[1][0]+"<br/>");
document.write("Age:"+personnel[1][1]+"<br/>");
document.write("Address:"+personnel[1][2]);
Trychangingthedocument.write()commandssothattheydisplaythefirstperson’sdetails.Thecodewouldlooklikethis:
document.write("Name:"+personnel[0][0]+"<br/>");
document.write("Age:"+personnel[0][1]+"<br/>");
document.write("Address:"+personnel[0][2]);
It’spossibletocreatemulti-dimensionalarraysofthree,four,orevenahundreddimensions,butthingscanstarttogetveryconfusing,andyou’llfindthatyourarely,ifever,needmorethantwodimensions.Togiveyouanidea,here’showtodeclareandaccessafive-dimensionalarray:
varmyArray=[];
myArray[0]=[];
myArray[0][0]=[];
myArray[0][0][0]=[];
myArray[0][0][0][0]=[];
myArray[0][0][0][0][0]="Thisisgettingoutofhand";
document.write(myArray[0][0][0][0][0]);
That’sitforarraysfornow,butyoureturntotheminChapter5,whereyou’llfindoutsomethingshockingaboutthem.Youalsolearnaboutsomeoftheirmoreadvancedfeatures.
SUMMARYInthischapteryouhavebuiltupknowledgeofthefundamentalsofJavaScript’sdatatypesandvariablesandhowtousetheminoperations.Inparticular,yousawthat:
JavaScriptsupportsanumberoftypesofdata,suchasnumbers,text,andbooleans.
Textisrepresentedbystringsofcharactersandissurroundedbyquotes.Youmustmatchthequotessurroundingstrings.Escapecharactersenableyoutoincludecharactersinyourstringthatcannotbetyped.
VariablesareJavaScript’smeansofstoringdata,suchasnumbersandtext,inmemorysothattheycanbeusedagainandagaininyourcode.
Variablenamesmustnotincludecertainillegalcharacters,likethepercentsign(%)andtheampersand(&),orbeareservedword,likewith.
Beforeyoucangiveavaluetoavariable,youmustdeclareitsexistencetotheJavaScriptinterpreter.
JavaScripthasthefourbasicmathoperators,representedbythesymbolsplus(+),minus(−),star(*),andforwardslash(/).Toassignvaluesofacalculationtoavariable,youusetheequalssign(=),termedtheassignmentoperator.
Operatorshavedifferentlevelsofprecedence,somultiplicationanddivisionwillbecalculatedbeforeadditionandsubtraction.
Stringscanbejoined,orconcatenated,toproduceonebigstringbymeansofthe+operator.Whennumbersandstringsareconcatenatedwiththe+operator,JavaScriptautomaticallyconvertsthenumberintoastring.
AlthoughJavaScript’sautomaticdataconversionsuitsusmostofthetime,onsomeoccasionsyouneedtoforcetheconversionofdata.YousawhowparseInt()andparseFloat()canbeusedtoconvertstringstonumbers.Attemptingtoconvertstringsthatwon’tconvertwillresultinNaN(NotaNumber)beingreturned.
Arraysareaspecialtypeofvariablethatcanholdmorethanonepieceofdata.Thedataisinsertedandaccessedbymeansofauniqueindexnumber.
EXERCISES1. WriteaJavaScriptprogramtoconvertdegreescentigradeintodegreesFahrenheit,
andtowritetheresulttothepageinadescriptivesentence.TheJavaScriptequationforFahrenheittocentigradeisasfollows:
degFahren=9/5*degCent+32
2. Thefollowingcodeusestheprompt()functiontogettwonumbersfromtheuser.Itthenaddsthosetwonumbersandwritestheresulttothepage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Question2</title>
</head>
<body>
<script>
varfirstNumber=prompt("Enterthefirstnumber","");
varsecondNumber=prompt("Enterthesecondnumber","");
vartheTotal=firstNumber+secondNumber;
document.write(firstNumber+"addedto"+secondNumber+
"equals"+theTotal);
</script>
</body>
</html>
However,ifyoutryoutthecode,you’lldiscoverthatitdoesn’twork.Whynot?Changethecodesothatitdoeswork.
3DecisionsandLoopsWHATYOUWILLLEARNINTHISCHAPTER:
Comparingnumberandstringvalues
Makingdecisionswiththeif,else,andswitchstatements
Repeatingcodeforaslongasaconditionistrue
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Sofar,you’veseenhowtouseJavaScripttogetuserinput,performcalculationsandtaskswiththatinput,andwritetheresultstoawebpage.However,apocketcalculatorcandoallthis,sowhatisitthatmakescomputersdifferent?Thatistosay,whatgivescomputerstheappearanceofhavingintelligence?Theansweristhecapabilitytomakedecisionsbasedoninformationgathered.
Howwilldecision-makinghelpyouincreatingwebsites?IntheprecedingchapteryouwrotesomecodethatconvertedtemperatureindegreesFahrenheittocentigrade.YouobtainedthedegreesFahrenheitfromtheuserusingtheprompt()function.Thisworkedfineiftheuserenteredavalidnumber,suchas50.If,however,theuserenteredsomethinginvalidfortheFahrenheittemperature,suchasthestringaaa,youwouldfindthatyourcodenolongerworksasexpected.Now,ifyouhadsomedecision-makingcapabilitiesinyourprogram,youcouldchecktoseeifwhattheuserhasenteredisvalid.Ifitis,youcandothecalculation,andifitisn’t,youcantelltheuserwhyandaskhimtoenteravalidnumber.
ValidationofuserinputisprobablyoneofthemostcommonusesofdecisionmakinginJavaScript,butit’sfarfrombeingtheonlyuse.
InthischapteryoulookathowdecisionmakingisimplementedinJavaScriptandhowyoucanuseittomakeyourcodesmarter.
DECISIONMAKING—THEIFANDSWITCHSTATEMENTSAllprogramminglanguagesenableyoutomakedecisions—thatis,theyenabletheprogramtofollowacertaincourseofactiondependingonwhetheraparticularconditionismet.Thisiswhatgivesprogramminglanguagestheirintelligence.
Conditionsarecomparisonsbetweenvariablesanddata,suchasthefollowing:
IsAbiggerthanB?
IsXequaltoY?
IsMnotequaltoN?
Forexample,ifthevariabletodayheldthedayoftheweekonwhichyouarereadingthischapter,theconditionwouldbethis:
IstodayequaltoFriday?
You’llnoticethatallofthesequestionshaveayesornoanswer—thatis,theyareboolean-basedandcanonlyevaluatetotrueorfalse.Howdoyouusethistocreatedecision-makingcapabilitiesinyourcode?Yougetthebrowsertotestforwhethertheconditionistrue.If(andonlyif)itistrue,youexecuteaparticularsectionofcode.
Lookatanotherexample.RecallfromChapter1thenaturalEnglishinstructionsusedtodemonstratehowcodeflows.Oneoftheseinstructionsformakingacupofcoffeeis:
Hasthekettleboiled?Ifso,thenpourwaterintocup;otherwise,continuetowait.
Thisisanexampleofmakingadecision.Theconditioninthisinstructionis“Hasthekettleboiled?”Ithasatrueorfalseanswer.Iftheansweristrue,youpourthewaterintothecup.Ifitisn’ttrue,youcontinuetowait.
InJavaScript,youcanchangetheflowofthecode’sexecutiondependingonwhetheraconditionistrueorfalse,usinganifstatementoraswitchstatement.Youlookattheseshortly,butfirstweneedtointroducesomenewoperatorsthatareessentialforthedefinitionofconditions—comparisonoperators.
ComparisonOperatorsInChapter2yousawhowmathematicalfunctions,suchasadditionanddivision,wererepresentedbysymbols,suchasplus(+)andforwardslash(/),calledoperators.Youalsosawthatifyouwanttogiveavariableavalue,youcanassigntoitavalueortheresultofacalculationusingtheequalssign(=),termedtheassignmentoperator.
Decisionmakingalsohasitsownoperators,whichenableyoutotestconditions.Comparisonoperators,justlikethemathematicaloperatorsyousawintheprecedingchapter,havealeft-handside(LHS)andaright-handside(RHS),andthecomparisonis
madebetweenthetwo.Thetechnicaltermsforthesearetheleftoperandandtherightoperand.Forexample,theless-thanoperator,withthesymbol<,isacomparisonoperator.Youcouldwrite23<45,whichtranslatesas“Is23lessthan45?”Here,theanswerwouldbetrue(seeFigure3.1).
Figure3.1
Othercomparisonoperatorsexist,themoreusefulofwhicharesummarizedinthefollowingtable:
OPERATORSYMBOL PURPOSE== TestsifLHSisequaltoRHS< TestsifLHSislessthanRHS> TestsifLHSisgreaterthanRHS<= TestsifLHSislessthanorequaltoRHS>= TestsifLHSisgreaterthanorequaltoRHS!= TestsifLHSisnotequaltoRHS
Youseethesecomparisonoperatorsinuseinthenextsectionwhenyoulookattheifstatement.
PrecedenceRecallfromChapter2thatoperatorshaveanorderofprecedence.Thisappliesalsotothecomparisonoperators.The==and!=comparisonoperatorshavethelowestorderofprecedence,andtherestofthecomparisonoperators,<,>,<=,and>=,haveanequalprecedence.
Allofthesecomparisonoperatorshaveaprecedencethatisbelowarithmeticoperators,suchas+,−,*,and/.Thismeansthatifyoumakeacomparisonsuchas3*5>2*5,themultiplicationcalculationsareworkedoutfirst,beforetheirresultsarecompared.However,inthesecircumstances,it’sbothsaferandclearerifyouwrapthecalculationsoneithersideinsideparentheses;forexample,(3*5)>(2*5).Asageneralrule,it’sagoodideatouseparenthesestoensurethattheprecedenceisclear,oryoumayfindyourselfsurprisedbytheoutcome.
AssignmentversusComparisonOneveryimportantpointtomentionistheeasewithwhichtheassignmentoperator(=)
andthecomparisonoperator(==)canbemixedup.Rememberthatthe=operatorassignsavaluetoavariableandthatthe==operatorcomparesthevalueoftwovariables.Evenwhenyouhavethisideaclear,it’samazinglyeasytoputoneequalssignwhereyoumeanttoputtwo.
AssigningtheResultsofComparisonsYoucanstoretheresultsofacomparisoninavariable,asshowninthefollowingexample:
varage=prompt("Enterage:","");
varisOverSixty=parseInt(age,10)>60;
document.write("Olderthan60:"+isOverSixty);
Hereyouobtaintheuser’sageusingtheprompt()function.Thisreturns,asastring,whatevervaluetheuserenters.YouthenconvertthattoanumberusingtheparseInt()functionyousawinthepreviouschapterandusethegreater-thanoperatortoseeifit’sgreaterthan60.Theresult(eithertrueorfalse)ofthecomparisonwillbestoredinthevariableisOverSixty.
Iftheuserenters35,thedocument.write()onthefinallinewillwritethistothepage:
Olderthan60:false
Iftheuserenters61,thiswillbedisplayed:
Olderthan60:true
TheifStatementTheifstatementisoneyou’llfindyourselfusinginalmosteveryprogramthatismorethanacoupleoflineslong.ItworksverymuchasitdoesintheEnglishlanguage.Forexample,youmightsayinEnglish,“Iftheroomtemperatureismorethan80degreesFahrenheit,thenI’llturntheairconditioningon.”InJavaScript,thiswouldtranslateintosomethinglikethis:
if(roomTemperature>80){
roomTemperature=roomTemperature–10;
}
Howdoesthiswork?SeeFigure3.2.
Figure3.2
Noticethatthetestconditionisplacedinparenthesesandfollowstheifkeyword.Also,
notethatthereisnosemicolonattheendofthisline.Thecodetobeexecutediftheconditionistrueisplacedincurlybracesonthelineafterthecondition,andeachoftheselinesofcodedoesendwithasemicolon.
Thecurlybraces,{},haveaspecialpurposeinJavaScript:Theymarkoutablockofcode.MarkingoutlinesofcodeasbelongingtoasingleblockmeansthatJavaScriptwilltreatthemallasonepieceofcode.Iftheconditionofanifstatementistrue,JavaScriptexecutesthenextlineorblockofcodefollowingtheifstatement.Intheprecedingexample,theblockofcodehasonlyonestatement,sowecouldequallyaswellhavewrittenthis:
if(roomTemperature>80)
roomTemperature=roomTemperature–10;
However,ifyouhaveanumberoflinesofcodethatyouwanttoexecute,youneedthebracestomarkthemoutasasingleblockofcode.Forexample,amodifiedversionoftheexamplewiththreestatementsofcodewouldhavetoincludethebraces:
if(roomTemperature>80){
roomTemperature=roomTemperature–10;
alert("It'sgettinghotinhere");
alert("Airconditioningswitchedon");
}
Aparticularlyeasymistaketomakeistoforgetthebraceswhenmarkingoutablockofcodetobeexecuted.Insteadofthecodeintheblockbeingexecutedwhentheconditionistrue,you’llfindthatonlythefirstlineaftertheifstatementisexecuted.However,theotherlineswillalwaysbeexecutedregardlessoftheoutcomeofthetestcondition.Toavoidmistakeslikethese,it’sagoodideatoalwaysusebraces,evenwherethereisonlyonestatement.Ifyougetintothishabit,you’llbelesslikelytoleavethemoutwhentheyareactuallyneeded.
TRYITOUTTheifStatementLet’sreturntothetemperatureconverterexamplefromChapter2andaddsomedecision-makingfunctionality.
1. Enterthefollowingcodeandsaveitasch3_example1.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter3,Example1</title>
</head>
<body>
<script>
vardegFahren=parseInt(prompt("Enterthedegrees
Fahrenheit",32),10);
vardegCent=5/9*(degFahren-32);
document.write(degFahren+"\xB0Fahrenheitis"+degCent
+
"\xB0centigrade<br/>");
if(degCent<0){
document.write("That'sbelowthefreezingpointof
water");
}
if(degCent==100)
document.write("That'stheboilingpointofwater");
</script>
</body>
</html>
2. Loadthepageintoyourbrowserandenter32intothepromptboxfortheFahrenheitvaluetobeconverted.Withavalueof32,neitheroftheifstatement’sconditionswillbetrue,sotheonlylinewritteninthepagewillbethatshowninFigure3.3.
Figure3.3
3. Nowreloadthepageandenter31fortheFahrenheitvalue.Thistimeyou’llseetwolinesinthepage,asshowninFigure3.4.
Figure3.4
4. Finally,reloadthepageagain,butthistime,enter212inthepromptbox.ThetwolinesshowninFigure3.5willappearinthepage.
Figure3.5
Thefirstpartofthescriptblockinthispageissimilartotheexamplech2_example4.htmlinChapter2.Youdeclaretwovariables,degFahrenanddegCent.ThevariabledegFahrenisgivenaninitialvalueobtainedfromtheuserwiththeprompt()function.Notetheprompt()functionreturnsastringvalue,whichyouthenconverttoanumericvalueusingtheparseInt()function.ThevariabledegCentisinitializedtotheresultofthecalculation5/9*(degFahren-32),whichisthe
Fahrenheit-to-centigradeconversioncalculation:
vardegFahren=parseInt(prompt("EnterthedegreesFahrenheit",32),
10);
vardegCent=5/9*(degFahren-32);
Thenyouwritetheresultofyourcalculationtothepage:
document.write(degFahren+"\xB0Fahrenheitis"+degCent+
"\xB0centigrade<br/>");
Nowcomesthenewcode;thefirstoftwoifstatements:
if(degCent<0){
document.write("That'sbelowthefreezingpointofwater");
}
Thisifstatementhastheconditionthatasks,“IsthevalueofthevariabledegCentlessthanzero?”Iftheanswerisyes(true),thecodeinsidethecurlybracesexecutes.Inthiscase,youwriteasentencetothepageusingdocument.write().Iftheanswerisno(false),theprocessingmovesontothenextlineaftertheclosingbrace.Alsoworthnotingisthefactthatthecodeinsidetheifstatement’sopeningbraceisindented.Thisisnotnecessary,butitisagoodpracticetogetintobecauseitmakesyourcodemucheasiertoread.
Whentryingouttheexample,youstartedbyentering32,sothatdegFahrenwillbeinitializedto32.InthiscasethecalculationdegCent=5/9*(degFahren−32)willsetdegCentto0.Sotheanswertothequestion“IsdegCentlessthanzero?”isfalse,becausedegCentisequaltozero,notlessthanzero.Thecodeinsidethecurlybraceswillbeskippedandneverexecuted.Inthiscase,thenextlinetobeexecutedwillbethesecondifstatement’scondition,whichwe’lldiscussshortly.
Whenyouentered31inthepromptbox,degFahrenwassetto31,sothevariabledegCentwillbe−0.55555555556.Sohowdoesyourifstatementlooknow?Itevaluatesto“Is–0.55555555556lessthanzero?”Theanswerthistimeistrue,andthecodeinsidethebraces,herejustadocument.write()statement,executes.
Finally,whenyouentered212,howdidthisaltertheifstatement?ThevariabledegCentissetto100bythecalculation,sotheifstatementnowasksthequestion,“Is100lessthanzero?”Theanswerisfalse,andthecodeinsidethebraceswillbeskippedover.
Inthesecondifstatement,youevaluatethecondition“IsthevalueofvariabledegCentequalto100?”:
if(degCent==100)
document.write("That'stheboilingpointofwater");
Therearenobraceshere,soiftheconditionistrue,theonlycodetoexecuteisthefirstlinebelowtheifstatement.Whenyouwanttoexecutemultiplelinesinthecaseoftheconditionbeingtrue,bracesarerequired.
YousawthatwhendegFahrenis32,degCentwillbe0.Soyourifstatementwillbe
“Is0equalto100?”Theanswerisclearlyfalse,andthecodewon’texecute.Again,whenyousetdegFahrento31,degCentwillbecalculatedtobe-0.55555555556;“Is–0.55555555556equalto100?”isalsofalse,andthecodewon’texecute.
Finally,whendegFahrenissetto212,degCentwillbe100.Thistimetheifstatementis“Is100equalto100?”andtheansweristrue,sothedocument.write()statementexecutes.
Asyouhaveseenalready,oneofthemostcommonerrorsinJavaScript,evenforexperts,isusingoneequalssignforevaluating,ratherthanthenecessarytwo.Takealookatthefollowingcodeextract:
if(degCent=100)
document.write("That'stheboilingpointofwater");
Thisconditionwillalwaysevaluatetotrue,andthecodebelowtheifstatementwillalwaysexecute.Worsestill,yourvariabledegCentwillbesetto100.Why?Becauseasingleequalssignassignsvaluestoavariable;onlyadoubleequalssigncomparesvalues.Thereasonanassignmentalwaysevaluatestotrueisthattheresultoftheassignmentexpressionisthevalueoftheright-handsideexpressionandthisisthenumber100,whichisthenimplicitlyconvertedtoabooleanandanynumberbesides0andNaNconvertstotrue.
LogicalOperatorsYoushouldhaveageneralideaofhowtouseconditionsinifstatementsnow,buthowdoyouuseaconditionsuchas“IsdegFahrengreaterthanzerobutlessthan100?”Youhavetwoconditionstotesthere.YouneedtotestwhetherdegFahrenisgreaterthanzeroandwhetherdegFahrenislessthan100.
JavaScriptenablesyoutousesuchmultipleconditions.Todothis,youneedtolearnaboutthreemoreoperators:thelogicaloperatorsAND,OR,andNOT.Thesymbolsforthesearelistedinthefollowingtable:
OPERATOR SYMBOLAND &&
OR ||
NOT !
NoticethattheANDandORoperatorsaretwosymbolsrepeated:&&and||.Ifyoutypejustonesymbol,&or|,strangethingswillhappenbecausethesearespecialoperatorscalledbitwiseoperatorsusedinbinaryoperations—forlogicaloperationsyoumustalwaysusetwo.
Afteryou’velearnedaboutthethreelogicaloperators,youtakealookathowtousetheminifstatements,withplentyofpracticalexamples.Soifitseemsabitconfusingonfirstread,don’tpanic.Allwillbecomeclear.Let’slookathoweachoftheseworks,startingwiththeANDoperator.
ANDRecallthatwetalkedabouttheleft-handside(LHS)andtheright-handside(RHS)oftheoperator.ThesameistruewiththeANDoperator.However,nowtheLHSandRHSoftheconditionarebooleanvalues(usuallytheresultofacondition).
TheANDoperatorworksverymuchasitdoesinEnglish.Forexample,youmightsay,“IfIfeelcoldandIhaveacoat,thenI’llputmycoaton.”Here,theleft-handsideofthe“and”wordis“DoIfeelcold?”andthiscanbeevaluatedastrueorfalse.Theright-handsideis“DoIhaveacoat?”whichagainisevaluatedtoeithertrueorfalse.Iftheleft-handsideistrue(Iamcold)andtheright-handsideistrue(Idohaveacoat),thenyouputyourcoaton.
ThisisverysimilartohowtheANDoperatorworksinJavaScript.TheANDoperatoractuallyproducesaresult,justasaddingtwonumbersproducesaresult.However,theANDoperatortakestwobooleanvalues(onitsLHSandRHS)andresultsinanotherbooleanvalue.IftheLHSandRHSconditionsevaluatetotrue,theresultwillbetrue.Inanyothercircumstance,theresultwillbefalse.
Followingisatruthtableofpossibleevaluationsofleft-handsidesandright-handsidesandtheresultwhenANDisused:
LEFT-HANDSIDE RIGHT-HANDSIDE RESULTtrue true true
false true false
true false false
false false false
Althoughthetableis,strictlyspeaking,true,it’sworthnotingthatJavaScriptdoesn’tlikedoingunnecessarywork.Well,whodoes!Iftheleft-handsideisfalse,eveniftheright-handsidedoesevaluatetotrue,itwon’tmakeanydifferencetothefinalresult—it’llstillbefalse.Sotoavoidwastingtime,iftheleft-handsideisfalse,JavaScriptdoesn’tevenbothercheckingtheright-handsideandjustreturnsaresultoffalse.
ORJustlikeAND,ORalsoworksmuchasitdoesinEnglish.Forexample,youmightsaythatifitisrainingorifitissnowing,thenyou’lltakeanumbrella.Ifeitheroftheconditions“itisraining”or“itissnowing”istrue,youwilltakeanumbrella.
Again,justlikeAND,theORoperatoractsontwobooleanvalues(onefromitsleft-handsideandonefromitsright-handside)andreturnsanotherbooleanvalue.Iftheleft-handsideevaluatestotrueortheright-handsideevaluatestotrue,theresultreturnedistrue.Otherwise,theresultisfalse.Thefollowingtableshowsthepossibleresults:
LEFT-HANDSIDE RIGHT-HANDSIDE RESULTtrue true true
false true true
true false true
false false false
AswiththeANDoperator,JavaScriptlikestoavoiddoingthingsthatmakenodifferencetothefinalresult.Iftheleft-handsideistrue,thenwhethertheright-handsideistrueorfalsemakesnodifferencetothefinalresult—it’llstillbetrue.So,toavoidwork,iftheleft-handsideistrue,theright-handsideisnotevaluated,andJavaScriptsimplyreturnstrue.Theendresultisthesame—theonlydifferenceisinhowJavaScriptarrivesattheconclusion.However,itdoesmeanyoushouldnotrelyontheright-handsideoftheORoperatortobeexecuted.
NOTInEnglish,wemightsay,“IfI’mnothot,thenI’lleatsoup.”Theconditionbeingevaluatediswhetherwe’rehot.Theresultistrueorfalse,butinthisexampleweact(eatsoup)iftheresultisfalse.
However,JavaScriptisusedtoexecutingcodeonlyifaconditionistrue.Soifyouwantafalseconditiontocausecodetoexecute,youneedtoswitchthatfalsevaluetotrue(andanytruevaluetofalse).ThatwayyoucantrickJavaScriptintoexecutingcodeafterafalsecondition.
YoudothisusingtheNOToperator.Thisoperatorreversesthelogicofaresult;ittakesonebooleanvalueandchangesittotheotherbooleanvalue.Soitchangestruetofalseandfalsetotrue.Thisissometimescallednegation.
TousetheNOToperator,youputtheconditionyouwantreversedinparenthesesandputthe!symbolinfrontoftheparentheses.Forexample:
if(!(degCent<100)){
//Somecode
}
AnycodewithinthebraceswillbeexecutedonlyiftheconditiondegCent<100isfalse.
ThefollowingtabledetailsthepossibleresultswhenusingNOT:
RIGHT-HANDSIDE RESULTtrue false
false true
MultipleConditionsInsideanifStatementTheprevioussectionstartedbyaskinghowyoucouldusethecondition“IsdegFahrengreaterthanzerobutlessthan100?”Onewayofdoingthiswouldbetousetwoifstatements,onenestedinsideanother.Nestedsimplymeansthatthereisanouterif
statement,andinsidethisisaninnerifstatement.Iftheconditionfortheouterifstatementistrue,then(andonlythen)willthenestedinnerifstatement’sconditionbetested.
Usingnestedifstatements,yourcodewouldbe:
if(degCent<100){
if(degCent>0){
document.write("degCentisbetween0and100");
}
}
Thiswouldwork,butit’salittleverboseandcanbequiteconfusing.JavaScriptoffersabetteralternative—usingmultipleconditionsinsidetheconditionpartoftheifstatement.Themultipleconditionsarestrungtogetherwiththelogicaloperatorsyoujustlookedat.Sotheprecedingcodecouldberewrittenlikethis:
if(degCent>0&°Cent<100){
document.write("degCentisbetween0and100");
}
Theifstatement’sconditionfirstevaluateswhetherdegCentisgreaterthanzero.Ifthatistrue,thecodegoesontoevaluatewhetherdegCentislessthan100.Onlyifbothoftheseconditionsaretruewillthedocument.write()codelineexecute.
TRYITOUTMultipleConditionsThisexampledemonstratesmulti-conditionifstatementsusingtheAND,OR,andNOToperators.Typethefollowingcode,andsaveitasch3 _ example2.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter3,Example2</title>
</head>
<body>
<script>
varmyAge=parseInt(prompt("Enteryourage",30),10);
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10<br/>");
}
if(!(myAge>=0&&myAge<=10)){
document.write("myAgeisNOTbetween0and10<br/>");
}
if(myAge>=80||myAge<=10){
document.write("myAgeis80oraboveOR10orbelow<br
/>");
}
if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=
89)){
document.write("myAgeisbetween30and39ormyAgeis"+
"between80and89");
}
</script>
</body>
</html>
Whenyouloaditintoyourbrowser,apromptboxshouldappear.Enterthevalue30,thenpressReturn,andthelinesshowninFigure3.6arewrittentothewebpage.
Figure3.6
ThescriptblockstartsbydefiningthevariablemyAgeandinitializingittothevalueenteredbytheuserinthepromptboxandconvertedtoanumber:
varmyAge=parseInt(prompt("Enteryourage",30),10);
Afterthisarefourifstatements,eachusingmultipleconditions.Youlookateachindetailinturn.
Theeasiestwaytoworkoutwhatmultipleconditionsaredoingistosplitthemupintosmallerpiecesandthenevaluatethecombinedresult.Inthisexampleyouhaveenteredthevalue30,whichhasbeenstoredinthevariablemyAge.You’llsubstitutethisvalueintotheconditionstoseehowtheywork.
Here’sthefirstifstatement:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10<br/>");
}
Thefirstifstatementisaskingthequestion,“IsmyAgebetween0and10?”You’ll
taketheLHSoftheconditionfirst,substitutingyourparticularvalueformyAge.TheLHSasks,“Is30greaterthanorequalto0?”Theansweristrue.ThequestionposedbytheRHSconditionis“Is30lessthanorequalto10?”Theanswerisfalse.Thesetwohalvesoftheconditionarejoinedusing&&,whichindicatestheANDoperator.UsingtheANDresultstableshownearlier,youcanseethatifLHSistrueandRHSisfalse,youhaveanoverallresultoffalse.Sotheendresultoftheconditionfortheifstatementisfalse,andthecodeinsidethebraceswon’texecute.
Let’smoveontothesecondifstatement:
if(!(myAge>=0&&myAge<=10)){
document.write("myAgeisNOTbetween0and10<br/>");
}
Thesecondifstatementisposingthequestion,“IsmyAgenotbetween0and10?”Itsconditionissimilartothatofthefirstifstatement,butwithonesmalldifference:YouhaveenclosedtheconditioninsideparenthesesandputtheNOToperator(!)infront.
Thepartoftheconditioninsidetheparenthesesisevaluatedand,asbefore,producesthesameresult—false.However,theNOToperatorreversestheresultandmakesittrue.Becausetheifstatement’sconditionistrue,thecodeinsidethebraceswillexecutethistime,causingadocument.write()towritearesponsetothepage.
Whataboutthethirdifstatement?
if(myAge>=80||myAge<=10){
document.write("myAgeis80oraboveOR10orbelow<br/>");
}
Thethirdifstatementasks,“IsmyAgegreaterthanorequalto80,orlessthanorequalto10?”TakingtheLHSconditionfirst—“Is30greaterthanorequalto80?”—theanswerisfalse.TheanswertotheRHScondition—“Is30lessthanorequalto10?”—isagainfalse.Thesetwohalvesoftheconditionarecombinedusing| |,whichindicatestheORoperator.LookingattheORresulttableearlierinthissection,youseethatfalseORfalseproducesaresultoffalse.Soagaintheifstatement’sconditionevaluatestofalse,andthecodewithinthecurlybracesdoesnotexecute.
Thefinalifstatementisalittlemorecomplex:
if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)){
document.write("myAgeisbetween30and39ormyAgeisbetween80
and89");
}
Itasksthequestion,“IsmyAgebetween30and39orbetween80and89?”Let’sbreakdowntheconditionintoitscomponentparts.Thereisaleft-hand-sideandaright-hand-sidecondition,combinedbymeansofanORoperator.However,theLHSandRHSthemselveshaveanLHSandRHSeach,whicharecombinedusingANDoperators.NoticehowparenthesesareusedtotellJavaScriptwhichpartsoftheconditiontoevaluatefirst,justasyouwoulddowithnumbersinamathematicalcalculation.
Let’slookattheLHSoftheconditionfirst,namely(myAge>=30&&myAge<=39).Byputtingtheconditionintoparentheses,youensurethatit’streatedasasinglecondition;nomatterhowmanyconditionsareinsidetheparentheses,itonlyproducesasingleresult,eithertrueorfalse.Breakingdowntheconditionsintheparentheses,youhave“Is30greaterthanorequalto30?”witharesultoftrue,and“Is30lessthanorequalto39?”againwitharesultoftrue.FromtheANDtable,youknowtrueANDtrueproducesaresultoftrue.
Nowlet’slookattheRHSofthecondition,namely(myAge>=80&&myAge<=89).Againbreakingdownthecondition,youseethattheLHSasks,“Is30greaterthanorequalto80?”whichgivesafalseresult,andtheRHSasks,“Is30lessthanorequalto89?”whichgivesatrueresult.YouknowthatfalseANDtruegivesafalseresult.
Nowyoucanthinkofyourifstatement’sconditionaslookinglike(true| |false).LookingattheORresultstable,youcanseethattrueORfalsegivesaresultoftrue,sothecodewithinthebracesfollowingtheifstatementwillexecute,andalinewillbewrittentothepage.
However,rememberthatJavaScriptdoesnotevaluateconditionswheretheywon’taffectthefinalresult,andtheprecedingconditionisoneofthosesituations.TheLHSoftheconditionevaluatedtotrue.Afterthat,itdoesnotmatteriftheRHSoftheconditionistrueorfalsebecauseonlyoneoftheconditionsinanORoperationneedstobetrueforaresultoftrue.ThusJavaScriptdoesnotactuallyevaluatetheRHSofthecondition.Wedidsosimplyfordemonstrationpurposes.
Asyouhaveseen,theeasiestwaytoapproachunderstandingorcreatingmultipleconditionsistobreakthemdownintothesmallestlogicalchunks.You’llfindthatwithexperience,youwilldothisalmostwithoutthinking,unlessyouhaveaparticularlytrickyconditiontoevaluate.
Althoughusingmultipleconditionsisoftenbetterthanusingmultipleifstatements,sometimesitmakesyourcodehardertoreadandthereforehardertounderstandanddebug.It’spossibletohave10,20,ormorethan100conditionsinsideyourifstatement,butcanyouimaginetryingtoreadanifstatementwitheven10conditions?Ifyoufeelthatyourmultipleconditionsaregettingtoocomplex,breakthemdownintosmallerlogicalchunks.
Forexample,imagineyouwanttoexecutesomecodeifmyAgeisintheranges30–39,80–89,or100–115,usingdifferentcodeineachcase.Youcouldwritethestatementlikeso:
if((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)||
(myAge>=100&&myAge<=115)){
document.write("myAgeisbetween30and39"+
"ormyAgeisbetween80"+
"and89ormyAgeisbetween100and115");
}
There’snothingwrongwiththis,butitisstartingtogetalittlelonganddifficulttoread.Instead,youcouldcreateanotherifstatementforthecodeexecutedforthe
100–115range.
elseandelseifImagineasituationwhereyouwantsomecodetoexecuteifacertainconditionistrueandsomeothercodetoexecuteifitisfalse.Youcanachievethisbyhavingtwoifstatements,asshowninthefollowingexample:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10");
}
if(!(myAge>=0&&myAge<=10)){
document.write("myAgeisNOTbetween0and10");
}
ThefirstifstatementtestswhethermyAgeisbetween0and10,andthesecondforthesituationwheremyAgeisnotbetween0and10.However,JavaScriptprovidesaneasierwayofachievingthis:withanelsestatement.Again,theuseofthewordelseissimilartoitsuseintheEnglishlanguage.Youmightsay,“Ifitisraining,Iwilltakeanumbrella;otherwiseIwilltakeasunhat.”InJavaScriptyoucansayiftheconditionistrue,thenexecuteoneblockofcode;elseexecuteanalternativeblock.Rewritingtheprecedingcodeusingthistechnique,youwouldhavethefollowing:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10");
}else{
document.write("myAgeisNOTbetween0and10");
}
Writingthecodelikethismakesitsimplerandthereforeeasiertoread.PlusitalsosavesJavaScriptfromtestingaconditiontowhichyoualreadyknowtheanswer.
Youcouldalsoincludeanotherifstatementwiththeelsestatement.Forexample:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10");
}elseif((myAge>=30&&myAge<=39)||(myAge>=80&&myAge<=89)){
document.write("myAgeisbetween30and39"+
"ormyAgeisbetween80and89");
}else{
document.write("myAgeisNOTbetween0and10,"+
"norisitbetween30and39,nor"+
"isitbetween80and89");
}
ThefirstifstatementcheckswhethermyAgeisbetween0and10andexecutessomecodeifthat’strue.Ifit’sfalse,anelseifstatementchecksifmyAgeisbetween30and39or80and89,andexecutessomeothercodeifeitherofthoseconditionsistrue.Failingthat,youhaveafinalelsestatement,whichcatchesthesituationinwhichthevalueofmyAgedidnottriggertrueinanyoftheearlierifconditions.
Whenusingifandelseif,youneedtobeextracarefulwithyourcurlybracestoensurethattheifandelseifstatementsstartandstopwhereyouexpect,andyoudon’tendupwithanelsethatdoesn’tbelongtotherightif.Thisisquitetrickytodescribewithwords—it’seasiertoseewhatwemeanwithanexample:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10");
if(myAge==5){
document.write("You're5yearsold");
}
}else{
document.write("myAgeisNOTbetween0and10");
}
Noticethatwehaven’tindentedthecode.AlthoughthisdoesnotmattertoJavaScript,itdoesmakethecodemoredifficultforhumanstoreadandhidesthemissingcurlybracethatshouldbebeforethefinalelsestatement.
Correctlyformattedandwiththemissingbracketinserted,thecodelookslikethis:
if(myAge>=0&&myAge<=10){
document.write("myAgeisbetween0and10<br/>");
if(myAge==5){
document.write("You're5yearsold");
}
}else{
document.write("myAgeisNOTbetween0and10");
}
Asyoucansee,thecodeisworkingnow;itisalsoaloteasiertoseewhichcodeispartofwhichifblock.
ComparingStringsUptothispoint,youhavebeenlookingexclusivelyatusingcomparisonoperatorswithnumbers.However,theyworkjustaswellwithstrings.Allthat’sbeensaidanddonewithnumbersappliestostrings,butwithoneimportantdifference.Youarenowcomparingdataalphabeticallyratherthannumerically,soyouhaveafewtrapstowatchoutfor.
Inthefollowingcode,youcomparethevariablemyName,whichcontainsthestring"Paul",withthestringliteral"Paul":
varmyName="Paul";
if(myName=="Paul"){
alert("myNameisPaul");
}
HowdoesJavaScriptdealwiththis?Well,itgoesthrougheachletterinturnontheLHSandchecksitwiththeletterinthesamepositionontheRHStoseeifit’sactuallythesame.Ifatanypointitfindsadifference,itstops,andtheresultisfalse.If,afterhavingcheckedeachletterinturnallthewaytotheend,itconfirmsthattheyareallthesame,itreturnstrue.Theconditionintheprecedingifstatementwillreturntrue,soyou’llseeanalertbox.
However,stringcomparisoninJavaScriptiscasesensitive.So"P"isnotthesameas"p".Takingtheprecedingexample,butchangingthevariablemyNameto"paul",youfindthattheconditionisfalseandthecodeinsidetheifstatementdoesnotexecute:
varmyName="paul";
if(myName=="Paul"){
alert("myNameisPaul");
}
The>=,>,<=,and<operatorsworkwithstringsaswellaswithnumbers,butagainitisanalphabeticalcomparison.So"A"<"B"istrue,becauseAcomesbeforeBinthealphabet.However,JavaScript’scasesensitivitycomesintoplayagain."A"<"B"istrue,but"a"<"B"isfalse.Why?Becauseuppercaselettersaretreatedasalwayscomingbeforelowercaseletters.Whyisthis?EachletterhasacodenumberintheASCIIandUnicodecharactersets,andthecodenumbersforuppercaselettersarelowerthanthecodenumbersforlowercaseletters.Thisissomethingtowatchoutforwhenwritingyourowncode.
Thesimplestwaytoavoidconfusionwithdifferentcasesistoconvertbothstringstoeitheruppercaseorlowercasebeforeyoucomparethem.YoucandothiseasilyusingthetoUpperCase()ortoLowerCase()function,whichyoulearnaboutinChapter5.
TheswitchStatementYousawearlierhowtheifandelseifstatementscouldbeusedforcheckingvariousconditions;ifthefirstconditionisnotvalid,thenanotherischecked,andanother,andsoon.However,whenyouwanttocheckthevalueofaparticularvariableforalargenumberofpossiblevalues,thereisamoreefficientalternative,namelytheswitchstatement.ThestructureoftheswitchstatementisgiveninFigure3.7.
Figure3.7
Thebestwaytothinkoftheswitchstatementis“Switchtothecodewherethecasematches.”Theswitchstatementhasfourimportantelements:
Thetestexpression
Thecasestatements
Thebreakstatements
Thedefaultstatement
Thetestexpressionisgivenintheparenthesesfollowingtheswitchkeyword.Inthepreviousexample,youaretestingusingthevariablemyName.Insidetheparentheses,however,youcouldhaveanyvalidexpression.
Nextcomethecasestatements.Thecasestatementsdotheconditionchecking.Toindicatewhichcasestatementsbelongtoyourswitchstatement,youmustputtheminsidethecurlybracesfollowingthetestexpression.Eachcasestatementspecifiesavalue,forexample"Paul".Thecasestatementthenactslikeif(myName=="Paul").IfthevariablemyNamedidcontainthevalue"Paul",executionwouldcommencefromthecodestartingbelowthecase"Paul"statementandwouldcontinuetotheendoftheswitchstatement.Thisexamplehasonlytwocasestatements,butyoucanhaveasmanyasyoulike.
Inmostcases,youwantonlytheblockofcodedirectlyunderneaththerelevantcasestatementtoexecute,notallthecodebelowtherelevantcasestatement,includinganyothercasestatements.Toachievethis,youputabreakstatementattheendofthecodethatyouwantexecuted.ThistellsJavaScripttostopexecutingatthatpointandleavetheswitchstatement.
Finally,youhavethedefaultcase,which(asthenamesuggests)isthecodethatwillexecutewhennoneoftheothercasestatementsmatch.Thedefaultstatementisoptional;ifyouhavenodefaultcodethatyouwanttoexecute,youcanleaveitout,butrememberthatinthiscasenocodewillexecuteifnocasestatementsmatch.Itisagoodideatoincludeadefaultcase,unlessyouareabsolutelysurethatyouhaveallyouroptionscovered.
TRYITOUTUsingtheswitchStatementLet’stakealookattheswitchstatementinaction.Thefollowingexampleillustratesasimpleguessinggame.Typethecodeandsaveitasch3_example3.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter3,Example3</title>
</head>
<body>
<script>
varsecretNumber=prompt("Pickanumberbetween1and5:",
"");
secretNumber=parseInt(secretNumber,10);
switch(secretNumber){
case1:
document.write("Toolow!");
break;
case2:
document.write("Toolow!");
break;
case3:
document.write("Youguessedthesecretnumber!");
break;
case4:
document.write("Toohigh!");
break;
case5:
document.write("Toohigh!");
break;
default:
document.write("Youdidnotenteranumberbetween1
and5.");
break;
}
document.write("<br/>Executioncontinueshere");
</script>
</body>
</html>
Loadthisintoyourbrowserandenter,forexample,thevalue1inthepromptbox.YoushouldthenseesomethinglikewhatisshowninFigure3.8.
Figure3.8
If,ontheotherhand,youenterthevalue3,youshouldseeafriendlymessagelettingyouknowthatyouguessedthesecretnumbercorrectly,asshowninFigure3.9.
Figure3.9
FirstyoudeclarethevariablesecretNumberandsetittothevalueenteredbytheuserviathepromptbox.NotethatyouusetheparseInt()functiontoconvertthestringthatisreturnedfromprompt()toanintegervalue:
varsecretNumber=prompt("Pickanumberbetween1and5:","");
secretNumber=parseInt(secretNumber,10);
Nextyoucreatethestartoftheswitchstatement:
switch(secretNumber){
TheexpressioninparenthesesissimplythevariablesecretNumber,andit’sthisnumberthatthecasestatementswillbecomparedagainst.
Youspecifytheblockofcodeencompassingthecasestatementsusingcurlybraces.Eachcasestatementchecksoneofthenumbersbetween1and5,becausethisiswhatyouhavespecifiedtotheuserthatsheshouldenter.Thefirstsimplyoutputsamessagethatthenumbershehasenteredistoolow:
case1:
document.write("Toolow!");
break;
Thesecondcasestatement,forthevalue2,hasthesamemessage,sothecodeisnotrepeatedhere.Thethirdcasestatementletstheuserknowthatshehasguessedcorrectly:
case3:
document.write("Youguessedthesecretnumber!");
break;
Finally,thefourthandfifthcasestatementsoutputamessagethatthenumbertheuser
hasenteredistoohigh:
case4:
document.write("Toohigh!");
break;
Youdoneedtoaddadefaultcaseinthisexample,becausetheusermightverywell(despitetheinstructions)enteranumberthatisnotbetween1and5,orevenperhapsaletter.Inthiscase,youaddamessagetolettheuserknowthatthereisaproblem:
default:
document.write("Youdidnotenteranumberbetween1and5.");
break;
Adefaultstatementisalsoveryusefulforpickingupbugs—ifyouhavecodedsomeofthecasestatementsincorrectly,youwillpickthatupveryquicklyifyouseethedefaultcodebeingrunwhenitshouldn’tbe.
Finally,youhaveaddedtheclosingbraceindicatingtheendoftheswitchstatement.Afterthisyououtputalinetoindicatewheretheexecutioncontinues:
}
document.write("<br/>Executioncontinueshere");
Notethateachcasestatementendswithabreakstatement.Thisisimportanttoensurethatexecutionofthecodemovestothelineaftertheendoftheswitchstatement.Ifyouforgettoincludethis,youcouldendupexecutingthecodeforeachcasefollowingthecasethatmatches.
ExecutingtheSameCodeforDifferentCasesYoumayhavespottedaproblemwiththeswitchstatementinthisexample—youwanttoexecutethesamecodeiftheuserentersa1ora2,andthesamecodefora4ora5.However,toachievethis,youhavehadtorepeatthecodeineachcase.WhatyouwantisaneasierwayofgettingJavaScripttoexecutethesamecodefordifferentcases.Well,that’seasy!Simplychangethecodesothatitlookslikethis:
switch(secretNumber){
case1:
case2:
document.write("Toolow!");
break;
case3:
document.write("Youguessedthesecretnumber!");
break;
case4:
case5:
document.write("Toohigh!");
break;
default:
document.write("Youdidnotenteranumberbetween1and5.");
break;
}
Ifyouloadthisintoyourbrowserandexperimentwithenteringsomedifferentnumbers,youshouldseethatitbehavesexactlylikethepreviouscode.
Here,youaremakinguseofthefactthatifthereisnobreakstatementunderneaththecodeforacertaincasestatement,executionwillcontinuethrougheachfollowingcasestatementuntilabreakstatementortheendoftheswitchisreached.Thinkofitasasortoffreefallthroughtheswitchstatementuntilyouhitthebreakstatement.
Ifthecasestatementforthevalue1ismatched,executionsimplycontinuesuntilthebreakstatementundercase2,soeffectivelyyoucanexecutethesamecodeforbothcases.Thesametechniqueisusedforthecasestatementswithvalues4and5.
LOOPING—THEFORANDWHILESTATEMENTSLoopingmeansrepeatingablockofcodewhenaconditionistrue.ThisisachievedinJavaScriptwiththeuseoftwostatements:thewhilestatementandtheforstatement.You’llbelookingattheseshortly,butwhywouldyouwanttorepeatblocksofcodeanyway?
Well,takethesituationwhereyouhaveaseriesofresults,saytheaveragetemperatureforeachmonthinayear,andyouwanttoplottheseonagraph.Thecodeneededforplottingeachpointwillmostlikelybethesame.So,ratherthanwritethecode12times(onceforeachpoint),it’smucheasiertoexecutethesamecode12timesbyusingthenextitemofdataintheseries.Thisiswheretheforstatementwouldcomeinhandy,becauseyouknowhowmanytimesyouwantthecodetoexecute.
Inanothersituation,youmightwanttorepeatthesamepieceofcodewhenacertainconditionistrue,forexample,whiletheuserkeepsclickingaStartAgainbutton.Inthissituation,thewhilestatementwouldbeveryuseful.
TheforLoopTheforstatementenablesyoutorepeatablockofcodeacertainnumberoftimes.ThesyntaxisillustratedinFigure3.10.
Figure3.10
Let’slookatthemakeupofaforstatement.YoucanseefromFigure3.10that,justliketheifandswitchstatements,theforstatementalsohasitslogicinsideparentheses.However,thistimethatlogicissplitintothreeparts,eachpartseparatedbyasemicolon.Forexample,inFigure3.10youhavethefollowing:
(varloopCounter=1;loopCounter<=3;loopCounter++)
Thefirstpartoftheforstatement’slogicistheinitializationpartoftheforstatement.Tokeeptrackofhowmanytimesyouhaveloopedthroughthecode,youneedavariabletokeepcount.It’sintheinitializationpartthatyouinitializevariables.Intheexample,you
havedeclaredloopCounterandsetittothevalueof1.Thispartisonlyexecutedonceduringtheexecutionoftheloops,unliketheotherparts.Youdon’tneedtodeclarethevariableifitwasdeclaredearlierinthecode:
varloopCounter;
for(loopCounter=1;loopCounter<=3;loopCounter++)
Followingthesemicolon,youhavethetestconditionpartoftheforstatement.Thecodeinsidetheforstatementwillkeepexecutingforaslongasthistestconditionevaluatestotrue.Afterthecodeisloopedthrougheachtime,thisconditionistested.InFigure3.10,youexecuteforaslongasloopCounterislessthanorequalto3.Thenumberoftimesaloopisperformedisoftencalledthenumberofiterations.
Finally,youhavetheincrementpartoftheforloop,wherevariablesinyourloop’stestconditionhavetheirvaluesincremented.HereyoucanseethatloopCounterisincrementedbyonebymeansofthe++operatoryousawinChapter2.Again,thispartoftheforstatementisrepeatedwitheveryloopofthecode.Althoughwecallittheincrementpart,itcanactuallybeusedtodecrease,ordecrement,thevalue—forexample,ifyouwantedtocountdownfromthetopelementinanarraytothefirst.
Aftertheforstatementcomestheblockofcodethatwillbeexecutedrepeatedly,aslongasthetestconditionistrue.Thisblockofcodeiscontainedwithincurlybraces.Iftheconditionisnevertrue,evenatthefirsttestoftheloopcondition,thecodeinsidetheforloopwillbeskippedoverandneverexecuted.
Puttingallthistogether,howdoestheforloopwork?
1. Executeinitializationpartoftheforstatement.
2. Checkthetestcondition.Iftrue,continue;ifnot,exittheforstatement.
3. Executecodeintheblockaftertheforstatement.
4. Executetheincrementpartoftheforstatement.
5. Repeatsteps2through4untilthetestconditionisfalse.
TRYITOUTConvertingaSeriesofFahrenheitValuesLet’schangethetemperatureconvertersothatitconvertsaseriesofvalues,storedinanarray,fromFahrenheittocentigrade.Youwillbeusingtheforstatementtogothrougheachelementofthearray.Typethefollowingcodeandsaveitasch3_example4.html:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter3,Example4</title>
</head>
<body>
<script>
vardegFahren=[212,32,-459.15];
vardegCent=[];
varloopCounter;
for(loopCounter=0;loopCounter<=2;loopCounter++){
degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);
}
for(loopCounter=2;loopCounter>=0;loopCounter−−){
document.write("Value"+loopCounter+
"was"+degFahren[loopCounter]+
"degreesFahrenheit");
document.write("whichis"+degCent[loopCounter]+
"degreescentigrade<br/>");
}
</script>
</body>
</html>
Onloadingthisintoyourbrowser,you’llseeaseriesofthreelinesinthepage,containingtheresultsofconvertingyourarrayofFahrenheitvaluesintocentigrade(asshowninFigure3.11).
Figure3.11
Thefirsttaskistodeclarethevariablesyouaregoingtouse.First,youdeclareandinitializedegFahrentocontainanarrayofthreevalues:212,32,and–459.15.Next,youdeclaredegCentasanemptyarray.Finally,youdeclareloopCounterandwilluseittokeeptrackofwhicharrayindexyouareaccessingduringyourlooping:
vardegFahren=[212,32,-459.15];
vardegCent=[];
varloopCounter;
Followingthiscomesyourfirstforloop:
for(loopCounter=0;loopCounter<=2;loopCounter++){
degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);
}
Inthefirstline,youstartbyinitializingtheloopCounterto0.Thentheforloop’stestcondition,loopCounter<=2,ischecked.Ifthisconditionistrue,theloopexecutesforthefirsttime.Afterthecodeinsidethecurlybraceshasexecuted,theincrementingpartoftheforloop,loopCounter++,willbeexecuted,andthenthetestconditionwillbere-evaluated.Ifit’sstilltrue,anotherexecutionoftheloopcodeisperformed.Thiscontinuesuntiltheforloop’stestconditionevaluatestofalse,atwhichpointloopingwillend,andthefirststatementaftertheclosingcurlybracewillbeexecuted.
Thecodeinsidethecurlybracesistheequationyousawinearlierexamples,onlythistimeyouareplacingitsresultintothedegCentarray,withtheindexbeingthevalueofloopCounter.
Inthesecondforloop,youwritetheresultscontainedinthedegCentarraytothescreen:
for(loopCounter=2;loopCounter>=0;loopCounter−−){
document.write("Value"+loopCounter+
"was"+degFahren[loopCounter]+
"degreesFahrenheit");
document.write("whichis"+degCent[loopCounter]+
"degreescentigrade<br/>");
}
Thistimeyou’recountingdownfrom2to0.ThevariableloopCounterisinitializedto2,andtheloopconditionremainstrueuntilloopCounterislessthan0.ThistimeloopCounterisactuallydecrementedeachtimeratherthanincremented,bymeansofloopCounter−−.Again,loopCounterisservingadualpurpose:Itkeepscountofhowmanyloopsyouhavedoneandalsoprovidestheindexpositioninthearray.
NOTEIntheseexamples,you’veusedwholenumbersinyourloops.However,thereisnoreasonwhyyoucan’tusefractionalnumbers,althoughit’smuchlesscommontodoso.
Thefor…inLoopThisloopenablesyoutoloopthrougheachelementinthearraywithouthavingtoknowhowmanyelementsthearrayactuallycontains.InplainEnglish,whatthisloopsaysis“Foreachelementinthearray,executesomecode.”Ratherthanhavingtoworkouttheindexnumberofeachelement,thefor… inloopdoesitforyouandautomaticallymoves
tothenextindexwitheachiteration(loopthrough).
Itssyntaxforusewitharraysis:
for(indexinarrayName){
//somecode
}
Inthiscodeextract,indexisavariableyoudeclarepriortotheloop,whichwillautomaticallybepopulatedwiththenextindexvalueinthearray.arrayNameisthenameofthevariableholdingthearrayyouwanttoloopthrough.
Let’slookatanexampletomakethingsclearer.Youdefineanarrayandinitializeitwiththreevalues:
varmyArray=["Paul","Paula","Pauline"];
Toaccesseachelementusingaconventionalforloop,you’dwritethis:
for(varloopCounter=0;loopCounter<3;loopCounter++){
document.write(myArray[loopCounter]);
}
Todoexactlythesamethingwiththefor… inloop,youwritethis:
for(varelementIndexinmyArray){
document.write(myArray[elementIndex]);
}
Asyoucansee,thecodeinthesecondexampleisalittleclearer,aswellasshorter.Bothmethodsworkequallywellandwilliteratethreetimes.However,ifyouincreasethesizeofthearray,forexample,byaddingtheelementmyArray[3]="Philip",thefirstmethodwillstilllooponlythroughthefirstthreeelementsinthearray,whereasthesecondmethodwillloopthroughallfourelements.
ThewhileLoopWhereastheforloopisusedforloopingacertainnumberoftimes,thewhileloopenablesyoutotestaconditionandkeeponloopingwhileit’strue.Theforloopisusefulwhenyouknowhowmanytimesyouneedtoloop;forexample,whenyouareloopingthroughanarraythatyouknowhasacertainnumberofelements.Thewhileloopismoreusefulwhenyoudon’tknowhowmanytimesyou’llneedtoloop.Forexample,ifyouareloopingthroughanarrayoftemperaturevaluesandwanttocontinueloopingwhenthetemperaturevaluecontainedinthearrayelementislessthan100,youwillneedtousethewhilestatement.
Let’stakealookatthestructureofthewhilestatement,asillustratedinFigure3.12.
Figure3.12
Youcanseethatthewhileloophasfewerpartstoitthantheforloop.Thewhileloopconsistsofaconditionwhich,ifitevaluatestotrue,causestheblockofcodeinsidethecurlybracestoexecuteonce;thentheconditionisre-evaluated.Ifit’sstilltrue,thecodeisexecutedagain,theconditionisre-evaluated,andsoonuntiltheconditionevaluatestofalse.
Onethingtowatchoutforisthatiftheconditionisfalsetostartwith,thewhileloopneverexecutes.Forexample:
vardegCent=100;
while(degCent!=100){
//somecode
}
Here,theloopwillrunifdegCentdoesnotequal100.However,becausedegCentis100,theconditionisfalse,andthecodeneverexecutes.
Inpracticeyouwouldnormallyexpectthelooptoexecuteonce;whetheritexecutesagainwilldependonwhatthecodeinsidetheloophasdonetovariablesinvolvedintheloop
condition.Forexample:
vardegCent=[];
degFahren=[34,123,212];
varloopCounter=0;
while(loopCounter<3){
degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);
loopCounter++;
}
TheloopwillexecutesolongasloopCounterislessthan3.It’sthecodeinsidetheloop(loopCounter++;)thatincrementsloopCounterandwilleventuallycauseloopCounter<3tobefalsesothattheloopstops.Executionwillthencontinueonthefirstlineaftertheclosingbraceofthewhilestatement.
Somethingtowatchoutforistheinfiniteloop—aloopthatwillneverend.SupposeyouforgottoincludetheloopCounter++;lineinthecode.LeavingthislineoutwouldmeanthatloopCounterwillremainat0,sothecondition(loopCounter<3)willalwaysbetrue,andtheloopwillcontinueuntiltheusergetsboredandcross,andshutsdownherbrowser.However,itisaneasymistaketomake,andonethatJavaScriptwon’twarnyouabout.
It’snotjustmissinglinesthatcancauseinfiniteloops,butalsomistakesinsidetheloop’scode.Forexample:
vartestVariable=0;
while(testVariable<=10){
alert("TestVariableis"+testVariable);
testVariable++;
if(testVariable=10){
alert("Thelastloop");
}
}
Seeifyoucanspotthedeliberatemistakethatleadstoaninfiniteloop—yes,it’stheifstatementthatwillcausethiscodetogoonforever.Insteadofusing==asthecomparisonoperatorintheconditionoftheifstatement,youput=,sotestVariableissetto10againineachloop,despitethelinetestVariable++.Thismeansthatatthestartofeachloop,thetestconditionalwaysevaluatestotrue,because10islessthanorequalto10.Puttheextra=intomakeif(testVariable==10),andeverythingisfine.
Thedo…whileloopWiththewhileloop,yousawthatthecodeinsidethelooponlyexecutesiftheconditionistrue;ifit’sfalse,thecodeneverexecutes,andexecutioninsteadmovestothefirstlineafterthewhileloop.However,theremaybetimeswhenyouwantthecodeinthewhilelooptoexecuteatleastonce,regardlessofwhethertheconditioninthewhilestatementevaluatestotrue.Itmightevenbethatsomecodeinsidethewhileloopneedstobeexecutedbeforeyoucantestthewhilestatement’scondition.It’ssituationslikethisfor
whichthedo… whileloopisideal.
Lookatanexampleinwhichyouwanttogettheuser’sageviaapromptbox.Youwanttoshowthepromptboxbutalsomakesurethatwhattheuserhasenteredisanumber:
varuserAge;
do{
userAge=prompt("Pleaseenteryourage","")
}while(isNaN(userAge)==true);
Thecodelinewithintheloop:
userAge=prompt("Pleaseenteryourage","")
willbeexecutedregardlessofthewhilestatement’scondition.Thisisbecausetheconditionisnotcheckeduntiloneloophasbeenexecuted.Iftheconditionistrue,thecodeisloopedthroughagain.Ifit’sfalse,loopingstops.
Notethatwithinthewhilestatement’scondition,youareusingtheisNaN()functionthatyousawinChapter2.ThischeckswhethertheuserAgevariable’svalueisNaN(NotaNumber).Ifitisnotanumber,theconditionreturnsavalueoftrue;otherwise,itreturnsfalse.Asyoucanseefromtheexample,itenablesyoutotesttheuserinputtoensuretherightdatahasbeenentered.Theusermightlieabouthisage,butatleastyouknowheenteredanumber!
Thedo… whileloopisfairlyrare;there’snotmuchyoucan’tdowithoutit,soit’sbestavoidedunlessreallynecessary.
ThebreakandcontinueStatementsYoumetthebreakstatementearlierwhenyoulookedattheswitchstatement.Itsfunctioninsideaswitchstatementistostopcodeexecutionandmoveexecutiontothenextlineofcodeaftertheclosingcurlybraceoftheswitchstatement.However,youcanalsousethebreakstatementaspartoftheforandwhileloopswhenyouwanttoexittheloopprematurely.Forexample,supposeyou’reloopingthroughanarray,asyoudidinthetemperatureconversionexample,andyouhitaninvalidvalue.Inthissituation,youmightwanttostopthecodeinitstracks,notifytheuserthatthedataisinvalid,andleavetheloop.Thisisonesituationwherethebreakstatementcomesinhandy.
Let’sseehowyoucouldchangetheexamplewhereyouconvertedaseriesofFahrenheitvalues(ch3_example4.html)sothatifyouhitavaluethat’snotanumberyoustoptheloopandlettheuserknowabouttheinvaliddata:
<script>
vardegFahren=[212,"stringdata",-459.67];
vardegCent=[];
varloopCounter;
for(loopCounter=0;loopCounter<=2;loopCounter++){
if(isNaN(degFahren[loopCounter])){
alert("Data'"+degFahren[loopCounter]+"'atarrayindex"+
loopCounter+"isinvalid");
break;
}
degCent[loopCounter]=5/9*(degFahren[loopCounter]-32);
}
YouhavechangedtheinitializationofthedegFahrenarraysothatitnowcontainssomeinvaliddata.Then,insidetheforloop,youaddanifstatementtocheckwhetherthedatainthedegFahrenarrayisnotanumber.YoudothisbymeansoftheisNaN()function;itreturnstrueifthevaluepassedtoitintheparentheses,heredegFahren[loopCounter],isnotanumber.Ifthevalueisnotanumber,youtelltheuserwhereinthearrayyouhavetheinvaliddata.Thenyoubreakoutoftheforloopaltogether,usingthebreakstatement,andcodeexecutioncontinuesonthefirstlineaftertheendoftheforstatement.
That’sthebreakstatement,butwhataboutcontinue?Thecontinuestatementissimilartobreakinthatitstopstheexecutionofaloopatthepointwhereitisfound,butinsteadofleavingtheloop,itstartsexecutionatthenextiteration,startingwiththefororwhilestatement’sconditionbeingre-evaluated,justasifthelastlineoftheloop’scodehadbeenreached.
Inthebreakexample,itwasallornothing—ifevenonepieceofdatawasinvalid,youbrokeoutoftheloop.ItmightbebetterifyoutriedtoconvertallthevaluesindegFahren,butifyouhitaninvaliditemofdatainthearray,younotifytheuserandcontinuewiththenextitem,ratherthangivingupasthebreakstatementexampledoes:
if(isNaN(degFahren[loopCounter])){
alert("Data'"+degFahren[loopCounter]+"'atarrayindex"+
loopCounter+"isinvalid");
continue;
}
Justchangethebreakstatementtoacontinue.Youwillstillgetamessageabouttheinvaliddata,butthethirdvaluewillalsobeconverted.
SUMMARYInthischapteryoucontinuedyourlookatthecoreoftheJavaScriptlanguageanditssyntax.
Thechapterlookedatthefollowing:
Decisionmakingwiththeifandswitchstatements:Theabilitytomakedecisionsisessentiallywhatgivesthecodeits“intelligence.”Basedonwhetheraconditionistrueorfalse,youcandecideonacourseofactiontofollow.
Comparisonoperators:Thecomparisonoperatorscomparethevalueontheleftoftheoperator(left-handside,LHS)withthevalueontherightoftheoperator(right-handside,RHS)andreturnabooleanvalue.Hereisalistofthemaincomparisonoperators:
==means“istheLHSequaltotheRHS?”
!=means“istheLHSnotequaltotheRHS?”
<=means“istheLHSlessthanorequaltotheRHS?”
>=means“istheLHSgreaterthanorequaltotheRHS?”
<means“istheLHSlessthantheRHS?”
>means“istheLHSgreaterthantheRHS?”
Theifstatement:Usingtheifstatement,youcanchoosetoexecuteablockofcode(definedbybeingincurlybraces)whenaconditionistrue.Theifstatementhasatestcondition,specifiedinparentheses.Ifthisconditionevaluatestotrue,thecodeaftertheifstatementwillexecute.
Theelsestatement:Ifyouwantcodetoexecutewhentheifstatementisfalse,youcanusetheelsestatementthatappearsaftertheifstatement.
Logicaloperators:Tocombineconditions,youcanusethethreelogicaloperators:AND,OR,andNOT,representedby&&,||,and!,respectively:
TheANDoperatorreturnstrueonlyifbothsidesoftheexpressionaretrue.
TheORoperatorreturnstruewheneitheroneorbothsidesofanexpressionaretrue.
TheNOToperatorreversesthelogicofanexpression.
Theswitchstatement:Thiscomparestheresultofanexpressionwithaseriesofpossiblecasesandissimilarineffecttoamultipleifstatement.
Loopingwithfor,for… in,while,anddo… while:It’softennecessarytorepeatablockofcodeanumberoftimes,somethingJavaScriptenablesbylooping.
Theforloop:Usefulforloopingthroughcodeacertainnumberoftimes,theforloopconsistsofthreeparts:theinitialization,testcondition,andincrementparts.Loopingcontinueswhilethetestconditionistrue.Eachloopexecutesthe
blockofcodeandthenexecutestheincrementpartoftheforloopbeforere-evaluatingthetestconditiontoseeiftheresultsofincrementinghavechangedit.
Thefor… inloop:Thisisusefulwhenyouwanttoloopthroughanarraywithoutknowingthenumberofelementsinthearray.JavaScriptworksthisoutforyousothatnoelementsaremissed.
Thewhileloop:Thisisusefulforloopingthroughsomecodeforaslongasatestconditionremainstrue.Itconsistsofatestconditionandtheblockofcodethat’sexecutedonlyiftheconditionistrue.Iftheconditionisnevertrue,thecodeneverexecutes.
Thedo… whileloop:Thisissimilartoawhileloop,exceptthatitexecutesthecodeonceandthenkeepsexecutingthecodeaslongasthetestconditionremainstrue.
breakandcontinuestatements:Sometimesyouhaveagoodreasontobreakoutofaloopprematurely,inwhichcaseyouneedtousethebreakstatement.Onhittingabreakstatement,codeexecutionstopsfortheblockofcodemarkedoutbythecurlybracesandstartsimmediatelyaftertheclosingbrace.Thecontinuestatementissimilartobreak,exceptthatwhencodeexecutionstopsatthatpointintheloop,theloopisnotbrokenoutofbutinsteadcontinuesasiftheendofthatreiterationhadbeenreached.
EXERCISES1. Ajuniorprogrammercomestoyouwithsomecodethatappearsnottowork.Can
youspotwherehewentwrong?Givehimahandandcorrectthemistakes.
varuserAge=prompt("Pleaseenteryourage");
if(userAge=0){;
alert("Soyou'reababy!");
}elseif(userAge<0|userAge>200)
alert("Ithinkyoumaybelyingaboutyourage");
else{
alert("That'sagoodage");
}
2. Usingdocument.write(),writecodethatdisplaystheresultsofthe12timestable.Itsoutputshouldbetheresultsofthecalculations.
12*1=12
12*2=24
12*3=36…
12*11=132
12*12=144
4FunctionsandScopeWHATYOUWILLLEARNINTHISCHAPTER:
Creatingyourownfunctions
Identifying,creating,andusingglobalandlocalvariables
Usingfunctionsasavalue
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Afunctionissomethingthatperformsaparticulartask.Takeapocketcalculatorasanexample.Itperformslotsofbasiccalculations,suchasadditionandsubtraction.However,manyalsohavefunctionkeysthatperformmorecomplexoperations.Forexample,somecalculatorshaveabuttonforcalculatingthesquarerootofanumber,andothersevenprovidestatisticalfunctions,suchasthecalculationofanaverage.Mostofthesefunctionscouldbedonewiththebasicmathematicaloperationsofadd,subtract,multiply,anddivide,butthatmighttakealotofsteps—it’smuchsimplerfortheuserifsheonlyneedstopressonebutton.Allsheneedstodoisprovidethedata—numbersinthiscase—andthefunctionkeydoestherest.
FunctionsinJavaScriptworkalittlelikethefunctionbuttonsonapocketcalculator:Theyencapsulateablockofcodethatperformsacertaintask.Overthecourseofthebooksofar,youhavecomeacrossanumberofhandybuilt-infunctionsthatperformacertaintask,suchastheparseInt()andparseFloat()functions,whichconvertstringstonumbers,andtheisNaN()function,whichtellsyouwhetheraparticularvaluecanbeconvertedtoanumber.Someofthesefunctionsreturndata,suchasparseInt(),whichreturnsanintegernumber;otherssimplyperformanactionbutreturnnodata.You’llalsonoticethatsomefunctionscanbepasseddata,whereasotherscannot.Forexample,theisNaN()functionneedstobepassedsomedata,whichitcheckstoseeifitisNaN.Thedatathatafunctionrequirestobepassedareknownasitsparameter(s).
Asyouworkyourwaythroughthebook,you’llbecomingacrossmanymoreusefulbuilt-infunctions,butwouldn’titbegreattobeabletowriteyourownfunctions?Afteryou’veworkedout,written,anddebuggedablockofcodetoperformacertaintask,itwouldbenicetobeabletocallitagainandagainwhenyouneedit.JavaScriptenablesustodojustthat,andthisiswhatyou’llbeconcentratingoninthissection.
CREATINGYOUROWNFUNCTIONSCreatingandusingyourownfunctionsisverysimple.Figure4.1showsanexampleofafunctiondeclaration.
Figure4.1
You’veprobablyalreadyrealizedwhatthisfunctiondoesandhowthecodeworks.Yes,it’stheinfamousFahrenheit-to-centigradeconversioncodeagain.
EachfunctionyoudefineinJavaScriptmustbegivenauniquenameforthatparticularpage.Thenamecomesimmediatelyafterthefunctionkeyword.Tomakelifeeasierforyourself,tryusingmeaningfulnamessothatwhenyouseethembeingusedlaterinyourcode,you’llknowexactlywhattheydo.Forexample,afunctionthattakesasitsparameterssomeone’sbirthdayandtoday’sdateandreturnstheperson’sagecouldbecalledgetAge().However,thenamesyoucanusearelimited,muchasvariablenamesare.Forexample,youcan’tusewordsreservedbyJavaScript,soyoucan’tcallyourfunctionif()orwhile().
Theparametersforthefunctionaregiveninparenthesesafterthefunction’sname.Aparameterisjustanitemofdatathatthefunctionneedstobegiveninordertodoitsjob.Usually,notpassingtherequiredparameterswillresultinanerror.Afunctioncanhavezeroormoreparameters,thoughevenifithasnoparameters,youmuststillputtheopenandcloseparenthesesafteritsname.Forexample,thetopofyourfunctiondefinitionmustlooklikethefollowing:
functionmyNoParamFunction()
Youthenwritethecode,whichthefunctionwillexecutewhencalledontodoso.Allthefunctioncodemustbeputinablockwithapairofcurlybraces.
Functionsalsoenableyoutoreturnavaluefromafunctiontothecodethatcalledit.Youusethereturnstatementtoreturnavalue.Intheexamplefunctiongivenearlier,youreturnthevalueofthevariabledegCent,whichyouhavejustcalculated.Youdon’thavetoreturnavalueifyoudon’twantto,butit’simportanttonotethateveryfunctionreturnsavalueevenifyoudon’tusethereturnstatement.Functionsthatdonotexplicitlyreturnavalue—thatis,returnavaluewiththereturnstatement—returnundefined.
WhenJavaScriptcomesacrossareturnstatementinafunction,ittreatsitabitlikeabreakstatementinaforloop—itexitsthefunction,returninganyvaluespecifiedafterthereturnkeyword.
You’llprobablyfinditusefultobuildupa“library”offunctionsthatyouusefrequentlyinJavaScriptcode,whichyoucanreferenceinyourpages.
Havingcreatedyourfunctions,howdoyouusethem?Unlikethecodeyou’veseensofar,whichexecuteswhenJavaScriptreachesthatline,functionsonlyexecuteifyouaskthemto,whichistermedcallingorinvokingthefunction.Youcallafunctionbywritingitsnameatthepointwhereyouwantittobecalledandmakingsurethatyoupassanyparametersitneeds,separatedbycommas.Forexample:
myTemp=convertToCentigrade(212);
ThislinecallstheconvertToCentigrade()functionyousawearlier,passing212astheparameterandstoringthereturnvaluefromthefunction(thatis,100)inthemyTempvariable.
Haveagoatcreatingyourownfunctionsnow,takingacloserlookathowparametersarepassed.Parameterpassingcanbeabitconfusing,soyou’llfirstcreateasimplefunctionthattakesjustoneparameter(theuser’sname)andwritesittothepageinafriendlywelcomestring.First,youneedtothinkofanameforyourfunction.AshortbutdescriptivenameiswriteUserWelcome().Nowyouneedtodefinewhatparametersthefunctionexpectstobepassed.There’sonlyoneparameter—theusername.Definingparametersisalittlelikedefiningvariables—youneedtosticktothesamerulesfornaming,sothatmeansnospaces,specialcharacters,orreservedwords.Let’scallyourparameteruserName.Youneedtoadditinsideparenthesestotheendofthefunctionname(notethatyoudon’tputasemicolonattheendoftheline):
functionwriteUserWelcome(userName)
Okay,nowyouhavedefinedyourfunctionnameanditsparameters;allthat’sleftistocreatethefunctionbody—thatis,thecodethatwillbeexecutedwhenthefunctioniscalled.Youmarkoutthispartofthefunctionbywrappingitincurlybraces:
functionwriteUserWelcome(userName){
document.write("Welcometomywebsite"+userName+"<br/>");
document.write("Hopeyouenjoyit!");
}
Thecodeissimpleenough;youwriteoutamessagetothewebpageusingdocument.write().YoucanseethatuserNameisusedjustasyou’duseanynormalvariable;infact,it’sbesttothinkofparametersasnormalvariables.ThevaluethattheparameterhaswillbethatspecifiedbytheJavaScriptcodewherethefunctionwascalled.
Let’sseehowyouwouldcallthisfunction:
writeUserWelcome("Paul");
Simple,really—justwritethenameofthefunctionyouwanttocall,andtheninparenthesesaddthedatatobepassedtoeachoftheparameters,herejustonepiece.When
thecodeinthefunctionisexecuted,thevariableuserName,usedinthebodyofthefunctioncode,willcontainthetext"Paul".
Supposeyouwantedtopasstwoparameterstoyourfunction—whatwouldyouneedtochange?Well,firstyou’dhavetoalterthefunctiondefinition.Imaginethatthesecondparameterwillholdtheuser’sage—youcouldcallituserAgebecausethatmakesitprettyclearwhattheparameter’sdatarepresents.Hereisthenewcode:
functionwriteUserWelcome(userName,userAge){
document.write("Welcometomywebsite"+userName+"<br/>");
document.write("Hopeyouenjoyit<br/>");
document.write("Yourageis"+userAge);
}
You’veaddedalinetothebodyofthefunctionthatusestheparameteryouhaveadded.Tocallthefunction,you’dwritethefollowing:
writeUserWelcome("Paul",31);
Thesecondparameterisanumber,sothereisnoneedforquotesaroundit.HeretheuserNameparameterwillbePaul,andthesecondparameter,userAge,willbe31.
TRYITOUTFahrenheittoCentigradeFunctionLet’srewritethetemperatureconverterpageusingfunctions.Youcancutandpastemostofthiscodefromch3_example4.html—thepartsthathavechangedhavebeenhighlighted.Whenyou’vefinished,saveitasch4_example1.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter4,Example1</title>
</head>
<body>
<script>
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
vardegFahren=[212,32,-459.15];
vardegCent=[];
varloopCounter;
for(loopCounter=0;loopCounter<=2;loopCounter++){
degCent[loopCounter]=
convertToCentigrade(degFahren[loopCounter]);
}
for(loopCounter=2;loopCounter>=0;loopCounter−−){
document.write("Value"+loopCounter+
"was"+degFahren[loopCounter]+
"degreesFahrenheit");
document.write("whichis"+degCent[loopCounter]+
"degreescentigrade<br/>");
}
</script>
</body>
</html>
Whenyouloadthispageintoyourbrowser,youshouldseeexactlythesameresultsthatyouhadwithch3_example4.html.
AtthetopofthescriptblockyoudeclareyourconvertToCentigrade()function.Yousawthisfunctionearlier:
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
Ifyou’reusinganumberofseparatescriptblocksinapage,it’sveryimportantthatthefunctionbedefinedbeforeanyscriptcallsit.Ifyouhaveanumberoffunctions,youmaywanttoputthemallintheirownscriptfileandloaditbeforeallotherscripts.Thatwayyouknowwheretofindallyourfunctions,andyoucanbesurethattheyhavebeendeclaredbeforetheyhavebeenused.
Youshouldbeprettyfamiliarwithhowthecodeinthefunctionworks.YoudeclareavariabledegCent,doyourcalculation,andthenreturndegCentbacktothecallingcode.Thefunction’sparameterisdegFahren,whichprovidestheinformationthecalculationneeds.
Followingthefunctiondeclarationisthecodethatexecuteswhenthepageloads.Firstyoudefinethevariablesyouneed,andthenyouhavethetwoloopsthatcalculateandthenoutputtheresults.Thisismostlythesameasbefore,apartfromthefirstforloop:
for(loopCounter=0;loopCounter<=2;loopCounter++){
degCent[loopCounter]=convertToCentigrade(degFahren[loopCounter]);
}
ThecodeinsidethefirstforloopputsthevaluereturnedbythefunctionconvertToCentigrade()intothedegCentarray.
Thereisasubtlepointtothecodeinthisexample.NoticethatyoudeclarethevariabledegCentwithinyourfunctionconvertToCentigrade(),andyoualsodeclareitasanarrayafterthefunctiondefinition.
Surelythisisn’tallowed?
Well,thisleadsneatlytothenexttopicofthischapter—scope.
SCOPEANDLIFETIMEWhatismeantbyscope?Well,putsimply,it’sthescopeorextentofavariable’sorfunction’savailability—whichpartsofyourcodecanaccessavariableandthedataitcontains.Scopeisimportanttoanyprogramminglanguage—evenmoresoinJavaScript—soit’simperativethatyouunderstandhowscopeworksinJavaScript.
GlobalScopeAnyvariablesorfunctionsdeclaredoutsideofafunctionwillbeavailabletoallJavaScriptcodeonthepage,whetherthatcodeisinsideafunctionorotherwise—wecallthisglobalscope.Lookatthefollowingexample:
vardegFahren=12;
functionconvertToCentigrade(){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
Inthiscode,thedegFahrenvariableisaglobalvariablebecauseitiscreatedoutsideofafunction,andbecauseitisglobal,itcanbeusedanywhereinthepage.TheconvertToCentigrade()functionaccessesthedegFahrenvariable,usingitaspartofthecalculationtoconvertFahrenheittocentigrade.
Thisalsomeansyoucanchangethevalueofaglobalvariable,andthefollowingcodedoesjustthat:
vardegFahren=12;
functionconvertToCentigrade(){
degFahren=20;
vardegCent=5/9*(degFahren-32);
returndegCent;
}
ThisnewlineofcodechangesthevalueofdegFahrento20;sotheoriginalvalueof12isnolongerusedinthecalculation.Thischangeinvalueisn’tseenonlyinsideoftheconvertToCentigrade()function.ThedegFahrenvariableisaglobalvariable,andthusitsvalueis20everywhereitisused.
Additionally,thecovertToCentigrade()functionisaglobalfunctionbecauseitisdefinedoutsideofanotherfunction(yes,youcancreateafunctionwithinafunction…funception!),andtheytoocanbeaccessedanywhereinthepage.
Inpractice,youwanttoavoidcreatingglobalvariablesandfunctionsbecausetheycanbeeasilyandunintentionallymodified.Youcanusesometrickstoavoidglobals,andyouwillseethemthroughoutthisbook,buttheyallboildowntocreatingvariablesand
functionsinfunctionalscope.
FunctionalScopeVariablesandfunctionsdeclaredinsideafunctionarevisibleonlyinsidethatfunction—nocodeoutsidethefunctioncanaccessthem.Forexample,considerourstandardconvertToCentigrade()function:
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
ThedegCentvariableisdefinedinsidetheconvertToCentigrade()function.Therefore,itcanonlybeaccessedfromwithinconvertToCentigrade().Thisiscommonlyreferredtoasfunctionalorlocalscope,anddegCentiscommonlycalledalocalvariable.
Functionparametersaresimilartovariables;theyhavelocalscope,andthuscanonlybeaccessedfromwithinthefunction.SointhecaseofthepreviousconvertToCentigrade()function,degFahrenanddegCentarelocalvariables.
Sowhathappenswhenthecodeinsideafunctionendsandexecutionreturnstothepointatwhichthecodewascalled?Dothevariablesdefinedwithinthefunctionretaintheirvaluewhenyoucallthefunctionthenexttime?
Theanswerisno:Variablesnotonlyhavethescopeproperty—wheretheyarevisible—buttheyalsohavealifetime.Whenthefunctionfinishesexecuting,thevariablesinthatfunctiondieandtheirvaluesarelost,unlessyoureturnoneofthemtothecallingcode.EverysooftenJavaScriptperformsgarbagecollection(whichwetalkedaboutinChapter2),wherebyitscansthroughthecodeandseesifanyvariablesarenolongerinuse;ifso,thedatatheyholdarefreedfrommemorytomakewayforthedataofothervariables.
IdentifierLookupWhathappensifyouusethesamevariablenameforbothaglobalandlocalvariable?JavaScripthandlesthisseeminglycatastrophiceventwithaprocesscalledidentifierlookup.Anidentifierissimplythenameyougiveavariableorfunction.So,identifierlookupistheprocessthattheJavaScriptengineusestofindavariableorfunctionwithagivenname.Considerthefollowingcode:
vardegCent=10;
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
ThiscodecontainstwodegCentvariables:Oneisglobal,andtheotherislocaltoconvertToCentigrade().Whenyouexecutethefunction,theJavaScriptenginecreates
thelocaldegCentvariableandassignsittheresultoftheFahrenheit-to-centigradeconversion—theglobaldegCentvariableisleftaloneandstillcontains10.Butwhatvaluedoesthereturnstatementreturn:theglobalorlocaldegCent?
TheJavaScriptenginebeginstheidentifierlookupprocessinthecurrentlevelofscope.Therefore,itstartslookingwithinthefunctionalscopeofconvertToCentigrade()foravariableorfunctionwiththenamedegCent,itfindsthelocalvariable,andusesitsvalueinthereturnstatement.
ButifdegCentwasnotcreatedwithinconvertToCentigrade(),theJavaScriptenginewouldthenlookinthenextlevelofscope—theglobalscopeinthiscase—forthedegCentidentifier.Itwouldfindtheglobalvariableanduseitsvalue.
Sonowthatyouunderstandhowscopeworks,revisitExample1inthe“FahrenheittoCentigradeFunction”TryItOut.EventhoughithastwodegCentvariables—oneglobalandonelocaltoconvertToCentigrade()—thecodeexecuteswithoutaproblem.Insidethefunction,thelocaldegCentvariabletakesprecedenceovertheglobal.Andoutsideofthefunction,thelocalvariableisnolongerinscope;therefore,theglobaldegCentisused.
Althoughit’sperfectlyvalidtousethesameidentifierforglobalandlocalvariables,itishighlyrecommendedthatyouavoiddoingso.Itaddsextra,andoftenunnecessary,complexityandconfusiontoyourcode.Itcanalsomakeiteasiertointroducebugsthataredifficulttofindandfix.Imaginethat,withinafunction,youmodifiedalocalvariablewhenyoumeanttomodifyaglobalvariable.Thatisabug,andifyoureplicateditinmanyotherfunctions,youwillspendprecioustimefindingandfixingthoseerrors.
FUNCTIONSASVALUESJavaScriptisapowerfullanguage,andalotofthatpowercomesfromfunctions.Unlikemanyotherlanguages,functionsarefirst-classcitizensinJavaScript;inotherwords,wecantreatfunctionsjustlikeanyothertypeofvalue.Forexample,let’staketheconvertToCentigrade()functionandassignittoavariable:
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
varmyFunction=convertToCentigrade;
ThiscodeassignstheconvertToCentigrade()functiontothemyFunctionvariable,butlookcloselyattheright-handsideoftheassignment—theopeningandclosingparenthesesaremissingattheendoftheconvertToCentigradeidentifier.Itlooksalotlikeavariable!
Inthisstatement,wearenotexecutingconvertToCentigrade();wearereferringtotheactualfunctionitself.Thismeansthatwenowhavetwowaysofexecutingthesamefunction.WecancallitnormallybyexecutingconvertToCentigrade(),orwecanexecutemyFunction(),likethis:
vardegCent=myFunction(75);//23.88888889
vardegCent2=convertToCentigrade(75);//23.88888889
Thisalsomeanswecanpassafunctiontoanotherfunction’sparameter.Takealookatthefollowingcode:
functiondoSomething(fn){
fn("Hello,World");
}
doSomething(alert);
ThiscodedefinesafunctioncalleddoSomething(),andithasasingleparametercalledfn.Insidethefunction,thefnvariableisusedasafunction;it’sexecutedbyusingthefnidentifierfollowedbyapairofparentheses.ThefinallineofcodeexecutesthedoSomething()functionandpassesthealertfunctionastheparameter.Whenthiscodeexecutes,analertboxdisplaysthemessage"Hello,World".
TRYITOUTPassingFunctions
Let’srewritethetemperatureconverterpagetousemorefunctions.Youcancutandpastesomeofthecodefromch4_example1.html,butthemajorityofthisexamplewillbenewcode.Whenyou’vefinished,saveitasch4_example2.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter4,Example2</title>
</head>
<body>
<script>
functiontoCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
document.write(degFahren+"Fahrenheitis"+
degCent+"Celsius.<br/>");
}
functiontoFahrenheit(degCent){
vardegFahren=9/5*degCent+32;
document.write(degCent+"Celsiusis"+
degFahren+"Fahrenheit.<br/>");
}
functionconvert(converter,temperature){
converter(temperature);
}
convert(toFahrenheit,23);
convert(toCentigrade,75);
</script>
</body>
</html>
Whenyouloadthispageintoyourbrowser,youshouldseetheresultsshowninFigure4.2.
Figure4.2
AtthetopofthescriptblockisthetoCentigrade()function.ItissomewhatsimilartotheconvertToCentigrade()functionfromch4_example1.html;insteadofreturningtheconvertedvalue,itsimplywritestheconversioninformationtothedocument:
functiontoCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
document.write(degFahren+"Fahrenheitis"+
degCent+"Celsius.<br/>");
}
Thenextfunction,toFahrenheit(),issimilartotoCentigrade()exceptthatitconvertsthesuppliedvaluetoFahrenheit.Itthenwritestheconversioninformationtothedocument:
functiontoFahrenheit(degCent){
vardegFahren=9/5*degCent+32;
document.write(degCent+"Celsiusis"+
degFahren+"Fahrenheit.<br/>");
}
Admittedly,youcouldusethesefunctionsasiswithoutanyproblem,butthatwouldn’tresultinaveryinterestingexample.Instead,thethirdfunction,convert(),willbeusedtoexecutetoCentigrade()andtoFahrenheit():
functionconvert(converter,temperature){
returnconverter(temperature);
}
Thisfunctiontakesthefirstparameter,converter,andusesitasafunction.Thesecondparameter,temperature,isthenpassedtoconverter()toperformtheconversionandwritetheresultstothedocument.
Thefinaltwolinesofcodeuseconvert()andpassittheappropriateconverterfunctionandtemperaturevalue:
convert(toFahrenheit,23);
convert(toCentigrade,75);
Althoughthisiscertainlyamorecomplexsolutiontoarelativelysimpleproblem,itdemonstratesthefactthatfunctionsarevaluesinJavaScript.Wecanassignthemtovariablesandpassthemtootherfunctions.Thisisanextremelyimportantconcepttounderstand,andyou’llseewhyinChapter10whenyoulearnaboutevents.
SUMMARYInthischapteryouconcludedyourlookatthecoreoftheJavaScriptlanguageanditssyntax.Everythingfromnowonbuildsonthesefoundations,andwiththelessinterestingsyntaxunderyourbelt,youcanmoveontomoreinterestingthingsintheremainderofthebook.
Thechapterlookedatthefollowing:
Functionsarereusablebitsofcode.JavaScripthasalotofbuilt-infunctionsthatprovideprogrammersservices,suchasconvertingastringtoanumber.However,JavaScriptalsoenablesyoutodefineanduseyourownfunctionsusingthefunctionkeyword.Functionscanhavezeroormoreparameterspassedtothemandcanreturnavalueifyousowish.
Variablescopeandlifetime:Variablesdeclaredoutsideafunctionareavailableglobally—thatis,anywhereinthepage.Anyvariablesdefinedinsideafunctionareprivatetothatfunctionandcan’tbeaccessedoutsideofit.Variableshavealifetime,thelengthofwhichdependsonwherethevariablewasdeclared.Ifit’saglobalvariable,itslifetimeisthatofthepage—whilethepageisloadedinthebrowser,thevariableremainsalive.Forvariablesdefinedinafunction,thelifetimeislimitedtotheexecutionofthatfunction.Whenthefunctionisfinishedexecuting,thevariablesdie,andtheirvaluesarelost.Ifthefunctioniscalledagainlaterinthecode,thevariableswillbeempty.
Identifierlookup:Whenyouuseavariableorfunction,theJavaScriptenginegoesthroughtheidentifierlookupprocesstofindthevalueassociatedwiththeidentifier.
Functionsarefirst-classcitizensinJavaScript.Youcanassignfunctionstovariablesandpassthemtootherfunctions.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. ChangethecodeofQuestion2fromChapter3sothatit’safunctionthattakesasparametersthetimestablerequiredandthevaluesatwhichitshouldstartandend.Forexample,youmighttrythe4timestabledisplayedstartingwith4*4andendingat4*9.
2. ModifythecodeofQuestion1torequestthetimestabletobedisplayedfromtheuser;thecodeshouldcontinuetorequestanddisplaytimestablesuntiltheuserenters-1.Additionally,doachecktomakesurethattheuserisenteringavalidnumber;ifthenumberisnotvalid,asktheusertore-enterit.
5JavaScript—AnObject-BasedLanguageWHATYOUWILLLEARNINTHISCHAPTER:
UsingJavaScript’sbuilt-inobjectstoworkwithcomplexdata
Creatingcustomobjectstorepresentcomplexideasanddata
Definingcustomreferencetypes
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Inthischapter,youlookataconceptthatiscentraltoJavaScript,namelyobjects.Butwhatareobjects,andwhyaretheyuseful?
First,wehavetobreakittoyou:Youhavebeenusingobjectsthroughoutthisbook(forexample,anarrayisanobject).JavaScriptisanobject-basedlanguage,andthereforemostofwhatyoudoinvolvesmanipulatingobjects.You’llseethatwhenyoumakefulluseoftheseobjects,therangeofthingsyoucandowithJavaScriptexpandsimmensely.
We’llstartthischapterbytakingalookattheideaofwhatobjectsareandwhytheyareimportant.We’llmoveontowhatkindsofobjectsareusedinJavaScript,howtocreatethemandusethem,andhowtheysimplifymanyprogrammingtasksforyou.Finally,you’llseeinmoredetailsomeofthemostusefulobjectsthatJavaScriptprovidesandhowtousetheseinpracticalsituations.
NotonlydoestheJavaScriptlanguageconsistofanumberofthesethingscalledobjects(whicharealsocallednativeJavaScriptobjects),butalsothebrowseritselfismodeledasacollectionofobjectsavailableforyouruse.YoulearnabouttheseobjectsinparticularinChapter8.
OBJECT-BASEDPROGRAMMINGObject-basedprogrammingisaslightlyscarierwayofsaying“programmingusingobjects.”Butwhataretheseobjectsthatyouwillbeprogrammingwith?Wherearetheyandhowandwhywouldyouwanttoprogramwiththem?Inthissection,youlookattheanswerstothesequestions,bothingeneralprogrammingtermsandmorespecificallywithinJavaScript.
WhatAreObjects?Tostarttheintroductiontoobjects,let’sthinkaboutwhatismeantbyanobjectinthe“realworld”outsidecomputing.Theworldiscomposedofthings,orobjects,suchastables,chairs,andcars(tonamejustafew!).Let’stakeacarasanexample,toexplorewhatanobjectreallyis.
Howwouldyoudefinethecar?Youmightsayit’sabluecarwithfour-wheeldrive.Youmightspecifythespeedatwhichit’straveling.Whenyoudothis,youarespecifyingpropertiesoftheobject.Forexample,thecarhasacolorproperty,whichinthisinstancehasthevalueblue.
Howdoyouusethecar?Youturntheignitionkey,pressthegaspedal,beepthehorn,changethegear(thatis,choosebetween1,2,3,4,andreverseonamanualcar,ordriveandreverseonanautomatic),andsoon.Whenyoudothis,youareusingmethodsoftheobject.
Youcanthinkofmethodsasbeingabitlikefunctions.Sometimes,youmayneedtousesomeinformationwiththemethod,orpassitaparameter,togetittowork.Forexample,whenyouusethechanging-gearsmethod,youneedtosaywhichgearyouwanttochangeto.Othermethodsmaypassinformationbacktotheowner.Forexample,thedipstickmethodwilltelltheownerhowmuchoilisleftinthecar.
Sometimesusingoneormoreofthemethodsmaychangeoneormoreoftheobject’sproperties.Forexample,usingtheacceleratormethodwillprobablychangethecar’sspeedproperty.Otherpropertiescan’tbechanged:forexample,thebody-shapepropertyofthecar(unlessyouhitabrickwallwiththespeedpropertyat100milesperhour!).
Youcouldsaythatthecarisdefinedbyitscollectionofmethodsandproperties.Inobject-basedprogramming,theideaistomodelreal-worldsituationsbyobjects,whicharedefinedbytheirmethodsandproperties.
ObjectsinJavaScriptYoushouldnowhaveabasicideaofwhatanobjectis—a“thing”withmethodsandproperties.ButhowdoyouusethisconceptinJavaScript?
Inthepreviouschaptersyouhave(forthemostpart)beendealingwithprimitivedata(thatis,you’vebeenworkingwithactualdata).Thistypeofdataisnottoocomplexandisfairlyeasytodealwith.However,notallinformationisassimpleasprimitivedata.Let’s
lookatanexampletoclarifythingsalittle.
Supposeyouhadwrittenawebapplicationthatdisplayedtimetableinformationforbusesortrains.Oncetheuserhasselectedajourney,youmightwanttolethimknowhowlongthatjourneywilltake.Todothat,youneedtosubtractthearrivaltimefromthedeparturetime.
However,that’snotquiteassimpleasitmayappearatfirstglance.Forexample,consideradeparturetimeof14:53(for2:53p.m.)andanarrivaltimeof15:10(for3:10p.m.).IfyoutellJavaScripttoevaluatetheexpression15.10–14.53,yougettheresult0.57,whichis57minutes.However,youknowthattherealdifferenceintimeis17minutes.Usingthenormalmathematicaloperatorsontimesdoesn’twork!
Whatwouldyouneedtodotocalculatethedifferencebetweenthesetwotimes?Youwouldfirstneedtoseparatethehoursfromtheminutesineachtime.Then,togetthedifferenceinminutesbetweenthetwotimes,youwouldneedtocheckwhethertheminutesofthearrivaltimeweregreaterthantheminutesofthedeparture.Ifso,youcouldsimplysubtractthedeparturetimeminutesfromthearrivaltimeminutes.Ifnot,you’dneedtoadd60tothearrivaltimeminutesandsubtractonefromthearrivaltimehourstocompensate,beforetakingthedeparturetimeminutesfromthearrivaltimeminutes.You’dthenneedtosubtractthedeparturetimehoursfromthearrivaltimehours,beforeputtingtheminutesandhoursthatyouhavearrivedatbacktogether.
Thiswouldworkokaysolongasthetwotimeswereinthesameday.Itwouldn’twork,forexample,withthetimes23:45and04:32.
Thiswayofworkingoutthetimedifferenceobviouslyhasitsproblems,butitalsoseemsverycomplex.Isthereaneasierwaytodealwithmorecomplexdatasuchastimesanddates?
Thisiswhereobjectscomein.YoucandefineyourdepartureandarrivaltimesasDateobjects.BecausetheyareDateobjects,theycomewithavarietyofpropertiesandmethodsthatyoucanusewhenyouneedtomanipulateorcalculatetimes.Forexample,youcanusethegetTime()methodtogetthenumberofmillisecondsbetweenthetimeintheDateobjectandJanuary1,1970,00:00:00.Onceyouhavethesemillisecondvaluesforthearrivalanddeparturetimes,youcansimplysubtractonefromtheotherandstoretheresultinanotherDateobject.Toretrievethehoursandminutesofthistime,yousimplyusethegetHours()andgetMinutes()methodsoftheDateobject.Youseemoreexamplesofthislaterinthechapter.
TheDateobjectisnottheonlytypeofobjectthatJavaScripthastooffer.AnotherobjecttypewasintroducedinChapter2,buttokeepthingssimple,wedidn’ttellyouwhatitwasatthetime:theArrayobject.Recallthatanarrayisawayofholdinganumberofpiecesofdataatthesametime.
Arrayobjectshaveapropertycalledlengththattellsyouhowmanypiecesofdata,orratherhowmanyelements,thearrayholds.Theyalsohaveanumberofmethods.Oneexampleisthesort()method,whichyoucanusetosorttheelementswithinthearrayintoalphabeticalorder.
YoushouldnowhaveanideawhyobjectsareusefulinJavaScript.YouhaveseentheDate
andArrayobjects,butJavaScriptmakesavailablemanyothertypesofobjectssothatyoucanachievemorewithyourcode.TheseincludetheMathandStringobjects,whichwetalkmoreaboutlaterinthechapter.
UsingJavaScriptObjectsNowthatyouhaveseenthewhyofJavaScriptobjects,youneedtolookatthewhatandthehow.
EachofJavaScript’sobjectshasacollectionofrelatedpropertiesandmethodsthatyoucanusetomanipulateacertainkindofdata.Forexample,theArrayobjectconsistsofmethodstomanipulatearraysandpropertiestofindoutinformationfromthem.Inmostcases,tomakeuseofthesemethodsandproperties,youneedtodefineyourdataasoneoftheseobjects.Inotherwords,youneedtocreateanobject.
Inthissection,youlookathowtogoaboutcreatinganobjectand,havingdonethat,howyouuseitspropertiesandmethods.
CreatinganObjectTocreatemanytypesofobjects,youusethenewoperator.ThefollowingstatementcreatesaDateobject:
varmyDate=newDate();
Thefirsthalfofthestatementisfamiliartoyou.YouusethevarkeywordtodefineavariablecalledmyDate.Thisvariableisinitialized,usingtheequalssignassignmentoperator(=),totheright-handsideofthestatement.
Theright-handsideofthestatementconsistsoftwoparts.Firstyouhavetheoperatornew.ThistellsJavaScriptthatyouwanttocreateanewobject.NextyouhaveDate().ThisistheconstructorforaDateobject.It’safunctionthattellsJavaScriptwhattypeofobjectyouwanttocreate.Mostobjectshaveconstructorslikethis.Forexample,theArrayobjecthastheArray()constructor(butremember,wetypicallydon’tuseitinfavoroftheliteral[]).TheonlyexceptionyouseeinthisbookistheMathobject,andthisisexplainedinalaterpartofthechapter.
Becauseaconstructorisafunction,youcanpassparameterstotheconstructortoadddatatoyourobject.Forexample,thefollowingcodecreatesaDateobjectcontainingthedate1January2014:
varmyDate=newDate("1Jan2014");
Howobjectdataisstoredinvariablesdiffersfromhowprimitivedata,suchastextandnumbers,isstored.(PrimitivedataisthemostbasicdatapossibleinJavaScript.)Withprimitivedata,thevariableholdsthedata’sactualvalue.Forexample:
varmyNumber=23;
ThiscodemeansthatthevariablemyNumberholdsthedata23.However,variablesassignedtoobjectsdon’tholdtheactualdata,butratherareferencetothememoryaddress
wherethedatacanbefound.Thisdoesn’tmeanyoucangetholdofthememoryaddress—thisissomethingonlyJavaScripthasdetailsofandkeepstoitselfinthebackground.Allyouneedtorememberisthatwhenyousaythatavariablereferencesanobject,youmeanitreferencesamemoryaddress.Thisisshowninthefollowingexample:
varmyArrayRef=[0,1,2];
varmySecondArrayRef=myArrayRef;
myArrayRef[0]=100;
alert(mySecondArrayRef[0]);
FirstyousetthemyArrayRefvariabletoreferencethenewarrayobject,andthenyousetmySecondArrayReftothesamereference—forexample,nowmySecondArrayRefissettoreferencethesamearrayobject.Sowhenyousetthefirstelementofthearrayto100,asshownhere:
myArrayRef[0]=100;
anddisplaythecontentsofthefirstelementofthearrayreferencedinmySecondArrayRefasfollows:
alert(mySecondArrayRef[0]);
you’llseeithasalsomagicallychangedto100!However,asyounowknow,it’snotmagic;it’sbecausebothvariablesreferencethesamearrayobject—whenitcomestoobjects,it’sareferencetotheobjectandnottheobjectitselfthatisstoredinavariable.Whenyoudidtheassignment,itdidn’tmakeacopyofthearrayobject,itsimplycopiedthereference.Contrastthatwiththefollowing:
varmyVariable="ABC";
varmySecondVariable=myVariable;
myVariable="DEF";
alert(mySecondVariable);
Inthiscaseyou’redealingwithastring,whichisaprimitivedatatype,asarenumbers.Thistimetheactualvaluesarestoredinthevariable,sowhenyoudothis:
varmySecondVariable=myVariable;
mySecondVariablegetsitsownseparatecopyofthedatainmyVariable.SothealertattheendwillstillshowmySecondVariableasholding"ABC".
Tosummarizethissection,youcreateJavaScriptobjectsusingthefollowingbasicsyntax:
varmyVariable=newConstructorName(optionalparameters);
UsinganObject’sPropertiesAccessingthevaluescontainedinanobject’spropertiesisverysimple.Youwritethenameofthevariablecontaining(orreferencing)yourobject,followedbyadot,andthenthenameoftheobject’sproperty.
Forexample,ifyoudefinedanArrayobjectcontainedinthevariablemyArray,youcouldaccessitslengthpropertylikethis:
myArray.length
Butwhatcanyoudowiththispropertynowthatyouhaveit?Youcanuseitasyouwouldanyotherpieceofdataandstoreitinavariable:
varmyVariable=myArray.length;
Oryoucanshowittotheuser:
alert(myArray.length);
Insomecases,youcanevenchangethevalueoftheproperty,likethis:
myArray.length=12;
However,unlikevariables,somepropertiesareread-only—youcangetinformationfromthem,butyoucan’tchangeinformationinsidethem.
CallinganObject’sMethodsMethodsareverymuchlikefunctionsinthattheycanbeusedtoperformusefultasks,suchasgettingthehoursfromaparticulardateorgeneratingarandomnumber.Againlikefunctions,somemethodsreturnavalue,suchasaDateobject’sgetHours()method,whereasothersperformatask,butreturnnodata,suchasanArrayobject’ssort()method.
Usingthemethodsofanobjectisverysimilartousingproperties,inthatyouputtheobject’svariablenamefirst,thenadot,andthenthenameofthemethod.Forexample,tosorttheelementsofanArrayinthevariablemyArray,youcanusethefollowingcode:
myArray.sort();
Justaswithfunctions,youcanpassparameterstosomemethodsbyplacingtheparametersbetweentheparenthesesfollowingthemethod’sname.However,whetherornotamethodtakesparameters,youmuststillputparenthesesafterthemethod’sname,justasyoudidwithfunctions.Asageneralrule,anywhereyoucanuseafunction,youcanuseamethodofanobject.
PrimitivesandObjectsYoushouldnowhaveagoodideaaboutthedifferencebetweenprimitivedata,suchasnumbersandstrings,andobjectdata,suchasDatesandArrays.However,aswasmentionedearlier,thereisalsoaStringobject.Wheredoesthisfitin?
Infact,thereareString,Number,andBooleanobjectscorrespondingtothestring,number,andbooleanprimitivedatatypes.Forexample,tocreateaStringobjectcontainingthetext"I'maStringobject"youcanusethefollowingcode:
varmyString=newString("I'maStringobject");
StringobjectshavethelengthpropertyjustasArrayobjectsdo.ThisreturnsthenumberofcharactersintheStringobject.Forexample,
varlengthOfString=myString.length;
wouldstorethevalue19inthevariablelengthOfString(rememberthatspacesarereferredtoascharacters,too).
ButwhatifyouhaddeclaredaprimitivestringcalledmySecondStringholdingthetext"I'maprimitivestring"likethis:
varmySecondString="I'maprimitivestring";
andwantedtoknowhowmanycharacterscouldbefoundinthisprimitivestring?
ThisiswhereJavaScripthelpsyouout.RecallfrompreviouschaptersthatJavaScriptcanhandletheconversionofonedatatypetoanotherautomatically.Forexample,ifyoutriedtoaddastringprimitivetoanumberprimitive,likethis:
theResult="23"+23;
JavaScriptwouldassumethatyouwanttotreatthenumberasastringandconcatenatethetwotogether,thenumberbeingconvertedtotextautomatically.ThevariabletheResultwouldcontain"2323"—theconcatenationof23and23,andnotthesumof23and23,whichwouldbe46.
Thesameappliestoobjects.Ifyoudeclareaprimitivestringandthentreatitasanobject,suchasbytryingtoaccessoneofitsmethodsorproperties,JavaScriptwillknowthattheoperationyou’retryingtodowon’twork.Theoperationwillonlyworkwithanobject;forexample,itwouldbevalidwithaStringobject.Inthiscase,JavaScriptconvertstheplaintextstringintoatemporaryStringobject,justforthatoperation,anddestroystheobjectwhenit’sfinishedtheoperation.
So,foryourprimitivestringmySecondString,youcanusethelengthpropertyoftheStringobjecttofindoutthenumberofcharactersitcontains.Forexample:
varlengthOfSecondString=mySecondString.length;
Thiswouldstorethedata22inthevariablelengthOfSecondString.
ThesameideasexpressedherearealsotruefornumberandbooleanprimitivesandtheircorrespondingNumberandBooleanobjects.However,theseobjectsarenotusedveryoften,sowewillnotbediscussingthemfurtherinthisbook.
JAVASCRIPT’SNATIVEOBJECTTYPESSofar,youhavejustbeenlookingatwhatobjectsare,howtocreatethem,andhowtousethem.NowtakealookatsomeofthemoreusefulobjectsthatarenativetoJavaScript—thatis,thosethatarebuiltintotheJavaScriptlanguage.
Youwon’tbelookingatallofthenativeJavaScriptobjects,justsomeofthemorecommonlyusedones,namelytheStringobject,theMathobject,theArrayobject,andtheDateobject.
StringObjectsLikemostobjects,Stringobjectsneedtobecreatedbeforetheycanbeused.TocreateaStringobject,youcanwritethis:
varstring1=newString("Hello");
varstring2=newString(123);
varstring3=newString(123.456);
However,asyouhaveseen,youcanalsodeclareastringprimitiveanduseitasifitwereaStringobject,lettingJavaScriptdotheconversiontoanobjectforyoubehindthescenes.Forexample:
varstring1="Hello";
Usingthistechniqueispreferable.TheadvantagestodoingitthiswayarethatthereisnoneedtocreateaStringobjectitself,andyouavoidthetroubleswithcomparingstringobjects.Whenyoutrytocomparestringobjectswithprimitivestringvalues,theactualvaluesarecompared,butwithStringobjects,theobjectreferencesarecompared.
TheStringobjecthasavastnumberofmethodsandproperties.Inthissection,youlookonlyatsomeofthelesscomplexandmorecommonlyusedmethods.However,inChapter6youlookatsomeofthetrickierbutverypowerfulmethodsassociatedwithstringsandtheregularexpressionobject(RegExp).Regularexpressionsprovideaverypowerfulmeansofsearchingstringsforpatternsofcharacters.Forexample,ifyouwanttofind"Paul"whereitexistsasawholewordinthestring"Pauline,Paul,Paula",youneedtouseregularexpressions.However,theycanbealittletrickytouse,sowewon’tdiscussthemfurtherinthischapter—wewanttosavesomefunforlater!
WithmostoftheStringobject’smethods,ithelpstorememberthatastringisjustaseriesofindividualcharactersandthat,aswitharrays,eachcharacterhasaposition,orindex.Alsoaswitharrays,thefirstposition,orindex,islabeled0andnot1.So,forexample,thestring"HelloWorld"hasthecharacterpositionsshowninthefollowingtable:
CHARACTERINDEX 0 1 2 3 4 5 6 7 8 9 10Character H e l l o W o r l d
ThelengthPropertyThelengthpropertysimplyreturnsthenumberofcharactersinthestring.Forexample,
varmyName="Jeremy";
document.write(myName.length);
willwritethelengthofthestring"Jeremy"(thatis,6)tothepage.
FindingaStringInsideAnotherString—TheindexOf()andlastIndexOf()MethodsThemethodsindexOf()andlastIndexOf()areusedforsearchingfortheoccurrenceofonestringinsideanother.Astringcontainedinsideanotherisusuallytermedasubstring.Theyareusefulwhenyouhaveastringofinformationbutonlywantasmallpartofit.Forexample,inthetriviaquiz,whensomeoneentersatextanswer,youwanttocheckifcertainkeywordsarepresentwithinthestring.
BothindexOf()andlastIndexOf()taketwoparameters:
Thestringyouwanttofind
Thecharacterpositionyouwanttostartsearchingfrom(optional)
Characterpositionsstartat0.Ifyoudon’tincludethesecondparameter,searchingstartsfromthebeginningofthestring.
ThereturnvalueofindexOf()andlastIndexOf()isthecharacterpositioninthestringatwhichthesubstringwasfound.Again,it’szero-based,soifthesubstringisfoundatthestartofthestring,then0isreturned.Ifthereisnomatch,thevalue-1isreturned.
Forexample,tosearchforthesubstring"Jeremy"inthestring"Hellojeremy.HowareyouJeremy",youcanusethefollowingcode:
varmyString="Hellojeremy.HowareyouJeremy";
varfoundAtPosition=myString.indexOf("Jeremy");
alert(foundAtPosition);
Thiscodeshouldresultinamessageboxcontainingthenumber26,whichisthecharacterpositionof"Jeremy".Youmightbewonderingwhyit’s26,whichclearlyreferstothesecond"Jeremy"inthestring,ratherthan6forthefirst"jeremy".
Thisisduetocasesensitivity.JavaScripttakescasesensitivityveryseriously,bothinitssyntaxandwhenmakingcomparisons.IfyoutypeIndexOf()insteadofindexOf(),JavaScriptwillcomplain.Similarly,"jeremy"isnotthesameas"Jeremy".Rememberthatmistakeswithcaseareverycommonandsoeasytomake,evenforexperts,andit’sbesttobeveryawareofcasewhenprogramming.
You’veseenindexOf()inaction,buthowdoeslastIndexOf()differ?Well,whereasindexOf()startssearchingfromthebeginningofthestring,orthepositionyouspecifiedinthesecondparameter,andworkstowardtheend,lastIndexOf()startsattheendofthestring,orthepositionyouspecified,andworkstowardthebeginningofthestring.Let’smodifythepreviousexampletothefollowingcode:
varmyString="HelloJeremy.HowareyouJeremy";
varfoundAtPosition=myString.indexOf("Jeremy");
alert(foundAtPosition);
foundAtPosition=myString.lastIndexOf("Jeremy");
alert(foundAtPosition);
First,noticethestringvalueassignedtomyString;bothinstancesof"Jeremy"nowbeginwithacapitalletter.Thefirstalertboxdisplaystheresultof6becausethatisthepositionofthefirstoccurrenceof"Jeremy".Thesecondalertboxdisplays26becauselastIndexOf()startssearchingattheendofthestring,andthepositionofthefirstoccurrenceof"Jeremy"fromtheendofthestringis26.
TRYITOUTCountingOccurrencesofSubstringsInthisexample,youlookathowtousethe“startcharacterposition”parameterofindexOf().HereyouwillcounthowmanytimesthewordWroxappearsinthestring:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example1</title>
</head>
<body>
<script>
varmyString="WelcometoWroxbooks."+
"TheWroxwebsiteiswww.wrox.com."+
"VisittheWroxwebsitetoday.Thanksforbuying
Wrox";
varfoundAtPosition=0;
varwroxCount=0;
while(foundAtPosition!=-1){
foundAtPosition=myString.indexOf("Wrox",
foundAtPosition);
if(foundAtPosition!=-1){
wroxCount++;
foundAtPosition++;
}
}
document.write("Thereare"+wroxCount+"occurrencesofthe
wordWrox");
</script>
</body>
</html>
Savethisexampleasch5_example1.html.Whenyouloadthepageintoyourbrowser,youshouldseethefollowingsentence:Thereare4occurrencesofthewordWrox.
Atthetopofthescriptblock,youbuiltupastringinsidethevariablemyString,whichyouthenwanttosearchfortheoccurrenceofthewordWrox.Youalsodefinetwovariables:wroxCountwillcontainthenumberoftimesWroxisfoundinthestring,andfoundAtPositionwillcontainthepositioninthestringofthecurrentoccurrenceofthesubstringWrox.
Youthenusedawhileloop,whichcontinuesloopingallthewhileyouarefindingthewordWroxinthestring—thatis,whilethevariablefoundAtPositionisnotequalto-1.Insidethewhileloop,youhavethisline:
foundAtPosition=myString.indexOf("Wrox",foundAtPosition);
HereyousearchforthenextoccurrenceofthesubstringWroxinthestringmyString.Howdoyoumakesurethatyougetthenextoccurrence?YouusethevariablefoundAtPositiontogiveyouthestartingpositionofyoursearch,becausethiscontainstheindexaftertheindexpositionofthelastoccurrenceofthesubstringWrox.YouassignthevariablefoundAtPositiontotheresultofyoursearch,theindexpositionofthenextoccurrenceofthesubstringWrox.
EachtimeWroxisfound(thatis,eachtimefoundAtPositionisnot-1)youincreasethevariablewroxCount,whichcountshowmanytimesyouhavefoundthesubstring,andyouincreasefoundAtPositionsothatyoucontinuethesearchatthenextpositioninthestring:
if(foundAtPosition!=-1){
wroxCount++;
foundAtPosition++;
}
Finally,youdocument.write()thevalueofthevariablewroxCounttothepage.
Chapter3talkedaboutthedangerofinfiniteloops,andyoucanseethatthereisadangerofonehere.IffoundAtPosition++wereremoved,you’dkeepsearchingfromthesamestartingpointandnevermovetofindthenextoccurrenceofthewordWrox.
TheindexOf()andlastIndexOf()methodsaremoreusefulwhencoupledwiththesubstr()andsubstring()methods,whichyoulookatinthenextsection.Usingacombinationofthesemethodsenablesyoutocutsubstringsoutofastring.
CopyingPartofaString—Thesubstr()andsubstring()MethodsIfyouwantedtocutoutpartofastringandassignthatcut-outparttoanothervariableoruseitinanexpression,youwouldusethesubstr()andsubstring()methods.Bothmethodsprovidethesameendresult—thatis,apartofastring—buttheydifferintheparameterstheyrequire.
Themethodsubstring()acceptstwoparameters:thecharacterstartpositionandthepositionafterthelastcharacterdesiredinthesubstring.Thesecondparameterisoptional;
ifyoudon’tincludeit,allcharactersfromthestartpositiontotheendofthestringareincluded.
Forexample,ifyourstringis"JavaScript"andyouwantjustthetext"Java",youcouldcallthemethodlikeso:
varmyString="JavaScript";
varmySubString=myString.substring(0,4);
alert(mySubString);
Thecharacterpositionsforthestring“JavaScript”are:
CHARACTERPOSITION 0 1 2 3 4 5 6 7 8 9Character J a v a S c r i p t
Likesubstring(),themethodsubstr()againtakestwoparameters,thefirstbeingthestartpositionofthefirstcharacteryouwantincludedinyoursubstring.However,thistimethesecondparameterspecifiesthelengthofthestringofcharactersthatyouwanttocutoutofthelongerstring.Forexample,youcouldrewritetheprecedingcodelikethis:
varmyString="JavaScript";
varmySubString=myString.substr(0,4);
alert(mySubString);
Aswiththesubstring()method,thesecondparameterisoptional.Ifyoudon’tincludeit,allthecharactersfromthestartpositiononwardwillbeincluded.
NOTEThesubstring()methodwasintroducedlongbeforesubstr().Mostofthetime,youwillusethesubstr()method.
Let’slookattheuseofthesubstr()andlastIndexOf()methodstogether.Laterinthebook,youseehowyoucanretrievethefilepathandnameofthecurrentlyloadedwebpage.However,thereisnowayofretrievingthefilenamealone.Soif,forexample,yourfileishttp://mywebsite/temp/myfile.html,youmayneedtoextractthemyfile.htmlpart.Thisiswheresubstr()andlastIndexOf()areuseful:
varfileName=window.location.href;
fileName=fileName.substr(fileName.lastIndexOf("/")+1);
document.write("Thefilenameofthispageis"+fileName);
ThefirstlinesetsthevariablefileNametothecurrentfilepathandname,suchas/mywebsite/temp/myfile.html.Don’tworryaboutunderstandingthislinerightnow;you’llseeitlater.
Thesecondlineiswheretheinterestingactionis.YoucanseethatthiscodeusesthereturnvalueofthelastIndexOf()methodasaparameterforanothermethod,somethingthat’sperfectlycorrectandveryuseful.ThegoalinusingfileName.lastIndexOf("/")istofindthepositionofthefinalforwardslash(/),whichwillbethelastcharacterbeforethenameofthefile.Youaddonetothisvalue,becauseyoudon’twanttoincludethatcharacter,andthenpassthisnewvaluetothesubstr()method.There’snosecond
parameterhere(thelength),becauseyoudon’tknowit.Asaresult,substr()willreturnallthecharactersrighttotheendofthestring,whichiswhatyouwant.
NOTEThisexampleretrievesthenameofthepageonthelocalmachine,becauseyou’renotaccessingthepagefromawebserver.However,don’tletthismisleadyouintothinkingthataccessingfilesonalocalharddrivefromawebpageissomethingyou’llbeabletodowithJavaScriptalone.Toprotectusersfrommalicioushackers,JavaScript’saccesstotheuser’ssystem,suchasaccesstofiles,isverylimited.Youlearnmoreaboutthislaterinthebook.
ConvertingCase—ThetoLowerCase()andtoUpperCase()MethodsIfyouwanttochangethecaseofastring(forexample,toremovecasesensitivitywhencomparingstrings),youneedthetoLowerCase()andtoUpperCase()methods.It’snothardtoguesswhatthesetwomethodsdo.BothofthemreturnastringthatisthevalueofthestringintheStringobject,butwithitscaseconvertedtoeitherupperorlowerdependingonthemethodinvoked.Anynon-alphabeticalcharactersremainunchangedbythesefunctions.
Inthefollowingexample,youcanseethatbychangingthecaseofbothstringsyoucancomparethemwithoutcasesensitivitybeinganissue:
varmyString="IDon'tCareAboutCase";
if(myString.toLowerCase()=="idon'tcareaboutcase"){
alert("Whocaresaboutcase?");
}
EventhoughtoLowerCase()andtoUpperCase()don’ttakeanyparameters,youmustremembertoputthetwoemptyparentheses—thatis,()—attheend,ifyouwanttocallamethod.
SelectingaSingleCharacterfromaString—ThecharAt()andcharCodeAt()MethodsIfyouwanttofindoutinformationaboutasinglecharacterwithinastring,youneedthecharAt()andcharCodeAt()methods.Thesemethodscanbeveryusefulforcheckingthevalidityofuserinput,somethingyouseemoreofinChapter11whenyoulookatHTMLforms.
ThecharAt()methodacceptsoneparameter:theindexpositionofthecharacteryouwantinthestring.Itthenreturnsthatcharacter.charAt()treatsthepositionsofthestringcharactersasstartingat0,sothefirstcharacterisatindex0,thesecondatindex1,andsoon.
Forexample,tofindthelastcharacterinastring,youcouldusethiscode:
varmyString=prompt("Entersometext","HelloWorld!");
vartheLastChar=myString.charAt(myString.length-1);
document.write("Thelastcharacteris"+theLastChar);
Inthefirstline,youprompttheuserforastring,withthedefaultof"HelloWorld!",andstorethisstringinthevariablemyString.
Inthenextline,youusethecharAt()methodtoretrievethelastcharacterinthestring.Youusetheindexpositionof(myString.length-1).Why?Let’stakethestring"HelloWorld!"asanexample.Thelengthofthisstringis12,butthelastcharacterpositionis11becausetheindexingstartsat0.Therefore,youneedtosubtractonefromthelengthofthestringtogetthelastcharacter’sposition.
Inthefinalline,youwritethelastcharacterinthestringtothepage.
ThecharCodeAt()methodissimilarinusetothecharAt()method,butinsteadofreturningthecharacteritself,itreturnsanumberthatrepresentsthedecimalcharactercodeforthatcharacterintheUnicodecharacterset.Recallthatcomputersonlyunderstandnumbers—tothecomputer,allyourstringsarejustnumericdata.Whenyourequesttextratherthannumbers,thecomputerdoesaconversionbasedonitsinternalunderstandingofeachnumberandprovidestherespectivecharacter.
Forexample,tofindthecharactercodeofthefirstcharacterinastring,youcouldwritethis:
varmyString=prompt("Entersometext","HelloWorld!");
vartheFirstCharCode=myString.charCodeAt(0);
document.write("Thefirstcharactercodeis"+theFirstCharCode);
Thiswillgetthecharactercodeforthecharacteratindexposition0inthestringgivenbytheuser,andwriteitouttothepage.
Charactercodesgoinorder,so,forexample,theletterAhasthecode65,B66,andsoon.Lowercaselettersstartat97(ais97,bis98,andsoon).Digitsgofrom48(forthenumber0)to57(forthenumber9).Youcanusethisinformationforvariouspurposes,asyouseeinthenextexample.
TRYITOUTCheckingaCharacter’sCaseThisisanexamplethatdetectsthetypeofthecharacteratthestartofagivenstring—thatis,whetherthecharacterisuppercase,lowercase,numeric,orother:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example2</title>
</head>
<body>
<script>
functioncheckCharType(charToCheck){
varreturnValue="O";
varcharCode=charToCheck.charCodeAt(0);
if(charCode>="A".charCodeAt(0)&&charCode<=
"Z".charCodeAt(0)){
returnValue="U";
}elseif(charCode>="a".charCodeAt(0)&&
charCode<="z".charCodeAt(0)){
returnValue="L";
}elseif(charCode>="0".charCodeAt(0)&&
charCode<="9".charCodeAt(0)){
returnValue="N";
}
returnreturnValue;
}
varmyString=prompt("Entersometext","HelloWorld!");
switch(checkCharType(myString)){
case"U":
document.write("Firstcharacterwasuppercase");
break;
case"L":
document.write("Firstcharacterwaslowercase");
break;
case"N":
document.write("Firstcharacterwasanumber");
break;
default:
document.write("Firstcharacterwasnotacharacteror
anumber");
}
</script>
</body>
</html>
Typethecodeandsaveitasch5_example2.html.Whenyouloadthepageintoyourbrowser,youwillbepromptedforastring.Amessagewillthenbewrittentothepageinformingyouofthetypeofthefirstcharacterthatyouentered—whetheritisuppercase,lowercase,anumber,orsomethingelse,suchasapunctuationmark.
Tostartwith,youdefineafunctioncheckCharType().YoustartthisfunctionbydeclaringthevariablereturnValueandinitializingittothecharacter"O"toindicateit’ssomeothercharacterthanalowercaseletter,uppercaseletter,ornumericalcharacter:
functioncheckCharType(charToCheck){
varreturnValue="O";
Youusethisvariableasthevaluetobereturnedattheendofthefunction,indicatingthetypeofcharacter.ItwilltakethevaluesUforuppercase,Lforlowercase,Nfornumber,andOforother.
ThenextlineinthefunctionusesthecharCodeAt()methodtogetthecharactercodeofthefirstcharacterinthestringstoredincharToCheck,whichisthefunction’sonlyparameter.ThecharactercodeisstoredinthevariablecharCode:
varcharCode=charToCheck.charCodeAt(0);
Inthefollowinglines,youhaveaseriesofifstatements,whichcheckwithinwhatrangeofvaluesthecharactercodefalls.YouknowthatifitfallsbetweenthecharactercodesforAandZ,it’suppercase,andsoyouassignthevariablereturnValuethevalueU.Ifthecharactercodefallsbetweenthecharactercodesforaandz,it’slowercase,andsoyouassignthevalueLtothevariablereturnValue.Ifthecharactercodefallsbetweenthecharactercodesfor0and9,it’sanumber,andyouassignthevalueNtothevariablereturnValue.Ifthevaluefallsintononeoftheseranges,thevariableretainsitsinitializationvalueofOforother,andyoudon’thavetodoanything.
if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0))
{
returnValue="U";
}elseif(charCode>="a".charCodeAt(0)&&
charCode<="z".charCodeAt(0)){
returnValue="L";
}elseif(charCode>="0".charCodeAt(0)&&
charCode<="9".charCodeAt(0)){
returnValue="N";
}
Thisprobablyseemsabitweirdatfirst,solet’sseewhatJavaScriptisdoingwithyourcode.Whenyouwrite
"A".charCodeAt(0)
itappearsthatyouaretryingtouseamethodoftheStringobjectonastringliteral,whichisthesameasaprimitivestringinthatit’sjustcharactersandnotanobject.However,JavaScriptrealizeswhatyouaredoinganddoesthenecessaryconversionofliteralcharacter"A"intoatemporaryStringobjectcontaining"A".Then,andonlythen,doesJavaScriptperformthecharCodeAt()methodontheStringobjectithascreatedinthebackground.Whenithasfinished,theStringobjectisdisposedof.Basically,thisisashorthandwayofwritingthefollowing:
varmyChar=newString("A");
myChar.charCodeAt(0);
Ineithercase,thefirst(and,inthisstring,theonly)character’scodeisreturnedtoyou.Forexample,"A".charCodeAt(0)willreturnthenumber65.
Finally,youcometotheendofthefunctionandreturnthereturnValuevariabletowherethefunctionwascalled:
returnreturnValue;
}
YoumightwonderwhyyoubotherusingthevariablereturnValueatall,insteadofjustreturningitsvalue.Forexample,youcouldwritethecodeasfollows:
if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0)){
return"U";
}elseif(charCode>="a".charCodeAt(0)&&
charCode<="z".charCodeAt(0)){
return"L";
}elseif(charCode>="0".charCodeAt(0)&&
charCode<="9".charCodeAt(0)){
return"N";
}
return"O";
Thiswouldworkfine,sowhynotdoitthisway?Thedisadvantageofthiswayisthatit’sdifficulttofollowtheflowofexecutionofthefunction,whichisnotthatbadinasmallfunctionlikethis,butcangettrickyinbiggerfunctions.Withtheoriginalcodeyoualwaysknowexactlywherethefunctionexecutionstops:Itstopsattheendwiththeonlyreturnstatement.Theversionofthefunctionjustshownfinisheswhenanyofthereturnstatementsisreached,sotherearefourpossibleplaceswherethefunctionmightend.
Thenextchunkofcodechecksthatthefunctionworks.YoufirstusethevariablemyString,initializedto"HelloWorld!"orwhatevertheuserentersintothepromptbox,asyourteststring.
varmyString=prompt("Entersometext","HelloWorld!");
Next,theswitchstatementusesthecheckCharType()functionthatyoudefinedearlierinitscomparisonexpression.Dependingonwhatisreturnedbythefunction,oneofthecasestatementswillexecuteandlettheuserknowwhatthecharactertypewas:
switch(checkCharType(myString)){
case"U":
document.write("Firstcharacterwasuppercase");
break;
case"L":
document.write("Firstcharacterwaslowercase");
break;
case"N":
document.write("Firstcharacterwasanumber");
break;
default:
document.write("Firstcharacterwasnotacharacterora
number");
}
Thatcompletestheexample,butbeforemovingon,it’sworthnotingthatthisexampleisjustthat—anexampleofusingcharCodeAt().Inpractice,itwouldbemucheasiertojustwrite
if(char>="A"&&char<="Z")
ratherthan
if(charCode>="A".charCodeAt(0)&&charCode<="Z".charCodeAt(0))
whichyouhaveusedhere.
ConvertingCharacterCodestoaString—ThefromCharCode()MethodYoucanthinkofthemethodfromCharCode()astheoppositeofcharCodeAt(),inthatyoupassitaseriesofcomma-separatednumbersrepresentingcharactercodes,anditconvertsthemtoasinglestring.
However,thefromCharCode()methodisunusualinthatit’sastaticmethod—youdon’tneedtohavecreatedaStringobjecttouseitwith;it’salwaysavailabletoyou.
Forexample,thefollowinglinesputthestring"ABC"intothevariablemyString:
varmyString=String.fromCharCode(65,66,67);
ThefromCharCode()methodcanbeveryusefulwhenusedwithvariables.Forexample,tobuildupastringconsistingofalltheuppercaselettersofthealphabet,youcouldusethefollowingcode:
varmyString="";
varcharCode;
for(charCode=65;charCode<=90;charCode++){
myString=myString+String.fromCharCode(charCode);
}
document.write(myString);
YouusetheforlooptoselecteachcharacterfromAtoZinturnandconcatenatethistomyString.Notethatalthoughthisisfineasanexample,itismoreefficientandlessmemory-hungrytosimplywritethisinstead:
varmyString="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
RemovingLeadingandTrailingWhitespace—Thetrim()MethodWhenworkingwithuser-provideddata,you’reneverguaranteedthattheusersinputtheirdataexactlyhowyouwantthemto.Therefore,it’salwaysbesttoassumeuserinputisincorrect,andit’syourjobtomakeitcorrect.
Theprocessofscrubbingdataisdependentonthespecificneedsofyourapplication,butyou’llcommonlywanttotrimthewhitespacefromthestartandendofthestring.Forthis,Stringobjectshavethetrim()method.Itreturnsanewstringwithallleadingandtrailingwhitespaceremoved.Forexample:
varname=prompt("Pleaseenteryourname");
name=name.trim();
alert("Hello,"+name);
Thiscodepromptsuserstoentertheirname.Youthentrimtheirinputofwhitespaceandusetheresultingvalueinagreetingthatisdisplayedinanalertbox.So,iftheuserentered"Jim",he’dstillonlysee"Hello,Jim"inthealertboxbecauseyoutrimmedhisinput.
ArrayObjectsYousawhowtocreateandusearraysinChapter2,andthischaptermentionedearlierthattheyareactuallyobjects.
Inadditiontostoringdata,Arrayobjectsprovideanumberofusefulpropertiesandmethodsyoucanusetomanipulatethedatainthearrayandfindoutinformationsuchasthesizeofthearray.
Again,thisisnotanexhaustivelookateverypropertyandmethodofArrayobjects,butratherjustsomeofthemoreusefulones.
FindingOutHowManyElementsAreinanArray—ThelengthPropertyThelengthpropertygivesyouthenumberofelementswithinanarray.Sometimesyouknowexactlyhowlongthearrayis,butinsomesituationsyoumayhavebeenaddingnewelementstoanarraywithnoeasywayofkeepingtrackofhowmanyhavebeenadded.
Youcanusethelengthpropertytofindtheindexofthelastelementinthearray.Thisisillustratedinthefollowingexample:
varnames=[];
names[0]="Paul";
names[1]="Jeremy";
names[11]="Nick";
document.write("Thelastnameis"+names[names.length-1]);
NOTENotethatyouhaveinserteddataintheelementswithindexpositions0,1,and11.Thearrayindexstartsat0,sothelastelementisatindexlength-1,whichis11,ratherthanthevalueofthelengthproperty,whichis12.
AnothersituationinwhichthelengthpropertyprovesusefuliswhereaJavaScriptmethodreturnsanarrayithasbuiltitself.Forexample,inthenextchapter,youseethattheStringobjecthasthesplit()method,whichsplitstextintopiecesandpassesbacktheresultasanArrayobject.BecauseJavaScriptcreatedthearray,thereisnowayforyoutoknow,withoutthelengthproperty,whattheindexisofthelastelementinthearray.
AddingElements—Thepush()MethodYou’llfindthatArrayobjectshavemanyusefulmethods,butyouwillprobablyusethepush()methodmorethananyother.Itspurposeissimple—addelementstothearray—anditletsyoudosowithoutneedingtospecifyanindex,likethis:
varnames=[];
names.push("Jeremy");
names.push("Paul");
Itsusageissimple—simplypassthevalueyouwanttoaddtothearray,andthatvaluewillbepushedtotheendofthearray.Sointhepreviousnamesarray,"Jeremy"and"Paul"are
inindexpositionsof0and1,respectively.
JoiningArrays—Theconcat()MethodIfyouwanttotaketwoseparatearraysandjointhemintoonebigarray,youcanusetheArrayobject’sconcat()method.Theconcat()methodreturnsanewarray,whichisthecombinationofthetwoarrays:theelementsofthefirstarray,thentheelementsofthesecondarray.Todothis,youusethemethodonyourfirstarrayandpassthenameofthesecondarrayasitsparameter.
Forexample,sayyouhavetwoarrays,namesandages,andseparatelytheylooklikethefollowingtables:
namesarrayELEMENTINDEX 0 1 2VALUE Paul Jeremy Nick
agesarrayELEMENTINDEX 0 1 2VALUE 31 30 31
Ifyoucombinethemusingnames.concat(ages),youwillgetanarrayliketheoneinthefollowingtable:
ELEMENTINDEX 0 1 2 3 4 5VALUE Paul Jeremy Nick 31 30 31
Inthefollowingcode,thisisexactlywhatyouaredoing:
varnames=["Paul","Jeremy","Nick"];
varages=[31,30,31];
varconcatArray=names.concat(ages);
It’salsopossibletocombinetwoarraysintoonebutassignthenewarraytothenameoftheexistingfirstarray,usingnames=names.concat(ages).
Ifyouweretouseages.concat(names),whatwouldbethedifference?Well,asyoucanseeinthefollowingtable,thedifferenceisthatnowtheagesarrayelementsarefirst,andtheelementsfromthenamesarrayareconcatenatedontheend:
ELEMENTINDEX 0 1 2 3 4 5VALUE 31 30 31 Paul Jeremy Nick
CopyingPartofanArray—Theslice()MethodWhenyoujustwanttocopyaportionofanarray,youcanusetheslice()method.Usingtheslice()method,youcansliceoutaportionofthearrayandassignittoanewvariablename.Theslice()methodhastwoparameters:
Theindexofthefirstelementyouwantcopied
Theindexoftheelementmarkingtheendoftheportionyouareslicingout(optional)
Justaswithstringcopyingwithsubstring(),thestartpointisincludedinthecopy,buttheendpointisnot.Again,ifyoudon’tincludethesecondparameter,allelementsfromthestartindexonwardarecopied.
Supposeyouhavethearraynamesshowninthefollowingtable:
INDEX 0 1 2 3 4VALUE Paul Sarah Jeremy Adam Bob
Ifyouwanttocreateanewarraywithelements1,Sarah,and2,Jeremy,youwouldspecifyastartindexof1andanendindexof3.Thecodewouldlooksomethinglikethis:
varnames=["Paul","Sarah","Jeremy","Adam","Bob"];
varslicedArray=names.slice(1,3);
WhenJavaScriptcopiesthearray,itcopiesthenewelementstoanarrayinwhichtheyhaveindexes0and1,nottheiroldindexesof1and2.
Afterslicing,theslicedArraylookslikethefollowingtable:
INDEX 0 1VALUE Sarah Jeremy
Thefirstarray,names,isunaffectedbytheslicing.
ConvertinganArrayintoaSingleString—Thejoin()MethodThejoin()methodconcatenatesalltheelementsinanarrayandreturnsthemasastring.Italsoenablesyoutospecifyanycharactersyouwanttoinsertbetweenelementsastheyarejoinedtogether.Themethodhasonlyoneparameter,andthat’sthestringyouwantbetweenelements.
Anexamplewillhelpexplainthings.Imaginethatyouhaveyourweeklyshoppingliststoredinanarray,whichlookssomethinglikethis:
INDEX 0 1 2 3 4VALUE Eggs Milk Potatoes Cereal Banana
Nowyouwanttowriteoutyourshoppinglisttothepageusingdocument.write().Youwanteachitemtobeonadifferentline,andyoucandothisbyusingthe<br/>tagbetweeneachelementinthearray.The<br/>tagisanHTMLlinebreak,avisualcarriagereturnforbreakingtextintodifferentlines.First,youneedtodeclareyourarray:
varmyShopping=["Eggs","Milk","Potatoes","Cereal","Banana"];
Next,convertthearrayintoonestringwiththejoin()method:
varmyShoppingList=myShopping.join("<br/>");
NowthevariablemyShoppingListwillholdthefollowingtext:
"Eggs<br/>Milk<br/>Potatoes<br/>Cereal<br/>Banana"
whichyoucanwriteouttothepagewithdocument.write():
document.write(myShoppingList);
Theshoppinglistwillappearinthepagewitheachitemonanewline,asshowninFigure5.1.
Figure5.1
PuttingYourArrayinOrder—Thesort()MethodIfyouhaveanarraythatcontainssimilardata,suchasalistofnamesoralistofages,youmaywanttoputtheminalphabeticalornumericalorder.Thisissomethingthatthesort()methodmakesveryeasy.Inthefollowingcode,youdefineyourarrayandthenputitinascendingalphabeticalorderusingnames.sort().Finally,yououtputitsothatyoucanseethatit’sinorder:
varnames=["Paul","Sarah","Jeremy","Adam","Bob"];
names.sort();
document.write("Nowthenamesagaininorder<br/>");
for(varindex=0;index<names.length;index++){
document.write(names[index]+"<br/>");
}
Don’tforgetthatthesortingiscasesensitive,soPaulwillcomebeforepaul.RememberthatJavaScriptstoreslettersencodedintheirequivalentUnicodenumber,andthatsortingisdonebasedonUnicodenumbersratherthanactualletters.ItjusthappensthatUnicode
numbersmatchtheorderinthealphabet.However,lowercaselettersaregivenadifferentsequenceofnumbers,whichcomeaftertheuppercaseletters.SothearraywithelementsAdam,adam,Zoë,zoë,willbesortedtotheorderAdam,Zoë,adam,zoë.
Notethatinyourforstatementyou’veusedtheArrayobject’slengthpropertyintheconditionstatement,ratherthaninsertingthelengthofthearray(5),likethis:
for(varindex=0;index<5;index++)
Whydothis?Afterall,youknowinadvancethatyouhavefiveelementsinthearray.Well,whatwouldhappenifyoualteredthenumberofelementsinthearraybyaddingtwomorenames?
varnames=["Paul","Sarah","Jeremy","Adam","Bob","Karen","Steve"];
Ifyouhadinserted5ratherthannames.length,yourloopcodewouldn’tworkasyouwantitto.Itwouldn’tdisplaythelasttwoelementsunlessyouchangedtheconditionpartoftheforloopto7.Byusingthelengthproperty,you’vemadelifeeasier,becausenowthereisnoneedtochangecodeelsewhereifyouaddarrayelements.
Okay,you’veputthingsinascendingorder,butwhatifyouwanteddescendingorder?Thatiswherethereverse()methodcomesin.
PuttingYourArrayintoReverseOrder—Thereverse()MethodThenextmethodfortheArrayobjectisthereverse()method,which,noprizesforguessing,reversestheorderofthearraysothattheelementsatthebackaremovedtothefront.Let’staketheshoppinglistagainasanexample:
INDEX 0 1 2 3 4VALUE Eggs Milk Potatoes Cereal Banana
Ifyouusethereverse()method
varmyShopping=["Eggs","Milk","Potatoes","Cereal","Banana"];
myShopping.reverse();
youget
INDEX 0 1 2 3 4VALUE Banana Cereal Potatoes Milk Eggs
Toprovethis,youcouldwriteittothepagewiththejoin()methodyousawearlier.
varmyShoppingList=myShopping.join("<br/>")
document.write(myShoppingList);
TRYITOUTSortinganArrayWhenusedinconjunctionwiththesort()method,thereverse()methodcanbe
usedtosortanarraysothatitselementsappearinreversealphabeticalornumericalorder.Thisisshowninthefollowingexample:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example3</title>
</head>
<body>
<script>
varmyShopping=["Eggs","Milk","Potatoes","Cereal",
"Banana"];
varord=prompt("Enter1foralphabeticalorder,"+
"and-1forreverseorder",1);
if(ord==1){
myShopping.sort();
document.write(myShopping.join("<br/>"));
}elseif(ord==-1){
myShopping.sort();
myShopping.reverse();
document.write(myShopping.join("<br/>"));
}else{
document.write("Thatisnotavalidinput");
}
</script>
</body>
</html>
Savetheexampleasch5_example3.html.Whenyouloadthisintoyourbrowser,youwillbeaskedtoentersomeinputdependingonwhetheryouwantthearraytobeorderedinforwardorbackwardorder.Ifyouenter1,thearraywillbedisplayedinforwardorder.Ifyouenter–1,thearraywillbedisplayedinreverseorder.Ifyouenterneitherofthesevalues,youwillbetoldthatyourinputwasinvalid.
Atthetopofthescriptblock,youdefinethearraycontainingyourshoppinglist.Nextyoudefinethevariableordtobethevalueenteredbytheuserinapromptbox:
varord=prompt("Enter1foralphabeticalorder,"+
"and-1forreverseorder",1);
Thisvalueisusedintheconditionsoftheifstatementsthatfollow.Thefirstifcheckswhetherthevalueofordis1—thatis,whethertheuserwantsthearrayinalphabeticalorder.Ifso,thefollowingcodeisexecuted:
myShopping.sort();
document.write(myShopping.join("<br/>"));
Thearrayissortedandthendisplayedtotheuseronseparatelinesusingthejoin()method.Next,intheelseifstatement,youcheckwhetherthevalueofordis-1—thatis,whethertheuserwantsthearrayinreversealphabeticalorder.Ifso,thefollowingcodeisexecuted:
myShopping.sort();
myShopping.reverse();
document.write(myShopping.join("<br/>"));
Here,yousortthearraybeforereversingitsorder.Againthearrayisdisplayedtotheuserbymeansofthejoin()method.
Finally,ifordhasneitherthevalue1northevalue-1,youtelltheuserthathisinputwasinvalid:
document.write("Thatisnotavalidinput");
FindingArrayElements—TheindexOf()andlastIndexOf()MethodsAsyoucanprobablyguess,theArrayobject’sindexOf()andlastIndexOf()methodsbehavesimilarlytotheStringobject’smethods—theyreturntheindexofanitem’sfirstandlastoccurrenceinanarray.Considerthefollowingcode:
varcolors=["red","blue","green","blue"];
alert(colors.indexOf("red"));
alert(colors.lastIndexOf("blue"));
Thefirstlineofcodecreatesanarraycalledcolors.Ithasfourelements(twoofwhichareblue).Thesecondlinealerts0totheuser,becauseredisthefirstelementofthearray.Thethirdlinereturnsthevalueof3becausethelastIndexOf()methodbeginsitssearchattheveryendofthearray.
BoththeindexOf()andlastIndexOf()methodsreturn-1iftheprovidedvaluecannotbefoundinthearray.
IteratingthroughanArraywithoutLoopsTheremainingfivemethodsarecallediterativemethodsbecausetheyiterate,orloop,throughthearray.Inaddition,thesemethodsexecuteafunctionthatyoudefineoneveryelementwhiletheyiteratethroughthearray.Thefunctionthesemethodsusemustfollowonerule—itmustacceptthreeargumentslikethefollowingcode:
functionfunctionName(value,index,array){
//dosomethinghere
}
Whenexecuted,JavaScriptpassesthreeargumentstoyourfunction.Thefirstisthevalueoftheelement,thesecondistheindexoftheelement,andthethirdisthearrayitself.Thesethreeparametersenableyoutoperformjustaboutanyoperationorcomparisonyoumightneedinrelationtothearrayanditselements.
TestingEachElement—Theevery(),some(),andfilter()MethodsLet’slookattheevery()andsome()methodsfirst.Thesearetestingmethods.Theevery()methodtestswhetherallelementsinthearraypassthetestinyourfunction.Considerthefollowingcode:
varnumbers=[1,2,3,4,5];
functionisLessThan3(value,index,array){
varreturnValue=false;
if(value<3){
returnValue=true;
}
returnreturnValue;
}
alert(numbers.every(isLessThan3));
Thefirstlineshowsthecreationofanarraycallednumbers;itselementsholdthevalues1through5.ThenextlinedefinestheisLessThan3()function.Itacceptsthethreemandatoryargumentsanddeterminesifthevalueofeachelementislessthan3.Thelastlinealertstheoutcomeoftheevery()test.Becausenoteveryvalueinthearrayislessthan3,theresultoftheevery()testisfalse.
Contrastthiswiththesome()method.Unlikeevery(),thesome()testonlycaresifsomeoftheelementspassthetestinyourfunction.UsingthesamenumbersarrayandisLessThan3()function,considerthislineofcode:
alert(numbers.some(isLessThan3));
Theresultistruebecausesomeoftheelementsinthearrayarelessthan3.It’seasytokeepthesetwomethodsstraight.Justremembertheevery()methodreturnstrueif,andonlyif,allelementsinthearraypassthetestinyourfunction;thesome()methodreturnstrueif,andonlyif,someoftheelementsinthearraypassyourfunction’stest.
Let’sassumeyouwanttoretrievetheelementsthathaveavaluelessthan3.Youalreadyknowsomeelementsmeetthiscriterion,buthowdoyouidentifythoseelementsandretrievethem?Thisiswherethefilter()methodbecomesuseful.
Thefilter()methodexecutesyourfunctiononeveryelementinthearray,andifyourfunctionreturnstrueforaparticularelement,thatelementisaddedtoanewarraythatthefilter()methodreturns.Keepingthatinmind,lookatthefollowingcode:
varnumbers=[1,2,3,4,5];
functionisLessThan3(value,index,array){
varreturnValue=false;
if(value<3){
returnValue=true;
}
returnreturnValue;
}
if(numbers.some(isLessThan3)){
varresult=numbers.filter(isLessThan3);
alert("Thesenumbersarelessthan3:"+result);
}
ThiscoderedefinesthenumbersarrayandtheisLessThan3functionusedinpreviousexamples.Thehighlightedcodedeterminesifanyelementsinthenumbersarraycontainavaluelessthan3,andifso,callsthefilter()methodtoplacethoseelementsintoanewarray.TheresultofthiscodeisshowninFigure5.2.
Figure5.2
OperatingonElements—TheforEach()andmap()MethodsThefinaltwomethodsaretheforEach()andmap()methods.Unlikethepreviousiterativemethods,thesetwomethodsdonottesteachelementinthearraywithyourfunction;instead,thefunctionyouwriteshouldperformsomekindofoperationthatusestheelementinsomeway.Lookatthefollowingcode:
varnumbers=[1,2,3,4,5];
for(vari=0;i<numbers.length;i++){
varresult=numbers[i]*2;
alert(result);
}
Asaprogrammer,you’lloftenseeandusethistypeofcode.Itdefinesanarrayandloopsthroughitinordertoperformsomekindofoperationoneachelement.Inthiscase,thevalueofeachelementisdoubled,andtheresultisshowninanalertboxtotheuser.
ThiscodecanberewrittentousetheforEach()method.Asitsnameimplies,itdoessomethingforeachelementinthearray.Allyouneedtodoiswriteafunctiontodoubleagivenvalueandoutputtheresultinanalertbox,likethis:
varnumbers=[1,2,3,4,5];
functiondoubleAndAlert(value,index,array){
varresult=value*2;
alert(result);
}
numbers.forEach(doubleAndAlert);
NoticethatthedoubleAndAlert()functiondoesn’treturnavaluelikethetestingmethods.Itcannotreturnavalue;itsonlypurposeistoperformanoperationoneveryelementinthearray.Thisisusefulinmanycases,butyou’llwanttousethemap()methodwhenyouneedtostoretheresultsofthefunction.
Thepremiseofthemap()methodissimilartothatofforEach().Itexecutesagivenfunctiononeveryelementinanarray,butitalsoreturnsanewarraythatcontainstheresultsofthefunction.
Let’smodifythepreviousexampleandwriteanewfunctioncalleddoubleAndReturn().Itwillstilldoubleeachelementinthearray,butitwillreturnthedoubledvalueinsteadofalertingit.ThefollowingcodepassesthedoubleAndReturn()functiontotheArrayobject’smap()method:
varnumbers=[1,2,3,4,5];
functiondoubleAndReturn(value,index,array){
varresult=value*2;
returnresult;
}
vardoubledNumbers=numbers.map(doubleAndReturn);
alert("Thedoublednumbersare:"+doubledNumbers);
Figure5.3showstheresultsofthiscode.It’simportanttonotethatthemap()methoddoesnotaltertheoriginalarray.
Figure5.3
TheMathObjectTheMathobjectprovidesanumberofusefulmathematicalfunctionsandnumbermanipulationmethods.Youtakealookatsomeofthemhere,butyou’llfindtherestdescribedindetailattheMozillaDeveloperNetwork:https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Math.
TheMathobjectisalittleunusualinthatJavaScriptcreatesitforyouautomatically.There’snoneedtodeclareavariableasaMathobjectordefineanewMathobjectbeforebeingabletouseit,makingitalittlebiteasiertouse.
ThepropertiesoftheMathobjectincludesomeusefulmathconstants,suchasthePIproperty(givingthevalue3.14159andsoon).Youaccesstheseproperties,asusual,byplacingadotaftertheobjectname(Math)andthenwritingthepropertyname.Forexample,tocalculatetheareaofacircle,youcanusethefollowingcode:
varradius=prompt("Givetheradiusofthecircle","");
vararea=Math.PI*radius*radius;
document.write("Theareais"+area);
ThemethodsoftheMathobjectincludesomeoperationsthatareimpossible,orcomplex,toperformusingthestandardmathematicaloperators(+,–,*,and/).Forexample,thecos()methodreturnsthecosineofthevaluepassedasaparameter.Youlookatafewofthesemethodsnow.
Theabs()MethodTheabs()methodreturnstheabsolutevalueofthenumberpassedasitsparameter.Essentially,thismeansthatitreturnsthepositivevalueofthenumber.So-1isreturnedas
1,-4as4,andsoon.However,1wouldbereturnedas1becauseit’salreadypositive.
Forexample,thefollowingcodewritesthenumber101tothepage:
varmyNumber=-101;
document.write(Math.abs(myNumber));
FindingtheLargestandSmallestNumbers—Themin()andmax()MethodsLet’ssayyouhavetwonumbers,andyouwanttofindeitherthelargestorsmallestofthetwo.Toaidyouinthistask,theMathobjectprovidesthemin()andmax()methods.Thesemethodsbothacceptatleasttwoarguments,allofwhichmustobviouslybenumbers.Lookatthisexamplecode:
varmax=Math.max(21,22);//resultis22
varmin=Math.min(30.1,30.2);//resultis30.1
Themin()methodreturnsthenumberwiththelowestvalue,andmax()returnsthenumberwiththehighestvalue.Thenumbersyoupasstothesetwomethodscanbewholeorfloating-pointnumbers.
NOTEThemax()andmin()methodscanacceptmanynumbers;you’renotlimitedtotwo.
RoundingNumbersTheMathobjectprovidesafewmethodstoroundnumbers,eachwithitsownspecificpurpose.
Theceil()MethodTheceil()methodalwaysroundsanumberuptothenextlargestwholenumberorinteger.So10.01becomes11,and–9.99becomes–9(because–9isgreaterthan–10).Theceil()methodhasjustoneparameter,namelythenumberyouwantroundedup.
Usingceil()isdifferentfromusingtheparseInt()functionyousawinChapter2,becauseparseInt()simplychopsoffanynumbersafterthedecimalpointtoleaveawholenumber,whereasceil()roundsthenumberup.
Forexample,thefollowingcodewritestwolinesinthepage,thefirstcontainingthenumber102andthesecondcontainingthenumber101:
varmyNumber=101.01;
document.write(Math.ceil(myNumber)+"<br/>");
document.write(parseInt(myNumber,10));
Thefloor()MethodLiketheceil()method,thefloor()methodremovesanynumbersafterthedecimalpoint,andreturnsawholenumberorinteger.Thedifferenceisthatfloor()alwaysroundsthenumberdown.Soifyoupass10.01youwillbereturned10,andifyoupass–9.99youwillsee–10returned.
Theround()MethodTheround()methodisverysimilartoceil()andfloor(),exceptthatinsteadofalwaysroundinguporalwaysroundingdown,itroundsuponlyifthedecimalpartis.5orgreater,androundsdownotherwise.
Forexample:
varmyNumber=44.5;
document.write(Math.round(myNumber)+"<br/>");
myNumber=44.49;
document.write(Math.round(myNumber));
Thiscodewouldwritethenumbers45and44tothepage.
SummaryofRoundingMethodsAsyouhaveseen,theceil(),floor(),andround()methodsallremovethenumbersafteradecimalpointandreturnjustawholenumber.However,whichwholenumbertheyreturndependsonthemethodused:floor()returnsthelowest,ceil()thehighest,andround()thenearestequivalentinteger.Thiscanbealittleconfusing,sothefollowingisatableofvaluesandwhatwholenumberwouldbereturnedifthesevalueswerepassedtotheparseInt()function,andceil(),floor(),andround()methods:
PARAMETER PARSEINT()RETURNS
CEIL()RETURNS
FLOOR()RETURNS
ROUND()RETURNS
10.25 10 11 10 1010.75 10 11 10 1110.5 10 11 10 11−10.25 −10 −10 −11 −10−10.75 −10 −10 −11 −11−10.5 −10 −10 −11 −10
NOTERememberthatparseInt()isanativeJavaScriptfunction,notamethodoftheMathobject,liketheothermethodspresentedinthistable.
TRYITOUTRoundingMethodsResultsCalculatorIfyou’restillnotsureaboutroundingnumbers,thisexampleshouldhelp.Here,youlookatacalculatorthatgetsanumberfromtheuser,andthenwritesoutwhattheresultwouldbewhenyoupassthatnumbertoparseInt(),ceil(),floor(),andround():
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example4</title>
</head>
<body>
<script>
varmyNumber=prompt("Enterthenumbertoberounded","");
document.write("<h3>Thenumberyouenteredwas"+myNumber+
"</h3>");
document.write("<p>Theroundingresultsforthisnumber
are</p>");
document.write("<tablewidth='150'border='1'>");
document.write("<tr><th>Method</th><th>Result</th></tr>");
document.write("<tr><td>parseInt()</td><td>"+
parseInt(myNumber,10)+"</td></tr>");
document.write("<tr><td>ceil()</td><td>"+Math.ceil(myNumber)
+
"</td></tr>");
document.write("<tr><td>floor()</td><td>"+Math.floor(myNumber)
+
"</td></tr>");
document.write("<tr><td>round()</td><td>"+
Math.round(myNumber)+
"</td></tr>");
document.write("</table>");
</script>
</body>
</html>
Savethisasch5_example4.htmlandloaditintoawebbrowser.Inthepromptbox,enteranumber(forexample,12.354),andclickOK.TheresultsofthisnumberbeingpassedtoparseInt(),ceil(),floor(),andround()willbedisplayedinthepageformattedinsideatable,asshowninFigure5.4.
Figure5.4
Thefirsttaskistogetthenumbertoberoundedfromtheuser:
varmyNumber=prompt("Enterthenumbertoberounded","");
Thenyouwriteoutthenumberandsomedescriptivetext:
document.write("<h3>Thenumberyouenteredwas"+myNumber+"</h3>");
document.write("<p>Theroundingresultsforthisnumberare</p>");
NoticehowthistimesomeHTMLtagsforformattinghavebeenincluded—themainheaderbeingin<h3>tags,andthedescriptionofwhatthetablemeansbeinginsideaparagraph<p>tag.
Nextyoucreatethetableofresults:
document.write("<tablewidth='150'border='1'>");
document.write("<tr><th>Method</th><th>Result</th></tr>");
document.write("<tr><td>parseInt()</td><td>"+
parseInt(myNumber,10)+"</td></tr>");
document.write("<tr><td>ceil()</td><td>"+Math.ceil(myNumber)+
"</td></tr>");
document.write("<tr><td>floor()</td><td>"+Math.floor(myNumber)+
"</td></tr>");
document.write("<tr><td>round()</td><td>"+Math.round(myNumber)+
"</td></tr>");
document.write("</table>");
Youcreatethetableheaderfirstbeforeactuallydisplayingtheresultsofeach
roundingfunctiononaseparaterow.TheprinciplesarethesameaswithHTMLinapage:Youmustmakesureyourtag’ssyntaxisvalidorotherwisethingswillappearstrangeornotappearatall.
Eachrowfollowsthesameprinciplebutusesadifferentroundingfunction.Let’slookatthefirstrow,whichdisplaystheresultsofparseInt():
document.write("<tr><td>parseInt()</td><td>"+
parseInt(myNumber,10)+"</td></tr>");
Insidethestringtobewrittenouttothepage,youstartbycreatingthetablerowwiththe<tr>tag.Thenyoucreateatablecellwitha<td>tagandinsertthenameofthemethodfromwhichtheresultsarebeingdisplayedonthisrow.Thenyouclosethecellwith</td>andopenanewonewith<td>.InsidethisnextcellyouareplacingtheactualresultsoftheparseInt()function.AlthoughanumberisreturnedbyparseInt(),becauseyouareconcatenatingittoastring,JavaScriptautomaticallyconvertsthenumberreturnedbyparseInt()intoastringbeforeconcatenating.Allthishappensinthebackgroundwithoutyouneedingtodoathing.Finally,youclosethecellandtherowwith</td></tr>.
Therandom()MethodTherandom()methodreturnsarandomfloating-pointnumberintherangebetween0and1,where0isincludedand1isnot.ThiscanbeveryusefulfordisplayingrandombannerimagesorforwritingaJavaScriptgame.
Let’slookathowyouwouldmimictherollofasingledie.Inthefollowingpage,10randomnumbersarewrittentothepage.Clickthebrowser’sRefreshbuttontogetanothersetofrandomnumbers.
<!DOCTYPEhtml>
<htmllang="en">
<body>
<script>
vardiceThrow;
for(varthrowCount=0;throwCount<10;throwCount++){
diceThrow=(Math.floor(Math.random()*6)+1);
document.write(diceThrow+"<br>");
}
</script>
</body>
</html>
YouwantdiceThrowtobebetween1and6.Therandom()functionreturnsafloating-pointnumberbetween0andjustunder1.Bymultiplyingthisnumberby6,yougetanumberbetween0andjustunder6.Thenbyadding1,yougetanumberbetween1andjustunder7.Byusingfloor()toalwaysrounditdowntothenextlowestwholenumber,youcanensurethatyou’llendupwithanumberbetween1and6.
Ifyouwantedarandomnumberbetween1and100,youwouldjustchangethecodeso
thatMath.random()ismultipliedby100ratherthan6.
Thepow()MethodThepow()methodraisesanumbertoaspecifiedpower.Ittakestwoparameters,thefirstbeingthenumberyouwantraisedtoapower,andthesecondbeingthepoweritself.Forexample,toraise2tothepowerof8(thatis,tocalculate2*2*2*2*2*2*2*2),youwouldwriteMath.pow(2,8)—theresultbeing256.Unlikesomeoftheothermathematicalmethods,likesin(),cos(),andacos(),whicharenotcommonlyusedinwebprogrammingunlessit’sascientificapplicationyou’rewriting,thepow()methodcanoftenproveveryuseful.
TRYITOUTUsingpow()Inthisexample,youwriteafunctionusingpow(),whichfixesthenumberofdecimalplacesinanumber:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter<5,Example5</title>
</head>
<body>
<script>
functionfix(fixNumber,decimalPlaces){
vardiv=Math.pow(10,decimalPlaces);
fixNumber=Math.round(fixNumber*div)/div;
returnfixNumber;
}
varnumber1=prompt("Enterthenumberwithdecimalplacesyou
"+
"wanttofix","");
varnumber2=prompt("Howmanydecimalplacesdoyouwant?",
"");
document.write(number1+"fixedto"+number2+"decimal
placesis:");
document.write(fix(number1,number2));
</script>
</body>
</html>
Savethepageasch5_example5.html.Whenyouloadthepageintoyourbrowser,youwillbepresentedwithtwopromptboxes.Inthefirst,enterthenumberforwhichyouwanttofixthenumberofdecimalplaces(forexample,2.2345).Inthesecond,enterthenumberofdecimalplacesyouwantfixed(forexample,2).Thentheresultoffixingthenumberyouhaveenteredtothenumberofdecimalplacesyouhavechosenwillbewrittentothepage,asshowninFigure5.5.Fortheexamplenumbers,
thiswillbe2.23.
Figure5.5
Youfirstdefinethefunctionfix().ThisfunctionwillfixitsfixNumberparametertoamaximumofitsdecimalPlacesparameter’snumberofdigitsafterthedecimalplace.Forexample,fixing34.76459toamaximumofthreedecimalplaceswillreturn34.765.
Thefirstlineofcodeinthefunctionsetsthevariabledivtothenumber10raisedtothepowerofthenumberofdecimalplacesyouwant:
functionfix(fixNumber,decimalPlaces){
vardiv=Math.pow(10,decimalPlaces);
Then,inthenextline,youcalculatethenewnumber:
fixNumber=Math.round(fixNumber*div)/div;
WhatthecodeMath.round(fixNumber*div)doesismovethedecimalpointinthenumberthatyouareconvertingtoafterthepointinthenumberthatyouwanttokeep.Sofor2.2345,ifyouwanttokeeptwodecimalplaces,youconvertitto223.45.TheMath.round()methodroundsthisnumbertothenearestinteger(inthiscase223)andsoremovesanyundesireddecimalpart.
Youthenconvertthisnumberbackintothefractionitshouldbe,butofcourseonlythefractionalpartyouwantisleft.Youdothisbydividingbythesamenumber(div)thatyoumultipliedby.Inthisexample,youdivide223by100,whichleaves2.23.Thisis2.2345fixedtotwodecimalplaces.Thisvalueisreturnedtothecallingcodeintheline:
returnfixNumber;
}
Next,youusetwopromptboxestogetnumbersfromtheuser.Youthendisplaytheresultsofusingthesenumbersinyourfix()functiontotheuserusingdocument.write().
Thisexampleisjustthat—anexample.Inafewminutes,youlearnabouttheNumberobject’stoFixed()method,whichdoesthesamethingasthefix()function.
NumberObjectsAswiththeStringobject,Numberobjectsneedtobecreatedbeforetheycanbeused.TocreateaNumberobject,youcanwritethefollowing:
varfirstNumber=newNumber(123);
varsecondNumber=newNumber('123');
However,asyouhaveseen,youcanalsodeclareanumberasprimitiveanduseitasifitwereaNumberobject,lettingJavaScriptdotheconversiontoanobjectforyoubehindthescenes.Forexample:
varmyNumber=123.765;
AswiththeStringobject,thistechniqueispreferablesolongasit’scleartoJavaScriptwhatobjectyouexpecttohavecreatedinthebackground.So,forexample,
varmyNumber="123.567";
willleadJavaScripttoassume,quiterightly,thatit’sastring,andanyattemptstousetheNumberobject’smethodswillfail.
YoulookatjustthetoFixed()methodoftheNumberobjectbecausethat’sthemostusefulmethodforregularuse.
ThetoFixed()MethodThetoFixed()methodcutsanumberoffafteracertainpoint.Let’ssayyouwanttodisplayapriceaftersalestax.Ifyourpriceis$9.99andsalestaxis7.5percent,thatmeanstheafter-taxcostwillbe$10.73925.Well,thisisratheranoddamountforamoneytransaction—whatyoureallywanttodoisfixthenumbertonomorethantwodecimalplaces.Let’screateanexample:
varitemCost=9.99;
varitemCostAfterTax=9.99*1.075;
document.write("Itemcostis$"+itemCostAfterTax+"<br/>");
itemCostAfterTax=itemCostAfterTax.toFixed(2);
document.write("Itemcostfixedto2decimalplacesis"+
"$"+itemCostAfterTax);
Thefirstdocument.write()outputsthefollowingtothepage:
Itemcostis$10.73925
However,thisisnottheformatyouwant;insteadyouwanttwodecimalplaces,soonthenextline,enterthis:
itemCostAfterTax=itemCostAfterTax.toFixed(2);
YouusethetoFixed()methodoftheNumberobjecttofixthenumbervariablethatitemCostAfterTaxholdstotwodecimalplaces.Themethod’sonlyparameteristhenumberofdecimalplacesyouwantyournumberfixedto.Thislinemeansthatthenextdocument.writedisplaysthis:
Itemcostfixedto2decimalplacesis$10.74
Thefirstthingyoumightwonderiswhy10.74andnot10.73?Well,thetoFixed()methoddoesn’tjustchopoffthedigitsnotrequired;italsoroundsupordown.Inthiscase,thenumberwas10.739,whichroundsupto10.74.Ifit’dbeen10.732,itwouldhavebeenroundeddownto10.73.
Notethatyoucanonlyfixanumberfrom0to20decimalplaces.
DateObjectsTheDateobjecthandleseverythingtodowithdateandtimeinJavaScript.Usingit,youcanfindoutthecurrentdateandtime,storeyourowndatesandtimes,docalculationswiththesedates,andconvertthedatesintostrings.
TheDateobjecthasalotofmethodsandcanbealittletrickytouse,whichiswhyChapter7isdedicatedtothedate,time,andtimersinJavaScript.However,inthissectionyoufocusonhowtocreateaDateobjectandsomeofitsmorecommonlyusedmethods.
CreatingaDateObjectYoucandeclareandinitializeaDateobjectinfourways.Inthefirstmethod,yousimplydeclareanewDateobjectwithoutinitializingitsvalue.Inthiscase,thedateandtimevaluewillbesettothecurrentdateandtimeonthePConwhichthescriptisrun:
vartheDate1=newDate();
Secondly,youcandefineaDateobjectbypassingthenumberofmillisecondssinceJanuary1,1970,at00:00:00GMT.Inthefollowingexample,thedateis31January200000:20:00GMT(thatis,20minutespastmidnight):
vartheDate2=newDate(949278000000);
It’sunlikelythatyou’llbeusingthiswayofdefiningaDateobjectveryoften,butthisishowJavaScriptactuallystoresthedates.Theotherformatsforgivingadatearesimplyforconvenience.
ThethirdwayforyoutodeclareaDateobjectistopassastringrepresentingadate,oradateandtime.Inthefollowingexample,youhave"31January2014":
vartheDate3=newDate("31January2014");
However,youcouldhavewritten31Jan2014,Jan312014,oranyofanumberofvalidvariationsyou’dcommonlyexpectwhenwritingdownadatenormally—ifindoubt,tryitout.
Ifyouarewritingyourwebpagesforaninternationalaudience,youneedtobeawareofthedifferentwaysofspecifyingdates.IntheUnitedKingdomandmanyotherplaces,thestandardisday,month,year,whereasintheUnitedStatesthestandardismonth,day,year.Thiscancauseproblemsifyouspecifyonlynumbers—JavaScriptmaythinkyou’rereferringtoadaywhenyoumeanamonth.
InthefourthandfinalwayofdefiningaDateobject,youinitializeitbypassingthefollowingparametersseparatedbycommas:year,month,day,hours,minutes,seconds,andmilliseconds.Forexample:
vartheDate4=newDate(2014,0,31,15,35,20,20);
Thisdateisactually31January2014at15:35:20and20milliseconds.Youcanspecifyjustthedatepartifyouwantandignorethetime.SomethingtobeawareofisthatinthisinstanceJanuaryismonth0,notmonth1,asyou’dexpect,andDecemberismonth11.
TIPIt’sveryeasytomakeamistakewhenspecifyingamonthusingeitherthethirdorfourthmethodofdeclaringaDateobject.Theeasiestwaytoavoidsuchheadachesistoalwaysusethenameofthemonthwherepossible.Thatwaytherecanbenoconfusion.
GettingDateValuesIt’sallverynicehavingstoredadate,buthowdoyougettheinformationoutagain?Well,youjustusethegetmethods.Thesearesummarizedinthefollowingtable:
METHOD RETURNSgetDate() ThedayofthemonthgetDay() Thedayoftheweekasaninteger,withSundayas0,Mondayas1,and
soongetMonth() Themonthasaninteger,withJanuaryas0,Februaryas1,andsoongetFullYear() Theyearasafour-digitnumbertoDateString() Returnsthefulldatebasedonthecurrenttimezoneasahuman-
readablestring,forexample,“Wed31Dec2003”
Forexample,ifyouwanttogetthemonthinourDateObj,youcansimplywritethefollowing:
theMonth=myDateObject.getMonth();
Allthemethodsworkinaverysimilarway,andallvaluesreturnedarebasedonlocaltime,meaningtimelocaltothemachineonwhichthecodeisrunning.It’salsopossibletouseUniversalTime,previouslyknownasGMT,whichwediscussinChapter7.
TRYITOUTUsingtheDateObjecttoRetrievetheCurrentDateInthisexample,youusethegetdatetypemethodsyouhavebeenlookingattowritethecurrentday,month,andyeartoawebpage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example6</title>
</head>
<body>
<script>
varmonths=["January","February","March","April","May",
"June","July","August","September",
"October","November","December"];
vardateNow=newDate();
varyearNow=dateNow.getFullYear();
varmonthNow=months[dateNow.getMonth()];
vardayNow=dateNow.getDate();
vardaySuffix;
switch(dayNow){
case1:
case21:
case31:
daySuffix="st";
break;
case2:
case22:
daySuffix="nd";
break;
case3:
case23:
daySuffix="rd";
break;
default:
daySuffix="th";
break;
}
document.write("Itisthe"+dayNow+daySuffix+"day");
document.write("inthemonthof"+monthNow);
document.write("intheyear"+yearNow);
</script>
</body>
</html>
Savethecodeasch5_example6.html.Whenyouloadthepageinyourbrowser,youshouldseeacorrectlyformattedsentencetellingyouthecurrentdate.
Thefirstthingyoudointhecodeisdeclareanarrayandpopulateitwiththemonthsofayear.Whydothis?Well,thereisnomethodoftheDateobjectthat’llgiveyouthemonthbynameinsteadofasanumber.However,thisposesnoproblem;youjustdeclareanarrayofmonthsandusethemonthnumberasthearrayindextoselectthecorrectmonthname:
varmonths=["January","February","March","April","May","June",
"July",
"August","September","October","November",
"December"];
NextyoucreateanewDateobject,andbynotinitializingitwithyourownvalue,youallowittoinitializeitselftothecurrentdateandtime:
vardateNow=newDate();
FollowingthisyousettheyearNowvariabletothecurrentyear,asreturnedbythegetFullYear()method:
varyearNow=dateNow.getFullYear();
YouthenpopulateyourmonthNowvariablewiththevaluecontainedinthearrayelementwithanindexofthenumberreturnedbygetMonth().RememberthatgetMonth()returnsthemonthasanintegervalue,startingwith0forJanuary—thisisabonusbecausearraysalsostartat0,sonoadjustmentisneededtofindthecorrectarrayelement:
varmonthNow=months[dateNow.getMonth()];
Finally,youputthecurrentdayofthemonthintothevariabledayNow:
vardayNow=dateNow.getDate();
Nextyouuseaswitchstatement,whichyoulearnedaboutinChapter3.Thisisausefultechniqueforaddingthecorrectsuffixtothedatethatyoualreadyhave.Afterall,yourapplicationwilllookmoreprofessionalifyoucansay"itisthe1stday",ratherthan"itisthe1day".Thisisalittletricky,however,becausethesuffixyouwanttoadddependsonthenumberthatprecedesit.So,forthefirst,twenty-first,andthirty-firstdaysofthemonth,youhavethis:
switch(dayNow){
case1:
case21:
case31:
daySuffix="st";
break;
Forthesecondandtwenty-seconddays,youhavethis:
case2:
case22:
daySuffix="nd";
break;
andforthethirdandtwenty-thirddays,youhavethis:
case3:
case23:
daySuffix="rd";
break;
Finally,youneedthedefaultcaseforeverythingelse.Asyouwillhaveguessedbynow,thisissimply"th":
default:
daySuffix="th";
break;
}
InthefinallinesyousimplywritetheinformationtotheHTMLpage,usingdocument.write().
SettingDateValuesTochangepartofthedateinaDateobject,youhaveagroupofsetfunctions,whichprettymuchreplicatethegetfunctionsdescribedearlier,exceptthatyouaresetting,notgetting,thevalues.Thesefunctionsaresummarizedinthefollowingtable:
METHOD DESCRIPTIONsetDate() Thedateofthemonthispassedinastheparametertosetthedate.setMonth() Themonthoftheyearispassedinasanintegerparameter,where0is
January,1isFebruary,andsoon.setFullYear() Thissetstheyeartothefour-digitintegernumberpassedinasa
parameter.
NOTEthatforsecurityreasons,thereisnowayforweb-basedJavaScripttochangethecurrentdateandtimeonauser’scomputer.
So,tochangetheyearto2016,thecodewouldbeasfollows:
myDateObject.setFullYear(2016);
Settingthedateandmonthtothe27thofFebruarylookslikethis:
myDateObject.setDate(27);
myDateObject.setMonth(1);
OneminorpointtonotehereisthatthereisnodirectequivalentofthegetDay()method.Aftertheyear,date,andmonthhavebeendefined,thedayisautomaticallysetforyou.
CalculationsandDatesTakealookatthefollowingcode:
varmyDate=newDate("1Jan2010");
myDate.setDate(32);
document.write(myDate);
Surelythereissomeerror—sincewhenhasJanuaryhad32days?Theansweristhatofcourseitdoesn’t,andJavaScriptknowsthat.InsteadJavaScriptsetsthedateto32daysfromthefirstofJanuary—thatis,itsetsittothe1stofFebruary.
ThesamealsoappliestothesetMonth()method.Ifyousetittoavaluegreaterthan11,thedateautomaticallyrollsovertothenextyear.SoifyouusesetMonth(12),thatwillsetthedatetoJanuaryofthenextyear,andsimilarlysetMonth(13)isFebruaryofthenextyear.
HowcanyouusethisfeatureofsetDate()andsetMonth()toyouradvantage?Well,let’ssayyouwanttofindoutwhatdateitwillbe28daysfromnow.Giventhatdifferentmonthshavedifferentnumbersofdaysandthatyoucouldrollovertoadifferentyear,it’snotassimpleataskasitmightfirstseem.OratleastthatwouldbethecaseifitwerenotforsetDate().Thecodetoachievethistaskisasfollows:
varnowDate=newDate();
varcurrentDay=nowDate.getDate();
nowDate.setDate(currentDay+28);
FirstyougetthecurrentsystemdatebysettingthenowDatevariabletoanewDateobjectwithnoinitializationvalue.Inthenextline,youputthecurrentdayofthemonthintoavariablecalledcurrentDay.Why?Well,whenyouusesetDate()andpassitavalueoutsideofthemaximumnumberofdaysforthatmonth,itstartsfromthefirstofthemonthandcountsthatmanydaysforward.So,iftoday’sdateisJanuary15andyouusesetDate(28),it’snot28daysfromthe15thofJanuary,but28daysfromthe1stofJanuary.Whatyouwantis28daysfromthecurrentdate,soyouneedtoaddthecurrentdatetothenumberofdaysaheadyouwant.SoyouwantsetDate(15+28).Inthethirdline,yousetthedatetothecurrentdate,plus28days.YoustoredthecurrentdayofthemonthincurrentDay,sonowyoujustadd28tothattomove28daysahead.
Ifyouwantthedate28dayspriortothecurrentdate,youjustpassthecurrentdateminus28.Notethatthiswillmostoftenbeanegativenumber.Youneedtochangeonlyoneline,andthat’sthethirdone,whichyouchangetothefollowing:
nowDate.setDate(currentDay-28);
YoucanuseexactlythesameprinciplesforsetMonth()asyouhaveusedforsetDate().
GettingTimeValuesThemethodsyouusetoretrievetheindividualpiecesoftimedataworkmuchlikethegetmethodsfordatevalues.Themethodsyouusehereare:
getHours()
getMinutes()
getSeconds()
getMilliseconds()
toTimeString()
Thesemethodsreturn,respectively,thehours,minutes,seconds,milliseconds,andfulltimeofthespecifiedDateobject,wherethetimeisbasedonthe24-hourclock:0formidnightand23for11p.m.ThelastmethodissimilartothetoDateString()methodinthatitreturnsaneasilyreadablestring,exceptthatinthiscaseitcontainsthetime(forexample,"13:03:51UTC").
TRYITOUTWritingtheCurrentTimeintoaWebPageLet’slookatanexamplethatwritesoutthecurrenttimetothepage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example7</title>
</head>
<body>
<script>
vargreeting;
varnowDate=newDate();
varnowHour=nowDate.getHours();
varnowMinute=nowDate.getMinutes();
varnowSecond=nowDate.getSeconds();
if(nowMinute<10){
nowMinute="0"+nowMinute;
}
if(nowSecond<10){
nowSecond="0"+nowSecond;
}
if(nowHour<12){
greeting="GoodMorning";
}elseif(nowHour<17){
greeting="GoodAfternoon";
}else{
greeting="GoodEvening";
}
document.write("<h4>"+greeting+"andwelcometomy
website</h4>");
document.write("Accordingtoyourclockthetimeis");
document.write(nowHour+":"+nowMinute+":"+nowSecond);
</script>
</body>
</html>
Savethispageasch5_example7.html.Whenyouloaditintoawebbrowser,itwritesagreetingbasedonthetimeofdayaswellasthecurrenttime,asshowninFigure5.6.
Figure5.6
Thefirsttwolinesofcodedeclaretwovariables—greetingandnowDate:
vargreeting;
varnowDate=newDate();
Thegreetingvariablewillbeusedshortlytostorethewelcomemessageonthewebsite,whetherthisis"GoodMorning","GoodAfternoon",or"GoodEvening".ThenowDatevariableisinitializedtoanewDateobject.NotethattheconstructorfortheDateobjectisempty,soJavaScriptwillstorethecurrentdateandtimeinit.
Next,yougettheinformationonthecurrenttimefromnowDateandstoreitinvariousvariables.Youcanseethatgettingtimedataisverysimilartogettingdatedata,justusingdifferentmethods:
varnowHour=nowDate.getHours();
varnowMinute=nowDate.getMinutes();
varnowSecond=nowDate.getSeconds();
Youmaywonderwhythefollowinglinesareincludedintheexample:
if(nowMinute<10){
nowMinute="0"+nowMinute;
}
if(nowSecond<10){
nowSecond="0"+nowSecond;
}
Theselinesaretherejustforformattingreasons.Ifthetimeisnineminutespast10,thenyouexpecttoseesomethinglike10:09.Youdon’texpect10:9,whichiswhatyouwouldgetifyouusedthegetMinutes()methodwithoutaddingtheextrazero.Thesamegoesforseconds.Ifyou’rejustusingthedataincalculations,youdon’tneedtoworryaboutformattingissues—youdoherebecauseyou’reinsertingthetimethecodeexecutedintothewebpage.
Next,inaseriesofifstatements,youdecide(basedonthetimeofday)whichgreetingtocreatefordisplayingtotheuser:
if(nowHour<12){
greeting="GoodMorning";
}elseif(nowHour<17){
greeting="GoodAfternoon";
}else{
greeting="GoodEvening";
}
Finally,youwriteoutthegreetingandthecurrenttimetothepage:
document.write("<h4>"+greeting+"andwelcometomywebsite</h4>");
document.write("Accordingtoyourclockthetimeis");
document.write(nowHour+":"+nowMinute+":"+nowSecond);
SettingTimeValuesWhenyouwanttosetthetimeinyourDateobjects,youhaveaseriesofmethodssimilartothoseusedforgettingthetime:
setHours()
setMinutes()
setSeconds()
setMilliseconds()
Theseworkmuchlikethemethodsyouusetosetthedate,inthatifyousetanyofthetimeparameterstoanillegalvalue,JavaScriptassumesyoumeanthenextorprevioustimeboundary.Ifit’s9:57andyousetminutesto64,thetimewillbesetto10:04—thatis,64minutesfrom9:00.
Thisisdemonstratedinthefollowingcode:
varnowDate=newDate();
nowDate.setHours(9);
nowDate.setMinutes(57);
alert(nowDate);
nowDate.setMinutes(64);
alert(nowDate);
FirstyoudeclarethenowDatevariableandassignittoanewDateobject,whichwillcontainthecurrentdateandtime.Inthefollowingtwolines,yousetthehoursto9andthe
minutesto57.Youshowthedateandtimeusinganalertbox,whichshouldshowatimeof9:57.Theminutesarethensetto64andagainanalertboxisusedtoshowthedateandtimetotheuser.Nowtheminuteshaverolledoverthehoursothetimeshownshouldbe10:04.
Ifthehoursweresetto23insteadof9,settingtheminutesto64wouldnotjustmovethetimetoanotherhour,butalsocausethedaytochangetothenextdate.
CREATINGYOUROWNCUSTOMOBJECTSWe’vespentalotoftimediscussingobjectsbuiltintoJavaScript,butJavaScript’srealpowercomesfromthefactthatyoucancreateyourownobjectstorepresentcomplexdata.Forexample,imaginethatyouneedtorepresentanindividualpersoninyourcode.Youcouldsimplyusetwovariablesforanindividualperson’sfirstnameandlastname,likethis:
varfirstName="John";
varlastName="Doe";
Butwhatifyouneededtorepresentmultiplepeople?Creatingtwovariablesforeverypersonwouldgetunwieldyveryquickly,andkeepingtrackofeveryvariableforeverypersonwouldcauseheadachesforeventhebestprogrammersintheworld.Instead,youcouldcreateanobjecttorepresenteachindividualperson.Eachoftheseobjectswouldcontainthenecessaryinformationthatmakesonepersonuniquefromother(suchasaperson’sfirstandlastnames).
TocreateanobjectinJavaScript,simplyusethenewoperatorinconjunctionwiththeObjectconstructor,likethis:
varjohnDoe=newObject();
Butlikearrays,JavaScriptprovidesaliteralsyntaxtosignifyanobject:apairofcurlybraces({}).Soyoucanrewritethepreviouscodelikethis:
varjohnDoe={};
Today’sJavaScriptdevelopersfavorthisliteralsyntaxinsteadofcallingtheObjectconstructor.
Onceyouhaveanobject,youcanbegintopopulateitwithproperties.Itissimilartocreatingavariable,exceptyoudonotusethevarkeyword.Simplyusethenameoftheobject,followedbyadot,thenthenameoftheproperty,andassignitavalue.Forexample:
johnDoe.firstName="John";
johnDoe.lastName="Doe";
ThesetwolinesofcodecreatethefirstNameandlastNamepropertiesonthejohnDoeobjectandassigntheirrespectivevalues.JavaScriptdoesnotcheckifthesepropertiesexistbeforethey’recreated;itsimplycreatesthem.Thisfreepropertycreationmightsoundgreat(anditis!),butitdoeshavedrawbacks.TheprimaryissueisthatJavaScriptwon’ttellyouifyouaccidentallymisspellapropertyname;it’lljustcreateanewpropertywiththemisspelledname,somethingthatcanmakeitdifficulttotrackbugs.Soalwaysbecarefulwhencreatingproperties.
Youcanassignmethodsinthesameway,exceptyouassignafunctioninsteadofanothertypeofvalue,likethis:
johnDoe.greet=function(){
alert("Mynameis"+this.firstName+""+this.lastName;
};
Thiscodecreatesamethodcalledgreet(),whichsimplyalertsagreeting.Afewimportantthingsareimportanttonoteinthiscode.
First,noticethereisnonamebetweenfunctionand().Afunctionthathasnonameiscalledananonymousfunction.Anonymousfunctions,inandofthemselves,areasyntaxerrorunlessyouassignthatfunctiontoavariable.Onceyouassignananonymousfunctiontoavariable,thatfunction’snamebecomesthenameofthevariable.SoyoucanexecutetheanonymousfunctionassignedtojohnDoe.greetlikethis:
johnDoe.greet();
Next,noticetheuseofthisinsideofthefunction:this.firstNameandthis.lastName.InJavaScript,thisisaspecialvariablethatreferstothecurrentobject—thejohnDoeobjectinthiscase.Itliterallymeans“thisobject.”Soyoucouldrewritegreet()likethefollowing:
johnDoe.greet=function(){
alert("Mynameis"+johnDoe.firstName+""+johnDoe.lastName;
};
However,youwon’talwayshavethenameofobjecttouseinplaceofthis.Therefore,itispreferredtorefertothecurrentobjectinsideofamethodbyusingthisratherthantheactualnameoftheobject.
ThefullcodeforcreatingthisjohnDoeobjectlookslikethis:
varjohnDoe={};
johnDoe.firstName="John";
johnDoe.lastName="Doe";
johnDoe.greet=function(){
alert("Mynameis"+johnDoe.firstName+""+johnDoe.lastName;
};
ThisisperfectlyvalidJavaScript,butittakesfourstatementstocreatethecompleteobject.Thesefourstatementscanbereducedtoonestatementbydefiningtheentireobjectusingliteralnotation.Admittedly,itwilllookalittleweirdatfirst,butyou’llsoongetusedtoit:
varjohnDoe={
firstName:"John",
lastName:"Doe",
greet:function(){
alert("Mynameis"+
this.firstName+""+
this.lastName;
}
};
Takeamomentandstudythiscode.First,noticethiscodeusescurlybracestoenclosethe
entireobject.Thennoticethateachpropertyandmethodisdefinedbyspecifyingthenameoftheproperty/method,followedbyacolon,andthenitsvalue.So,assigningthefirstNamepropertylookslikethis:
firstName:"John"
Thereisnoequalsignusedhere.Inobjectliteralnotation,thecolonsetsthevalueoftheproperty.
Finally,noticethateachpropertyandmethoddefinitionisseparatedbyacomma—verymuchlikehowyouseparateindividualelementsinanarrayliteral.
TRYITOUTUsingObjectLiteralsItisveryimportantforyoutounderstandobjectliterals—theyareusedextremelyliberallybyJavaScriptdevelopers.Let’slookatanexamplethatusesafunctiontocreateacustomobject:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Example8</title>
</head>
<body>
<script>
functioncreatePerson(firstName,lastName){
return{
firstName:firstName,
lastName:lastName,
getFullName:function(){
returnthis.firstName+""+this.lastName
},
greet:function(person){
alert("Hello,"+person.getFullName()+
".I'm"+this.getFullName());
}
};
}
varjohnDoe=createPerson("John","Doe");
varjaneDoe=createPerson("Jane","Doe");
johnDoe.greet(janeDoe);
</script>
</body>
</html>
Savethispageasch5_example8.html.Whenyouloadthepageintoawebbrowser,itdisplaysthemessage:"Hello,JaneDoe.I'mJohnDoe".
First,thiscodecreatesafunctioncalledcreatePerson()thatacceptsaperson’sfirstandlastnamesasparameters.Thisfunctioncreatesanobjectwiththeperson’sfirst
andlastnamesusingobjectliteralnotation:
functioncreatePerson(firstName,lastName){
return{
ThefirstpropertycreatedisthefirstNameproperty,anditisassignedthevalueofthefirstNameparameter:
firstName:firstName,
NextisthelastNameproperty,whichreceivesitsvaluefromthecreatePerson()function’slastNameparameter:
lastName:lastName,
ThenamethodcalledgetFullName()iscreated.Itspurposeistoreturnthefirstandlastnameofthepersontothecaller:
getFullName:function(){
returnthis.firstName+""+this.lastName
},
Thismethodusesthethisvariabletoaccessthisobject’sfirstNameandlastNameproperties.Notethatthethisvariableistheonlywaytoretrievetheseproperties—theobjectdoesn’thaveaname;itisananonymousobjectthatiscreatedandthenreturnedtothecaller.
Thefinalmethodofthisobjectisgreet().ItacceptsanotherpersonobjectasaparameterandusesitsgetFullName()inordertogreetthatperson:
greet:function(person){
alert("Hello,"+person.getFullName()+
".I'm"+this.getFullName());
}
};
}
Thenexttwolinescreatetwoobjectstworepresenttwoindividualpeople:
varjohnDoe=createPerson("John","Doe");
varjaneDoe=createPerson("Jane","Doe");
Noticetheabsenceofthenewkeyword.ThecreatePerson()functionisnotaconstructorfunction(youlearnhowtowriteconstructorfunctionslater).It’ssimplyafunctionthatcreatesandreturnsanobject.
Finally,JohnDoegreetsJaneDoebycallingthegreet()methodandpassingthejaneDoeobjecttoit:
johnDoe.greet(janeDoe);
CREATINGNEWTYPESOFOBJECTS(REFERENCETYPES)Thissection’sfocusisonsomeadvancedstuff.It’snotessentialstuff,soyoumaywanttomoveonandcomebacktoitlater.
You’veseenthatJavaScriptprovidesanumberofobjectsbuiltintothelanguageandreadyforustouse.You’vealsobuiltcustomobjectsthatyoucanusetorepresentmorecomplexdata,butJavaScriptalsoenablesyoutocreateyourowntypeofobjects.Forexample,youcreatedanobjectthatrepresentedanindividualperson,butyoucanalsocreateanobjectthatisaPersonobject.
It’sabitlikeahousethat’sbuiltalreadyandyoucanjustmoveonin.However,whatifyouwanttocreateyourownhouse,todesignitforyourownspecificneeds?Inthatcaseyou’lluseanarchitecttocreatetechnicaldrawingsandplansthatprovidethetemplateforthenewhouse—thebuildersusetheplanstotellthemhowtocreatethehouse.
SowhatdoesanyofthishavetodowithJavaScriptandobjects?Well,JavaScriptenablesyoutobeanarchitectandcreatethetemplatesforyourownobjectstoyourownspecification,tofityourspecificneeds.Goingbacktothepersonobjectexample,JavaScriptdoesn’tcomewithbuilt-inpersonobjects,soyou’dhavetodesignyourown.
Justasabuilderofahouseneedsanarchitect’splanstoknowwhattobuildandhowitshouldbelaidout,youneedtoprovideblueprintstellingJavaScripthowyourobjectshouldlook.YousomewhatdidthiswiththecreatePerson()functioninch5 _ example8.html,butyouonlycreatedplainobjectswithcustompropertiesandmethods—youdidn’tcreateanactualPersonobject.
ButJavaScriptsupportsthedefinitionofreferencetypes.Referencetypesareessentiallytemplatesforanobject,asthearchitect’sdrawingsarethetemplateusedtobuildahouse.Beforeyoucanuseyournewobjecttype,youneedtodefineitalongwithitsmethodsandproperties.Theimportantdistinctionisthatwhenyoudefineyourreferencetype,noobjectbasedonthattypeiscreated.It’sonlywhenyoucreateaninstanceofyourreferencetypeusingthenewkeywordthatanobjectofthattype,basedonyourblueprintorprototype,iscreated.
Beforeyoustart,animportantdistinctionmustbemade.Manydevelopersrefertoreferencetypesasclassesandusethetwotermsinterchangeably.Althoughthisiscorrectformanyobject-orientedlanguagessuchasJava,C#,andC++,itisnotcorrectforJavaScript.JavaScriptdoesnotyetsupportaclassconstruct,althoughthenextversionofJavaScriptwillprovideformalclasses.JavaScriptdoes,however,fullysupportthelogicalequivalent,referencetypes.
It’salsoimportanttopointoutthatthebuilt-inobjectsdiscussedthusfarinthischapterarealsoreferencetypes.String,Array,Number,Date,andevenObjectareallreferencetypes,andtheobjectsyoucreatedareinstancesofthesetypes.
Areferencetypeconsistsofthreethings:
Aconstructor
Methoddefinitions
Properties
Aconstructorisafunctionthatiscalledeverytimeoneofyourobjectsbasedonthisreferencetypeiscreated.It’susefulwhenyouwanttoinitializepropertiesortheobjectinsomeway.Youneedtocreateaconstructorevenifyoudon’tpassanyparameterstoitorifitcontainsnocode.(Inthatcaseit’djustbeanemptydefinition.)Aswithallfunctions,aconstructorcanhavezeroormoreparameters.
You’vecreatedobjectstorepresentindividualpeople.Nextyoucreateasimplereference,calledPerson,todothesamething—exceptthattheseobjectswillbeactualPersonobjects.
DefiningaReferenceTypeThefirstthingyouneedtodoiscreatetheconstructor,whichisshownhere:
functionPerson(firstName,lastName){
this.firstName=firstName;
this.lastName=lastName;
}
Yourfirstthoughtmightbethatwhatyouhavehereissimplyafunction,andyou’dberight.It’snotuntilyoustartdefiningthepropertiesandmethodsthatitbecomessomethingmorethanafunction.Thisisincontrasttosomeprogramminglanguages,whichhaveamoreformalwayofdefiningtypes.
NOTETypically,areferencetypeisdefinedwithanuppercaseletter.Doingsomakesiteasytodifferentiateafunctionfromareferencetypeeasilyandquickly.
Insidethefunction,noticetheuseofthethisvariable.Onceagain,itliterallymeans“thisobject,”anditistheonlywaytoaccesstheobjectthatisbeingcreated.SotocreatethefirstNameandlastNameproperties,youwritethefollowingcode:
this.firstName=firstName;
this.lastName=lastName;
NowyouneedtodefinegetFullName()andgreet()methods.Youcandefinetheminsideoftheconstructor,butitismoreefficienttodefinethemonPerson’sprototype,likethis:
Person.prototype.getFullName=function(){
returnthis.firstName+""+this.lastName;
};
Person.prototype.greet=function(person){
alert("Hello,"+person.getFullName()+
".I'm"+this.getFullName());
};
ThefirstthingyounoticeisPerson.prototype.RememberfromChapter4thatfunctions
areobjectsinJavaScript,andinthischapteryoulearnedthatobjectshavepropertiesandmethods.Soit’seasytoassumethatfunctionshavepropertiesandmethods.
Everyfunctionobjecthasaprototypeproperty,butitisonlyusefulforconstructorfunctions.YoucanthinkofthePerson.prototypepropertyasanactualprototypeforPersonobjects.AnypropertiesandmethodsyouassigntoPerson.prototypeareusableonallPersonobjects.Infact,they’remorethanusable—they’reshared!
ThefunctionsassignedtoPerson.prototype.getFullNameandPerson.prototype.greetaresharedbetweenallobjects,orinstances,ofPerson.ThismeansthatthefunctionobjectofonePersonobject’sgetFullNameistheexactsamefunctionobjectonanotherPersonobject’sgetFullName.Toexpressthatincode:
varareSame=person1.getFullName==person2.getFullName;//true
ButwhywerefirstNameandlastNameassignedintheconstructorinsteadofPerson.prototype?ThefirstNameandlastNamepropertiesarecalledinstancedata.Instancedataisuniquetoeachindividualobject,orinstance.SobecausefirstNameandlastNameareinstancedata,wedefinethemintheconstructor—theyshouldn’tbesharedbetweenallPersonobjects.
CreatingandUsingReferenceTypeInstancesYoucreateinstancesofyourreferencetypeinthesamewayyoucreatedinstancesofJavaScript’sbuilt-intypes:usingthenewkeyword.SotocreateanewinstanceofPerson,you’dwritethis:
varjohnDoe=newPerson("John","Doe");
varjaneDoe=newPerson("Jane","Doe");
Here,aswithaDateobject,youhavecreatedtwonewobjectsandstoredtheminvariables,johnDoeandjaneDoe,butthistimeit’sanewobjectbasedonthePersontype.
NOTETheuseofthenewkeywordisveryimportantwhencreatinganobjectwithaconstructor.Thebrowserdoesnotthrowanerrorifyoudonotusethenewkeyword,butyourscriptwillnotworkcorrectly.Insteadofcreatinganewobject,youactuallyaddpropertiestotheglobalwindowobject.Theproblemscausedbynotusingthenewkeywordcanbehardtodiagnose,somakesureyouspecifythenewkeywordwhencreatingobjectswithaconstructor.
Youusetheseobjectsjustlikeyoudidinch5 _ example8.html.Inthefollowingcode,JaneDoegreetsJohnDoe:
janeDoe.greet(johnDoe);
EventhoughgetFullName()andgreet()aredefinedonPerson.prototype,youstillcallthemlikenormalmethods.JavaScriptisintelligentenoughtolookatPerson.prototypeforthosemethods.
Nowforthemilliondollarquestion:Whydefineareferencetypeinsteadofcreatingplain,
butcustom,objects?It’savalidquestion.Boththeobjectscreatedinch5_example8.htmlandfromthePersonconstructorservethesamepurpose:torepresentanindividualperson.Themaindifferenceishowtheobjectsarecreated.Objectscreatedfromaconstructortypicallyconsumelessofthecomputer’smemorythanliteralobjects.
Frankly,it’saquestionyoudon’thavetoworryaboutatthispointintime.It’smoreimportanttoknowhowtocreateobjectsthanusingthecorrectapproach.Sopracticebothmethods;createyourowncustomobjectsandreferencetypes!
SUMMARYInthischapteryou’vetakenalookattheconceptofobjectsandseenhowvitaltheyaretoanunderstandingofJavaScript,whichrepresentsvirtuallyeverythingwithobjects.YoualsolookedatsomeofthevariousnativereferencetypesthattheJavaScriptlanguageprovidestoaddtoitsfunctionality.
Yousawthat:
JavaScriptisobject-based—itrepresentsthings,suchasstrings,dates,andarrays,usingtheconceptofobjects.
Objectshavepropertiesandmethods.Forexample,anArrayobjecthasthelengthpropertyandthesort()method.
Tocreateanewobject,yousimplywritenewObjectType().Youcanchoosetoinitializeanobjectwhenyoucreateit.
Tosetanobject’spropertyvalueorgetthatvalue,yousimplywriteobjectName.objectProperty.
Callingthemethodsofanobjectissimilartocallingfunctions.Parametersmaybepassed,andreturnvaluesmaybepassedback.Accessingthemethodsofanobjectisidenticaltoaccessingaproperty,exceptthatyoumustremembertoaddparenthesesattheend,evenwhenithasnoparameters.Forexample,youwouldwriteobjectName.objectMethod().
TheStringtypeprovideslotsofhandyfunctionalityfortextandgivesyouwaysoffindingouthowlongthetextis,searchingfortextinsidethestring,andselectingpartsofthetext.
TheMathtypeiscreatedautomaticallyandprovidesanumberofmathematicalpropertiesandmethods.Forexample,toobtainarandomnumberbetween0and1,youusethemethodMath.random().
TheArraytypeprovideswaysofmanipulatingarrays.Someofthethingsyoucandoarefindthelengthofanarray,sortitselements,andjointwoarraystogether.
TheDatetypeprovidesawayofstoring,calculatingwith,andlateraccessingdatesandtimes.
JavaScriptletsyoucreateyourowncustomobjects,givingthemthepropertiesandmethodsthatyouwantthemtohave.
JavaScriptenablesyoutocreateyourowntypesofobjectsusingreferencetypes.Thesecanbeusedtomodelreal-worldsituationsandformakingcodeeasiertocreateandmoremaintainable,thoughtheydorequireextraeffortatthestart.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. UsingtheDatetype,calculatethedate12monthsfromnowandwritethisintoawebpage.
2. Obtainalistofnamesfromtheuser,storingeachnameenteredinanarray.Keepgettinganothernameuntiltheuserentersnothing.Sortthenamesinascendingorderandthenwritethemouttothepage,witheachnameonitsownline.
3. ch5_example8.htmlusesafunctiontocreateobjectsusingliteralnotation.ModifythisexampletousethePersondatatype.
6StringManipulationWHATYOUWILLLEARNINTHISCHAPTER:
UsingtheStringobject’sadvancedmethodstomanipulatestrings
Matchingsubstringsfollowaspecificpattern
Validatingusefulpiecesofinformation,suchastelephonenumbers,e-mailaddresses,andpostalcodes
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
InChapter5youlookedattheStringobject,whichisoneofthenativeobjectsthatJavaScriptmakesavailabletoyou.Yousawanumberofitspropertiesandmethods,includingthefollowing:
length—Thelengthofthestringincharacters
charAt()andcharCodeAt()—Themethodsforreturningthecharacterorcharactercodeatacertainpositioninthestring
indexOf()andlastIndexOf()—Themethodsthatallowyoutosearchastringfortheexistenceofanotherstringandthatreturnthecharacterpositionofthestringiffound
substr()andsubstring()—Themethodsthatreturnjustaportionofastring
toUpperCase()andtoLowerCase()—Themethodsthatreturnastringconvertedtoupper-orlowercase
InthischapteryoulookatfournewmethodsoftheStringobject,namelysplit(),match(),replace(),andsearch().Thelastthree,inparticular,giveyousomeverypowerfultext-manipulationfunctionality.However,tomakefulluseofthisfunctionality,youneedtolearnaboutaslightlymorecomplexsubject.
Themethodssplit(),match(),replace(),andsearch()canallmakeuseofregularexpressions,somethingJavaScriptwrapsupinanobjectcalledtheRegExpobject.Regularexpressionsenableyoutodefineapatternofcharacters,whichyoucanusefortextsearchingorreplacement.Say,forexample,thatyouhaveastringinwhichyouwanttoreplaceallsinglequotesenclosingtextwithdoublequotes.Thismayseemeasy—justsearchthestringfor'andreplaceitwith"—butwhatifthestringisBobO'Harasaid"Hello"?Youwouldnotwanttoreplacethesingle-quotecharacterinO'Hara.Youcanperformthistextreplacementwithoutregularexpressions,butitwouldtakemorethanthetwolinesofcodeneededifyoudouseregularexpressions.
Althoughsplit(),match(),replace(),andsearch()areattheirmostpowerfulwithregularexpressions,theycanalsobeusedwithjustplaintext.Youtakealookathowtheyworkinthissimplercontextfirst,tobecomefamiliarwiththemethods.
ADDITIONALSTRINGMETHODSInthissectionyoutakealookatthesplit(),replace(),search(),andmatch()methods,andseehowtheyworkwithoutregularexpressions.
Thesplit()MethodTheStringobject’ssplit()methodsplitsasinglestringintoanarrayofsubstrings.Wherethestringissplitisdeterminedbytheseparationparameterthatyoupasstothemethod.Thisparameterissimplyacharacterortextstring.
Forexample,tosplitthestring"A,B,C"sothatyouhaveanarraypopulatedwiththelettersbetweenthecommas,thecodewouldbeasfollows:
varmyString="A,B,C";
varmyTextArray=myString.split(",");
JavaScriptcreatesanarraywiththreeelements.InthefirstelementitputseverythingfromthestartofthestringmyStringuptothefirstcomma.Inthesecondelementitputseverythingfromafterthefirstcommatobeforethesecondcomma.Finally,inthethirdelementitputseverythingfromafterthesecondcommatotheendofthestring.So,yourarraymyTextArraywilllooklikethis:
ABC
If,however,yourstringwere"A,B,C,"JavaScriptwouldsplititintofourelements,thelastelementcontainingeverythingfromthelastcommatotheendofthestring;inotherwords,thelaststringwouldbeanemptystring:
ABC
Thisissomethingthatcancatchyouoffguardifyou’renotawareofit.
TRYITOUTReversingtheOrderofTextLet’screateashortexampleusingthesplit()method,inwhichyoureversethelineswrittenina<textarea>element:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example1</title>
</head>
<body>
<script>
varvalues=prompt("Pleaseenterasetofcommaseparated
values.",
"Apples,Oranges,Bananas");
functionsplitAndReverseText(csv){
varparts=csv.split(",");
parts.reverse();
varreversedString=parts.join(",");
alert(reversedString);
}
splitAndReverseText(values);
</script>
</body>
</html>
Savethisasch6 _ example1.htmlandloaditintoyourbrowser.Usethedefaultvalueinthepromptbox,clickOK,andyoushouldseethescreenshowninFigure6.1.
Figure6.1
Tryothercomma-separatedvaluestotestitfurther.
ThekeytohowthiscodeworksisthefunctionsplitAndReverseText().Itacceptsastringvaluethatshouldcontainoneormorecommas.Youstartbysplittingthevaluecontainedwithincsvusingthesplit()methodandputtingtheresultingarrayinsidethepartsvariable:
functionsplitAndReverseText(csv){
varparts=csv.split(",");
Thisusesacommaastheseparator.YouthenreversethearrayofstringpartsusingtheArrayobject’sreverse()method:
parts.reverse();
Withthearraynowreversed,it’sjustasimplematterofcreatingthenewstring.YoucaneasilyaccomplishthiswiththeArrayobject’sjoin()method:
varreversedString=parts.join(",");
RememberfromChapter5thatthejoin()methodconvertsanarrayintoastring,separatingeachelementwiththespecifiedseparator.
Finally,youdisplaythenewstringinanalertbox:
alert(reversedString);
}
Afteryou’velookedatregularexpressions,you’llrevisitthesplit()method.
Thereplace()MethodThereplace()methodsearchesastringforoccurrencesofasubstring.Whereitfindsamatchforthissubstring,itreplacesthesubstringwithathirdstringthatyouspecify.
Let’slookatanexample.SayyouhaveastringwiththewordMayinit,asshowninthefollowing:
varmyString="TheeventwillbeinMay,the21stofJune";
Now,sayyouwanttoreplaceMaywithJune.Youcanusethereplace()methodlikeso:
VarmyCleanedUpString=myString.replace("May","June");
ThevalueofmyStringwillnotbechanged.Instead,thereplace()methodreturnsthevalueofmyStringbutwithMayreplacedwithJune.YouassignthisreturnedstringtothevariablemyCleanedUpString,whichwillcontainthecorrectedtext:
"TheeventwillbeinJune,the21stofJune"
Thesearch()MethodThesearch()methodenablesyoutosearchastringforaparticularpieceoftext.Ifthetextisfound,thecharacterpositionatwhichitwasfoundisreturned;otherwise,-1isreturned.Themethodtakesonlyoneparameter,namelythetextyouwanttosearchfor.
Whenusedwithplaintext,thesearch()methodprovidesnorealbenefitovermethodslikeindexOf(),whichyou’vealreadyseen.However,youseelaterthatthepowerofthismethodbecomesapparentwhenyouuseregularexpressions.
Inthefollowingexample,youwanttofindoutifthewordJavaiscontainedwithinthestringcalledmyString:
varmyString="BeginningJavaScript,BeginningJava,"+
"ProfessionalJavaScript";
alert(myString.search("Java"));
Thealertboxthatoccurswillshowthevalue10,whichisthecharacterpositionoftheJinthefirstoccurrenceofJava,aspartofthewordJavaScript.
Thematch()MethodThematch()methodisverysimilartothesearch()method,exceptthatinsteadofreturningthepositionatwhichamatchwasfound,itreturnsanarray.Eachelementofthearraycontainsthetextofeachmatchthatisfound.
Althoughyoucanuseplaintextwiththematch()method,itwouldbecompletelypointlesstodoso.Forexample,takealookatthefollowing:
varmyString="1997,1998,1999,2000,2000,2001,2002";
myMatchArray=myString.match("2000");
alert(myMatchArray.length);
ThiscoderesultsinmyMatchArrayholdinganelementcontainingthevalue2000.Giventhatyoualreadyknowyoursearchstringis2000,youcanseeit’sbeenaprettypointlessexercise.
However,thematch()methodmakesalotmoresensewhenyouuseitwithregularexpressions.Thenyoumightsearchforallyearsinthetwenty-firstcentury—thatis,thosebeginningwith2.Inthiscase,yourarraywouldcontainthevalues2000,2000,2001,and2002,whichismuchmoreusefulinformation!
REGULAREXPRESSIONSBeforeyoulookatthesplit(),match(),search(),andreplace()methodsoftheStringobjectagain,youneedtolookatregularexpressionsandtheRegExpobject.Regularexpressionsprovideameansofdefiningapatternofcharacters,whichyoucanthenusetosplit,searchfor,orreplacecharactersinastringwhentheyfitthedefinedpattern.
JavaScript’sregularexpressionsyntaxborrowsheavilyfromtheregularexpressionsyntaxofPerl,anotherscriptinglanguage.Mostmodernprogramminglanguagessupportregularexpressions,asdolotsofapplications,suchasWebMatrix,SublimeText,andDreamweaver,inwhichtheFindfacilityallowsregularexpressionstobeused.You’llfindthatyourregularexpressionknowledgewillproveusefulevenoutsideJavaScript.
RegularexpressionsinJavaScriptareusedthroughtheRegExpobject,whichisanativeJavaScriptobject,asareString,Array,andsoon.YouhavetwowaysofcreatinganewRegExpobject.Theeasieriswitharegularexpressionliteral,suchasthefollowing:
varmyRegExp=/\b'|'\b/;
Theforwardslashes(/)markthestartandendoftheregularexpression.ThisisaspecialsyntaxthattellsJavaScriptthatthecodeisaregularexpression,muchasquotemarksdefineastring’sstartandend.Don’tworryabouttheactualexpression’ssyntaxyet(the\b'|'\b)—thatisexplainedindetailshortly.
Alternatively,youcouldusetheRegExpobject’sconstructorfunctionRegExp()andtypethefollowing:
varmyRegExp=newRegExp("\\b'|'\\b");
Eitherwayofspecifyingaregularexpressionisfine,thoughtheformermethodisashorter,moreefficientoneforJavaScripttouseandthereforeisgenerallypreferred.Formuchoftheremainderofthechapter,youusethefirstmethod.Themainreasonforusingthesecondmethodisthatitallowstheregularexpressiontobedeterminedatruntime(asthecodeisexecutingandnotwhenyouarewritingthecode).Thisisusefulif,forexample,youwanttobasetheregularexpressiononuserinput.
Onceyougetfamiliarwithregularexpressions,youwillcomebacktothesecondwayofdefiningthem,usingtheRegExp()constructor.Asyoucansee,thesyntaxofregularexpressionsisslightlydifferentwiththesecondmethod,sowe’llreturntothissubjectlater.
Althoughyou’llbeconcentratingontheuseoftheRegExpobjectasaparameterfortheStringobject’ssplit(),replace(),match(),andsearch()methods,theRegExpobjectdoeshaveitsownmethodsandproperties.Forexample,thetest()methodenablesyoutotesttoseeifthestringpassedtoitasaparametercontainsapatternmatchingtheonedefinedintheRegExpobject.Youseethetest()methodinuseinanexampleshortly.
SimpleRegularExpressions
Definingpatternsofcharactersusingregularexpressionsyntaxcangetfairlycomplex.Inthissectionyouexplorejustthebasicsofregularexpressionpatterns.Thebestwaytodothisisthroughexamples.
Let’sstartbylookingatanexampleinwhichyouwanttodoasimpletextreplacementusingthereplace()methodandaregularexpression.Imagineyouhavethefollowingstring:
varmyString="Paul,Paula,Pauline,paul,Paul";
andyouwanttoreplaceanyoccurrenceofthename“Paul”with“Ringo.”
Well,thepatternoftextyouneedtolookforissimplyPaul.Representingthisasaregularexpression,youjusthavethis:
varmyRegExp=/Paul/;
Asyousawearlier,theforward-slashcharactersmarkthestartandendoftheregularexpression.Nowlet’susethisexpressionwiththereplace()method:
myString=myString.replace(myRegExp,"Ringo");
Youcanseethatthereplace()methodtakestwoparameters:theRegExpobjectthatdefinesthepatterntobesearchedandreplaced,andthereplacementtext.
Ifyouputthisalltogetherinanexample,youhavethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Figure2</title>
</head>
<body>
<script>
varmyString="Paul,Paula,Pauline,paul,Paul";
varmyRegExp=/Paul/;
myString=myString.replace(myRegExp,"Ringo");
alert(myString);
</script>
</body>
</html>
Youcansaveandrunthiscode.YouwillseethescreenshowninFigure6.2.
Figure6.2
YoucanseethatthishasreplacedthefirstoccurrenceofPaulinyourstring.ButwhatifyouwantedalltheoccurrencesofPaulinthestringtobereplaced?Thetwoatthefarendofthestringarestillthere,sowhathappened?
Bydefault,theRegExpobjectlooksonlyforthefirstmatchingpattern,inthiscasethefirstPaul,andthenstops.ThisisacommonandimportantbehaviorforRegExpobjects.Regularexpressionstendtostartatoneendofastringandlookthroughthecharactersuntilthefirstcompletematchisfound,thenstop.
Whatyouwantisaglobalmatch,whichisasearchforallpossiblematchestobemadeandreplaced.Tohelpyouout,theRegExpobjecthasthreeattributesyoucandefine,aslistedinthefollowingtable:
ATTRIBUTECHARACTER
DESCRIPTION
G Globalmatch.Thislooksforallmatchesofthepatternratherthanstoppingafterthefirstmatchisfound.
I Patterniscase-insensitive.Forexample,Paulandpaulareconsideredthesamepatternofcharacters.
M Multi-lineflag.Thisspecifiesthatthespecialcharacters^and$canmatchthebeginningandtheendoflinesaswellasthebeginningandendofthestring.
Youlearnmoreabouttheseattributecharacterslaterinthechapter.
IfyouchangetheRegExpobjectinthecodetothefollowing,aglobalcase-insensitivematchwillbemade:
varmyRegExp=/Paul/gi;
RunningthecodenowproducestheresultshowninFigure6.3.
Figure6.3
Thislooksasifithasallgonehorriblywrong.TheregularexpressionhasmatchedthePaulsubstringsatthestartandtheendofthestring,andthepenultimatepaul,justasyouwanted.However,thePaulsubstringsinsidePaulineandPaulahavealsobeenreplaced.
TheRegExpobjecthasdoneitsjobcorrectly.YouaskedforallpatternsofthecharactersPaultobereplacedandthat’swhatyougot.WhatyouactuallymeantwasforalloccurrencesofPaul,whenit’sasinglewordandnotpartofanotherword,suchasPaula,tobereplaced.Thekeytomakingregularexpressionsworkistodefineexactlythepatternofcharactersyoumean,sothatonlythatpatterncanmatchandnoother.Solet’sdothat.
1. YouwantpaulorPaultobereplaced.
2. Youdon’twantitreplacedwhenit’sactuallypartofanotherword,asinPauline.
Howdoyouspecifythissecondcondition?Howdoyouknowwhenthewordisjoinedtoothercharacters,ratherthanjustjoinedtospacesorpunctuationorthestartorendofthestring?
Toseehowyoucanachievethedesiredresultwithregularexpressions,youneedtoenlistthehelpofregularexpressionspecialcharacters.Youlookattheseinthenextsection,bytheendofwhichyoushouldbeabletosolvetheproblem.
RegularExpressions:SpecialCharactersYoulookatthreetypesofspecialcharactersinthissection.
Text,Numbers,andPunctuationThefirstgroupofspecialcharacterscontainsthecharacterclass’sspecialcharacters.
Characterclassmeansdigits,letters,andwhitespacecharacters.Thespecialcharactersaredisplayedinthefollowingtable:
CHARACTERCLASS
CHARACTERSITMATCHES EXAMPLE
\d Anydigitfrom0to9 \d\dmatches72,butnotaaor7a.
\D Anycharacterthatisnotadigit \D\D\Dmatchesabc,butnot123or8ef.
\w Anywordcharacter;thatis,A–Z,a–z,0–9,andtheunderscorecharacter(_)
\w\w\w\wmatchesAb_2,butnot£$%*orAb_@.
\W Anynon-wordcharacter \Wmatches@,butnota.\s Anywhitespacecharacter \smatchestab,return,
formfeed,andverticaltab.\S Anynon-whitespacecharacter \SmatchesA,butnotthe
tabcharacter.. Anysinglecharacterotherthanthenewline
character(\n).matchesaor4or@.
[...] Anyoneofthecharactersbetweenthebrackets[a-z]matchesanycharacterintherangeatoz
[abc]matchesaorborc,butnothingelse.
[^...] Anyonecharacter,butnotoneofthoseinsidethebrackets
[^abc]matchesanycharacterexceptaorborc.
[^a-z]matchesanycharacterthatisnotintherangeatoz
.
Notethatuppercaseandlowercasecharactersmeanverydifferentthings,soyouneedtobeextracarefulwithcasewhenusingregularexpressions.
Let’slookatanexample.Tomatchatelephonenumberintheformat1-800-888-5474,theregularexpressionwouldbeasfollows:
\d-\d\d\d-\d\d\d-\d\d\d\d
Youcanseethatthere’salotofrepetitionofcharactershere,whichmakestheexpressionquiteunwieldy.Tomakethissimpler,regularexpressionshaveawayofdefiningrepetition.Youseethisalittlelaterinthechapter,butfirstlet’slookatanotherexample.
TRYITOUTCheckingaPassphraseforAlphanumericCharactersYouusewhatyou’velearnedsofaraboutregularexpressionsinafullexampleinwhichyoucheckthatapassphrasecontainsonlylettersandnumbers—thatis,alphanumericcharacters,notpunctuationorsymbolslike@,%,andsoon:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example2</title>
</head>
<body>
<script>
varinput=prompt("Pleaseenterapassphrase.","");
functionisValid(text){
varmyRegExp=/[^a-z\d]/i;
return!(myRegExp.test(text));
}
if(isValid(input)){
alert("Yourpassphrasecontainsonlyvalidcharacters");
}else{
alert("Yourpassphrasecontainsoneormoreinvalid
characters");
}
</script>
</body>
</html>
Savethepageasch6 _ example2.html,andthenloaditintoyourbrowser.Typejustletters,numbers,andspacesintothepromptbox,clickOK,andyou’llbetoldthatthephrasecontainsvalidcharacters.Tryputtingpunctuationorspecialcharacterslike@,^,$,andsoonintothetextbox,andyou’llbeinformedthatyourpassphraseisinvalid.
Let’sstartbylookingattheisValid()function.Asitsnameimplies,itchecksthevalidityofthepassphrase:
functionisValid(text){
varmyRegExp=/[^a-z\d]/i;
return!(myRegExp.test(text));
}
Thefunctiontakesjustoneparameter:thetextyouwanttovalidate.Youthendeclareavariable,myRegExp,andsetittoanewregularexpression,whichimplicitlycreatesanewRegExpobject.
Theregularexpressionitselfisfairlysimple,butfirstthinkaboutwhatpatternyouare
lookingfor.WhatyouwanttofindoutiswhetheryourpassphrasestringcontainsanycharactersthatarenotlettersbetweenAandZorbetweenaandz,numbersbetween0and9,orspaces.Let’sseehowthistranslatesintoaregularexpression:
1. Youusesquarebracketswiththe^symbol:
[^]
Thismeansyouwanttomatchanycharacterthatisnotoneofthecharactersspecifiedinsidethesquarebrackets.
2. Youadda-z,whichspecifiesanycharacterintherangeathroughz:
[^a-z]
Sofar,yourregularexpressionmatchesanycharacterthatisnotbetweenaandz.Notethat,becauseyouaddedtheitotheendoftheexpressiondefinition,you’vemadethepatterncase-insensitive.SoyourregularexpressionactuallymatchesanycharacternotbetweenAandZoraandz.
3. Youadd\dtoindicateanydigitcharacter,oranycharacterbetween0and9:
[^a-z\d]
4. Yourexpressionmatchesanycharacterthatisnotbetweenaandz,AandZ,or0and9.Youdecidethataspaceisvalid,soyouaddthatinsidethesquarebrackets:
[^a-z\d]
Puttingthisalltogether,youhavearegularexpressionthatmatchesanycharacterthatisnotaletter,adigit,oraspace.
5. Onthesecondandfinallineofthefunction,youusetheRegExpobject’stest()methodtoreturnavalue:
return!(myRegExp.test(text));
Thetest()methodoftheRegExpobjectchecksthestringpassedasitsparametertoseeifthecharactersspecifiedbytheregularexpressionsyntaxmatchanythinginsidethestring.Iftheydo,trueisreturned;ifnot,falseisreturned.Yourregularexpressionmatchesthefirstinvalidcharacterfound,soifyougetaresultoftrue,youhaveaninvalidpassphrase.However,it’sabitillogicalforanis _ validfunctiontoreturntruewhenit’sinvalid,soyoureversetheresultreturnedbyaddingtheNOToperator(!).
Previouslyyousawthetwo-linevalidity-checkerfunctionusingregularexpressions.Justtoshowhowmuchmorecodingisrequiredtodothesamethingwithoutregularexpressions,hereisasecondfunctionthatdoesthesamethingasisValid()butwithoutregularexpressions:
functionisValid2(text){
varreturnValue=true;
varvalidChars="abcdefghijklmnopqrstuvwxyz1234567890";
for(varcharIndex=0;charIndex<text.length;charIndex++){
if(validChars.indexOf(text.charAt(charIndex).toLowerCase())<0)
{
returnValue=false;
break;
}
}
returnreturnValue;
}
Thisisprobablyassmallasthenon-regularexpressionversioncanbe,andyetit’sstillseverallineslongerthanisValid().
Theprincipleofthisfunctionissimilartothatoftheregularexpressionversion.Youhaveavariable,validChars,whichcontainsallthecharactersyouconsidertobevalid.YouthenusethecharAt()methodinaforlooptogeteachcharacterinthepassphrasestringandcheckwhetheritexistsinyourvalidCharsstring.Ifitdoesn’t,youknowyouhaveaninvalidcharacter.
Inthisexample,thenon-regularexpressionversionofthefunctionis10lines,butwithamorecomplexproblemyoucouldfindittakes20or30linestodothesamethingaregularexpressioncandoinjustafew.
Backtoyouractualcode:youuseanif…elsestatementtodisplaytheappropriatemessagetotheuser.Ifthepassphraseisvalid,analertboxtellstheuserthatallisfine:
if(isValid(input)){
alert("Yourpassphrasecontainsonlyvalidcharacters");
}
Ifitisn’t,anotheralertboxtellsusersthattheirtextwasinvalid:
else{
alert("Yourpassphrasecontainsoneormoreinvalidcharacters");
}
RepetitionCharactersRegularexpressionsincludesomethingcalledrepetitioncharacters,whichareameansofspecifyinghowmanyofthelastitemorcharacteryouwanttomatch.Thisprovesveryuseful,forexample,ifyouwanttospecifyaphonenumberthatrepeatsacharacteraspecificnumberoftimes.Thefollowingtablelistssomeofthemostcommonrepetitioncharactersandwhattheydo:
SPECIALCHARACTER
MEANING EXAMPLE
{n} Matchnofthepreviousitem. x{2}matchesxx.{n,} Matchnormoreoftheprevious
item.x{2,}matchesxx,xxx,xxxx,xxxxx,andsoon.
{n,m} Matchatleastnandatmostmofthepreviousitem.
x{2,4}matchesxx,xxx,andxxxx.
? Matchthepreviousitemzerooronetime.
x?matchesnothingorx.
+ Matchthepreviousitemoneormoretimes.
x+matchesx,xx,xxx,xxxx,xxxxx,andsoon.
* Matchthepreviousitemzeroormoretimes.
x*matchesnothing,orx,xx,xxx,xxxx,andsoon.
Yousawearlierthattomatchatelephonenumberintheformat1-800-888-5474,theregularexpressionwouldbe\d-\d\d\d-\d\d\d-\d\d\d\d.Let’sseehowthiswouldbesimplifiedwiththeuseoftherepetitioncharacters.
Thepatternyou’relookingforstartswithonedigitfollowedbyadash,soyouneedthefollowing:
\d-
Nextarethreedigitsfollowedbyadash.Thistimeyoucanusetherepetitionspecialcharacters—\d{3}willmatchexactlythree\d,whichistheany-digitcharacter:
\d-\d{3}-
Next,youhavethreedigitsfollowedbyadashagain,sonowyourregularexpressionlookslikethis:
\d-\d{3}-\d{3}-
Finally,thelastpartoftheexpressionisfourdigits,whichis\d{4}:
\d-\d{3}-\d{3}-\d{4}
You’ddeclarethisregularexpressionlikethis:
varmyRegExp=/\d-\d{3}-\d{3}-\d{4}/
Rememberthatthefirst/andlast/tellJavaScriptthatwhatisinbetweenthosecharactersisaregularexpression.JavaScriptcreatesaRegExpobjectbasedonthisregularexpression.
Asanotherexample,whatifyouhavethestringPaulPaulaPauline,andyouwanttoreplacePaulandPaulawithGeorge?Todothis,youwouldneedaregularexpressionthatmatchesbothPaulandPaula.
Let’sbreakthisdown.YouknowyouwantthecharactersPaul,soyourregularexpression
startsas:
Paul
NowyoualsowanttomatchPaula,butifyoumakeyourexpressionPaula,thiswillexcludeamatchonPaul.Thisiswherethespecialcharacter?comesin.Itenablesyoutospecifythatthepreviouscharacterisoptional—itmustappearzero(notatall)oronetime.So,thesolutionis:
Paula?
whichyou’ddeclareas:
varmyRegExp=/Paula?/
PositionCharactersThethirdgroupofspecialcharactersincludesthosethatenableyoutospecifyeitherwherethematchshouldstartorendorwhatwillbeoneithersideofthecharacterpattern.Forexample,youmightwantyourpatterntoexistatthestartorendofastringorline,oryoumightwantittobebetweentwowords.Thefollowingtablelistssomeofthemostcommonpositioncharactersandwhattheydo:
POSITIONCHARACTER
DESCRIPTION
^ Thepatternmustbeatthestartofthestring,orifit’samulti-linestring,thenatthebeginningofaline.Formulti-linetext(astringthatcontainscarriagereturns),youneedtosetthemulti-lineflagwhendefiningtheregularexpressionusing/myregex/m.NotethatthisisonlyapplicabletoIE5.5andlaterandNN6andlater.
$ Thepatternmustbeattheendofthestring,orifit’samulti-linestring,thenattheendofaline.Formulti-linetext(astringthatcontainscarriagereturns),youneedtosetthemulti-lineflagwhendefiningtheregularexpressionusing/myregex/m.NotethatthisisonlyapplicabletoIE5.5andlaterandNN6andlater.
\b Thismatchesawordboundary,whichisessentiallythepointbetweenawordcharacterandanon-wordcharacter.
\B Thismatchesapositionthat’snotawordboundary.
Forexample,ifyouwantedtomakesureyourpatternwasatthestartofaline,youwouldtypethefollowing:
^myPattern
ThiswouldmatchanoccurrenceofmyPatternifitwasatthebeginningofaline.
Tomatchthesamepattern,butattheendofaline,youwouldtypethefollowing:
myPattern$
Theword-boundaryspecialcharacters\band\Bcancauseconfusion,becausetheydonotmatchcharactersbutthepositionsbetweencharacters.
Imagineyouhadthestring"Helloworld!,let'slookatboundariessaid007."definedinthecodeasfollows:
varmyString="Helloworld!,let'slookatboundariessaid007.";
Tomakethewordboundaries(thatis,theboundariesbetweenthewords)ofthisstringstandout,let’sconvertthemtothe|character:
varmyRegExp=/\b/g;
myString=myString.replace(myRegExp,"|");
alert(myString);
You’vereplacedallthewordboundaries,\b,witha|,andyourmessageboxlooksliketheoneinFigure6.4.
Figure6.4
Youcanseethatthepositionbetweenanywordcharacter(letters,numbers,ortheunderscorecharacter)andanynon-wordcharacterisawordboundary.You’llalsonoticethattheboundarybetweenthestartorendofthestringandawordcharacterisconsideredtobeawordboundary.Theendofthisstringisafullstop.Sotheboundarybetweenthefullstopandtheendofthestringisanon-wordboundary,andthereforeno|hasbeeninserted.
Ifyouchangetheregularexpressionintheexample,sothatitreplacesnon-wordboundariesasfollows:
varmyRegExp=/\B/g;
yougettheresultshowninFigure6.5.
Figure6.5
Nowthepositionbetweenaletter,number,orunderscoreandanotherletter,number,orunderscoreisconsideredanon-wordboundaryandisreplacedbyan|intheexample.However,whatisslightlyconfusingisthattheboundarybetweentwonon-wordcharacters,suchasanexclamationmarkandacomma,isalsoconsideredanon-wordboundary.Ifyouthinkaboutit,itactuallydoesmakesense,butit’seasytoforgetwhencreatingregularexpressions.
You’llrememberthisexamplefromwhenyoustartedlookingatregularexpressions:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Figure2</title>
</head>
<body>
<script>
varmyString="Paul,Paula,Pauline,paul,Paul";
varmyRegExp=/Paul/gi;
myString=myString.replace(myRegExp,"Ringo");
alert(myString);
</script>
</body>
</html>
YouusedthiscodetoconvertallinstancesofPaulorpaultoRingo.
However,youfoundthatthiscodeactuallyconvertsallinstancesofPaultoRingo,evenwhenthewordPaulisinsideanotherword.
OnewaytosolvethisproblemwouldbetoreplacethestringPaulonlywhereitis
followedbyanon-wordcharacter.Thespecialcharacterfornon-wordcharactersis\W,soyouneedtoaltertheregularexpressiontothefollowing:
varmyRegExp=/Paul\W/gi;
ThisgivestheresultshowninFigure6.6.
Figure6.6
It’sgettingbetter,butit’sstillnotwhatyouwant.NoticethatthecommasafterthesecondandthirdPaulsubstringshavealsobeenreplacedbecausetheymatchedthe\Wcharacter.Also,you’restillnotreplacingPaulattheveryendofthestring.That’sbecausethereisnocharacteraftertheletterlinthelastPaul.WhatisafterthelinthelastPaul?Nothing,justtheboundarybetweenawordcharacterandanon-wordcharacter,andthereinliestheanswer.WhatyouwantasyourregularexpressionisPaulfollowedbyawordboundary.Let’saltertheregularexpressiontocopewiththatbyenteringthefollowing:
varmyRegExp=/Paul\b/gi;
Nowyougettheresultyouwant,asshowninFigure6.7.
Figure6.7
Atlastyou’vegotitright,andthisexampleisfinished.
CoveringAllEventualitiesPerhapsthetrickiestthingaboutaregularexpressionismakingsureitcoversalleventualities.Inthepreviousexampleyourregularexpressionworkswiththestringasdefined,butdoesitworkwiththefollowing?
varmyString="Paul,Paula,Pauline,paul,Paul,JeanPaul";
HerethePaulsubstringinJeanPaulwillbechangedtoRingo.YoureallyonlywanttoconvertthesubstringPaulwhereitisonitsown,withawordboundaryoneitherside.Ifyouchangeyourregularexpressioncodeto:
varmyRegExp=/\bPaul\b/gi;
youhaveyourfinalanswerandcanbesureonlyPaulorpaulwilleverbematched.
GroupingRegularExpressionsThefinaltopicunderregularexpressions,beforeyoulookatexamplesusingthematch(),replace(),andsearch()methods,ishowyoucangroupexpressions.Infact,it’squiteeasy.Ifyouwantanumberofexpressionstobetreatedasasinglegroup,youjustenclosetheminparentheses,forexample,/(\d\d)/.Parenthesesinregularexpressionsarespecialcharactersthatgrouptogethercharacterpatternsandarenotthemselvespartofthecharacterstobematched.
Whywouldyouwanttodothis?Well,bygroupingcharactersintopatterns,youcanusethespecialrepetitioncharacterstoapplytothewholegroupofcharacters,ratherthanjustone.
Let’stakethefollowingstringdefinedinmyStringasanexample:
varmyString="JavaScript,VBScriptandPHP";
HowcouldyoumatchbothJavaScriptandVBScriptusingthesameregularexpression?TheonlythingtheyhaveincommonisthattheyarewholewordsandtheybothendinScript.Well,aneasywaywouldbetouseparenthesestogroupthepatternsJavaandVB.Thenyoucanusethe?specialcharactertoapplytoeachofthesegroupsofcharacterstomakethepatternmatchanywordhavingzerooroneinstanceofthecharactersJavaorVB,andendinginScript:
varmyRegExp=/\b(VB)?(Java)?Script\b/gi;
Breakingdownthisexpression,youcanseethepatternitrequiresisasfollows:
1. Awordboundary:\b
2. ZerooroneinstanceofVB:(VB)?
3. ZerooroneinstanceofJava:(Java)?
4. ThecharactersScript:Script
5. Awordboundary:\b
Puttingthesetogether,yougetthis:
varmyString="JavaScript,VBScriptandPHP";
varmyRegExp=/\b(VB)?(Java)?Script\b/gi;
myString=myString.replace(myRegExp,"xxxx");
alert(myString);
TheoutputofthiscodeisshowninFigure6.8.
Figure6.8
Ifyoulookbackatthespecialrepetitioncharacterstable,you’llseethattheyapplytotheitemprecedingthem.Thiscanbeacharacter,or,wheretheyhavebeengroupedbymeansofparentheses,thepreviousgroupofcharacters.
However,thereisapotentialproblemwiththeregularexpressionyoujustdefined.AswellasmatchingVBScriptandJavaScript,italsomatchesVBJavaScript.Thisisclearlynotexactlywhatyoumeant.
Togetaroundthisyouneedtomakeuseofbothgroupingandthespecialcharacter|,whichisthealternationcharacter.Ithasanor-likemeaning,similarto||inifstatements,andwillmatchthecharactersoneithersideofitself.
Let’sthinkabouttheproblemagain.YouwantthepatterntomatchVBScriptorJavaScript.ClearlytheyhavetheScriptpartincommon.SowhatyouwantisanewwordstartingwithJavaorstartingwithVB;eitherway,itmustendinScript.
First,youknowthatthewordmuststartwithawordboundary:
\b
NextyouknowthatyouwanteitherVBorJavatobeatthestartoftheword.You’vejustseenthatinregularexpressions|providesthe“or”youneed,soinregularexpressionsyntaxyouwantthefollowing:
\b(VB|Java)
ThismatchesthepatternVBorJava.NowyoucanjustaddtheScriptpart:
\b(VB|Java)Script\b
Yourfinalcodelookslikethis:
varmyString="JavaScript,VBScriptandPerl";
varmyRegExp=/\b(VB|Java)Script\b/gi;
myString=myString.replace(myRegExp,"xxxx");
alert(myString);
ReusingGroupsofCharactersYoucanreusethepatternspecifiedbyagroupofcharacterslateronintheregularexpression.Torefertoapreviousgroupofcharacters,youjusttype\andanumberindicatingtheorderofthegroup.Forexample,youcanrefertothefirstgroupas\1,thesecondas\2,andsoon.
Let’slookatanexample.Sayyouhavealistofnumbersinastring,witheachnumberseparatedbyacomma.Forwhateverreason,youarenotallowedtohavetwoinstancesofthesamenumberinarow,soalthough
009,007,001,002,004,003
wouldbeokay,thefollowing:
007,007,001,002,002,003
wouldnotbevalid,becauseyouhave007and002repeatedafterthemselves.
HowcanyoufindinstancesofrepeateddigitsandreplacethemwiththewordERROR?Youneedtousetheabilitytorefertogroupsinregularexpressions.
First,let’sdefinethestringasfollows:
varmyString="007,007,001,002,002,003,002,004";
Nowyouknowyouneedtosearchforaseriesofoneormorenumbercharacters.Inregularexpressionsthe\dspecifiesanydigitcharacter,and+meansoneormoreofthepreviouscharacter.Sofar,thatgivesyouthisregularexpression:
\d+
Youwanttomatchaseriesofdigitsfollowedbyacomma,soyoujustaddthecomma:
\d+,
Thiswillmatchanyseriesofdigitsfollowedbyacomma,buthowdoyousearchforanyseriesofdigitsfollowedbyacomma,thenfollowedagainbythesameseriesofdigits?Becausethedigitscouldbeanydigits,youcan’taddthemdirectlyintotheexpressionlikeso:
\d+,007
Thiswouldnotworkwiththe002repeat.Whatyouneedtodoisputthefirstseriesofdigitsinagroup;thenyoucanspecifythatyouwanttomatchthatgroupofdigitsagain.Youcandothiswith\1,whichsays,“Matchthecharactersfoundinthefirstgroupdefinedusingparentheses.”Putallthistogether,andyouhavethefollowing:
(\d+),\1
Thisdefinesagroupwhosepatternofcharactersisoneormoredigitcharacters.Thisgroupmustbefollowedbyacommaandthenbythesamepatternofcharactersasinthefirstgroup.PutthisintosomeJavaScript,andyouhavethefollowing:
varmyString="007,007,001,002,002,003,002,004";
varmyRegExp=/(\d+),\1/g;
myString=myString.replace(myRegExp,"ERROR");
alert(myString);
Thealertboxwillshowthismessage:
ERROR,1,ERROR,003,002,004
Thatcompletesyourbrieflookatregularexpressionsyntax.Becauseregularexpressionscangetalittlecomplex,it’softenagoodideatostartsimpleandbuildthemupslowly,asinthepreviousexample.Infact,mostregularexpressionsarejusttoohardtogetrightinonestep—atleastforusmeremortalswithoutabrainthesizeofaplanet.
Ifit’sstilllookingabitstrangeandconfusing,don’tpanic.Inthenextsections,youlookattheStringobject’ssplit(),replace(),search(),andmatch()methodswithplentymoreexamplesofregularexpressionsyntax.
THESTRINGOBJECTThemainfunctionsmakinguseofregularexpressionsaretheStringobject’ssplit(),replace(),search(),andmatch()methods.You’vealreadyseentheirsyntax,sointhissectionyouconcentrateontheirusewithregularexpressionsandatthesametimelearnmoreaboutregularexpressionsyntaxandusage.
Thesplit()MethodYou’veseenthatthesplit()methodenablesyoutosplitastringintovariouspieces,withthesplitbeingmadeatthecharacterorcharactersspecifiedasaparameter.Theresultofthismethodisanarraywitheachelementcontainingoneofthesplitpieces.Forexample,thefollowingstring:
varmyListString="apple,banana,peach,orange"
couldbesplitintoanarrayinwhicheachelementcontainsadifferentfruit,likethis:
varmyFruitArray=myListString.split(",");
Howaboutifyourstringisthisinstead?
varmyListString="apple,0.99,banana,0.50,peach,0.25,orange,0.75";
Thestringcould,forexample,containboththenamesandpricesofthefruit.Howcouldyousplitthestring,butretrieveonlythenamesofthefruitandnottheprices?Youcoulddoitwithoutregularexpressions,butitwouldtakemanylinesofcode.Withregularexpressionsyoucanusethesamecodeandjustamendthesplit()method’sparameter.
TRYITOUTSplittingtheFruitStringLet’screateanexamplethatsolvestheproblemjustdescribed—itmustsplityourstring,butincludeonlythefruitnames,nottheprices:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example3</title>
</head>
<body>
<script>
varmyListString="apple,0.99,banana,0.50,peach,0.25,
orange,0.75";
vartheRegExp=/[^a-z]+/i;
varmyFruitArray=myListString.split(theRegExp);
document.write(myFruitArray.join("<br/>"));
</script>
</body>
</html>
Savethefileasch6 _ example3.htmlandloaditinyourbrowser.Youshouldseethefourfruitsfromyourstringwrittenouttothepage,witheachfruitonaseparateline.
Withinthescriptblock,firstyouhaveyourstringwithfruitnamesandprices:
varmyListString="apple,0.99,banana,0.50,peach,0.25,orange,
0.75";
Howdoyousplititinsuchawaythatonlythefruitnamesareincluded?Yourfirstthoughtmightbetousethecommaasthesplit()method’sparameter,butofcoursethatmeansyouendupwiththeprices.Whatyouhavetoaskis,“Whatisitthat’sbetweentheitemsIwant?”Orinotherwords,whatisbetweenthefruitnamesthatyoucanusetodefineyoursplit?Theansweristhatvariouscharactersarebetweenthenamesofthefruit,suchasacomma,aspace,numbers,afullstop,morenumbers,andfinallyanothercomma.Whatisitthatthesethingshaveincommonandmakesthemdifferentfromthefruitnamesthatyouwant?Whattheyhaveincommonisthatnoneofthemarelettersfromathroughz.Ifyousay“Splitthestringatthepointwherethereisagroupofcharactersthatarenotbetweenaandz,”thenyougettheresultyouwant.Nowyouknowwhatyouneedtocreateyourregularexpression.
Youknowthatwhatyouwantisnotthelettersathroughz,soyoustartwiththis:
[^a-z]
The^says“Matchanycharacterthatdoesnotmatchthosespecifiedinsidethesquarebrackets.”Inthiscaseyou’vespecifiedarangeofcharactersnottobematched—allthecharactersbetweenaandz.Asspecified,thisexpressionwillmatchonlyonecharacter,whereasyouwanttosplitwhereverthereisasinglegroupofoneormorecharactersthatarenotbetweenaandz.Todothisyouneedtoaddthe+specialrepetitioncharacter,whichsays“Matchoneormoreoftheprecedingcharacterorgroupspecified”:
[^a-z]+
Thefinalresultisthis:
vartheRegExp=/[^a-z]+/i
The/and/charactersmarkthestartandendoftheregularexpressionwhoseRegExpobjectisstoredasareferenceinthevariabletheRegExp.Youaddtheiontheendtomakethematchcase-insensitive.
Don’tpanicifcreatingregularexpressionsseemslikeafrustratingandless-than-obviousprocess.Atfirst,ittakesalotoftrialanderrortogetitright,butasyougetmoreexperienced,you’llfindcreatingthembecomesmucheasierandwillenableyoutodothingsthatwithoutregularexpressionswouldbeeitherveryawkwardorvirtuallyimpossible.
InthenextlineofscriptyoupasstheRegExpobjecttothesplit()method,whichusesittodecidewheretosplitthestring:
varmyFruitArray=myListString.split(theRegExp);
Afterthesplit,thevariablemyFruitArraywillcontainanArraywitheachelementcontainingthefruitname,asshownhere:
ARRAYELEMENTINDEX 0 1 2 3Elementvalue apple banana peach orange
YouthenjointhestringtogetheragainusingtheArrayobject’sjoin()methods,whichyousawinChapter4:
document.write(myFruitArray.join("<br/>"))
Thereplace()MethodYou’vealreadylookedatthesyntaxandusageofthereplace()method.However,somethinguniquetothereplace()methodisitsabilitytoreplacetextbasedonthegroupsmatchedintheregularexpression.Youdothisusingthe$signandthegroup’snumber.Eachgroupinaregularexpressionisgivenanumberfrom1to99;anygroupsgreaterthan99arenotaccessible.Torefertoagroup,youwrite$followedbythegroup’sposition.Forexample,ifyouhadthefollowing:
varmyRegExp=/(\d)(\W)/g;
then$1referstothegroup(\d),and$2referstothegroup(\W).You’vealsosettheglobalflaggtoensurethatallmatchingpatternsarereplaced—notjustthefirstone.
Youcanseethismoreclearlyinthenextexample.Sayyouhavethefollowingstring:
varmyString="2012,2013,2014";
Ifyouwantedtochangethisto"theyear2012,theyear2013,theyear2014",howcouldyoudoitwithregularexpressions?
First,youneedtoworkoutthepatternasaregularexpression,inthiscasefourdigits:
varmyRegExp=/\d{4}/g;
Butgiventhattheyearisdifferenteverytime,howcanyousubstitutetheyearvalueintothereplacedstring?
Well,youchangeyourregularexpressionsothatit’sinsideagroup,asfollows:
varmyRegExp=/(\d{4})/g;
Nowyoucanusethegroup,whichhasgroupnumber1,insidethereplacementstringlikethis:
myString=myString.replace(myRegExp,"theyear$1");
ThevariablemyStringnowcontainstherequiredstring"theyear2012,theyear2013,theyear2014".
Let’slookatanotherexampleinwhichyouwanttoconvertsinglequotesintexttodoublequotes.Yourteststringisthis:
Hethensaid'MyNameisO'Connerly,yesthat'sright,O'Connerly'.
Oneproblemthattheteststringmakesclearisthatyouwanttoreplacethesingle-quotemarkwithadoubleonlywhereitisusedinpairsaroundspeech,notwhenitisactingasanapostrophe,suchasinthewordthat's,orwhenit’spartofsomeone’sname,suchasinO'Connerly.
Let’sstartbydefiningtheregularexpression.First,youknowthatitmustincludeasinglequote,asshowninthefollowingcode:
varmyRegExp=/'/;
However,asitisthiswouldreplaceeverysinglequote,whichisnotwhatyouwant.
Lookingatthetext,youshouldalsonoticethatquotesarealwaysatthestartorendofaword—thatis,ataboundary.Onfirstglanceitmightbeeasytoassumethatitwouldbeawordboundary.However,don’tforgetthatthe'isanon-wordcharacter,sotheboundarywillbebetweenitandanothernon-wordcharacter,suchasaspace.Sotheboundarywillbeanon-wordboundaryor,inotherwords,\B.
Therefore,thecharacterpatternyouarelookingforiseitheranon-wordboundaryfollowedbyasinglequoteorasinglequotefollowedbyanon-wordboundary.Thekeyisthe“or,”forwhichyouuse|inregularexpressions.Thisleavesyourregularexpressionasthefollowing:
varmyRegExp=/\B'|'\B/g;
Thiswillmatchthepatternontheleftofthe|orthecharacterpatternontheright.Youwanttoreplaceallthesinglequoteswithdoublequotes,sotheghasbeenaddedattheend,indicatingthataglobalmatchshouldtakeplace.
TRYITOUTReplacingSingleQuoteswithDoubleQuotesLet’slookatanexampleusingtheregularexpressionjustdefined:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example4</title>
</head>
<body>
<script>
vartext="Hethensaid'MyNameisO'Connerly,yes"+
"that'sright,O'Connerly'";
document.write("Original:"+text+"<br/>");
varmyRegExp=/\B'|'\B/g;
text=text.replace(myRegExp,'"');
document.write("Corrected:"+text);
</script>
</body>
</html>
Savethepageasch6_example4.html.LoadthepageintoyourbrowserandyoushouldseewhatisshowninFigure6.9.
Figure6.9
Youcanseethatbyusingregularexpressions,youhavecompletedataskinacoupleoflinesofsimplecode.Withoutregularexpressions,itwouldprobablytakefourorfivetimesthatamount.
Theworkhorsesofthiscodearetwosimplelines:
varmyRegExp=/\B'|'\B/g;
text=text.replace(myRegExp,'"');
Youdefineyourregularexpression(asdiscussedpreviously),whichmatchesanynon-wordboundaryfollowedbyasinglequoteoranysinglequotefollowedbyanon-wordboundary.Forexample,'Hwillmatch,aswillH',butO'Rwon’t,becausethequoteisbetweentwowordboundaries.Don’tforgetthatawordboundaryisthepositionbetweenthestartorendofawordandanon-wordcharacter,suchasaspaceorpunctuationmark.
Thesecondlineofcodeusesthereplace()methodtodothecharacterpatternsearchandreplace,andassignsthenewvaluetothetextvariable.
Thesearch()MethodThesearch()methodenablesyoutosearchastringforapatternofcharacters.Ifthepatternisfound,thecharacterpositionatwhichitwasfoundisreturned;otherwise,-1isreturned.Themethodtakesonlyoneparameter,theRegExpobjectyouhavecreated.
AlthoughforbasicsearchestheindexOf()methodisfine,ifyouwantmorecomplexsearches,suchasasearchforapatternofanydigitsoroneinwhichawordmustbeinbetweenacertainboundary,search()providesamuchmorepowerfulandflexible,butsometimesmorecomplex,approach.
Inthefollowingexample,youwanttofindoutifthewordJavaiscontainedwithinthestring.However,youwanttolookjustforJavaasawholeword,notpartofanotherwordsuchasJavaScript:
varmyString="BeginningJavaScript,BeginningJava2,"+
"ProfessionalJavaScript";
varmyRegExp=/\bJava\b/i;
alert(myString.search(myRegExp));
First,youhavedefinedyourstring,andthenyou’vecreatedyourregularexpression.YouwanttofindthecharacterpatternJavawhenit’sonitsownbetweentwowordboundaries.You’vemadeyoursearchcase-insensitivebyaddingtheiaftertheregularexpression.Notethatwiththesearch()method,thegforglobalisnotrelevant,anditsusehasnoeffect.
Onthefinalline,yououtputthepositionatwhichthesearchhaslocatedthepattern,inthiscase32.
Thematch()MethodThematch()methodisverysimilartothesearch()method,exceptthatinsteadofreturningthepositionatwhichamatchwasfound,itreturnsanarray.Eachelementofthearraycontainsthetextofamatchmade.
Forexample,ifyouhadthestring:
varmyString="Theyearswere2012,2013and2014";
andwantedtoextracttheyearsfromthisstring,youcoulddosousingthematch()method.Tomatcheachyear,youarelookingforfourdigitsinbetweenwordboundaries.Thisrequirementtranslatestothefollowingregularexpression:
varmyRegExp=/\b\d{4}\b/g;
Youwanttomatchalltheyears,sotheghasbeenaddedtotheendforaglobalsearch.
Todothematchandstoretheresults,youusethematch()methodandstoretheArrayobjectitreturnsinavariable:
varresultsArray=myString.match(myRegExp);
Toproveithasworked,let’susesomecodetooutputeachiteminthearray.You’veadded
anifstatementtodouble-checkthattheresultsarrayactuallycontainsanarray.Ifnomatchesweremade,theresultsarraywillcontainnull—doingif(resultsArray)willreturntrueifthevariablehasavalueandnotnull:
if(resultsArray){
for(varindex=0;index<resultsArray.length;index++){
alert(resultsArray[index]);
}
}
Thiswouldresultinthreealertboxescontainingthenumbers2012,2013,and2014.
TRYITOUTSplittingHTMLInthisexample,youwanttotakeastringofHTMLandsplititintoitscomponentparts.Forexample,youwanttheHTML<p>Hello</p>tobecomeanarray,withtheelementshavingthefollowingcontents:
<p> Hello </p>
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example5</title>
</head>
<body>
<divid="output"></div>
<script>
varhtml="<h2>HelloWorld!</h2>"+
"<p>WeloveJavaScript!</p>";
varregex=/<[^>\r\n]+>|[^<>\r\n]+/g;
varresults=html.match(regex);
document.getElementById("output").innerText=
results.join("\r\n");
</script>
</body>
</html>
Savethisfileasch6 _ example5.html.Whenyouloadthepageintoyourbrowseryou’llseethatthestringofHTMLissplit,witheachelement’stagsandcontentdisplayedonseparatelines,asshowninFigure6.10.
Figure6.10
Onceagain,thecodethatmakesallofthisworkconsistsofjustafewlines.YoufirstcreateaRegExpobjectandinitializeittoyourregularexpression:
varregex=/<[^>\r\n]+>|[^<>\r\n]+/g;
Let’sbreakitdowntoseewhatpatternyou’retryingtomatch.First,notethatthepatternisbrokenupbyanalternationsymbol:|.Thismeansthatyouwantthepatternontheleftortherightofthissymbol.Lookatthesepatternsseparately.Ontheleft,youhavethefollowing:
Thepatternmuststartwitha<.
In[^>\r\n]+,youspecifythatyouwantoneormoreofanycharacterexceptthe>ora\r(carriagereturn)ora\n(linefeed).
>specifiesthatthepatternmustendwitha>.
Ontheright,youhaveonlythefollowing:
[^<>\r\n]+specifiesthatthepatternisoneormoreofanycharacter,solongasthatcharacterisnota<,>,\r,or\n.Thiswillmatchplaintext.
Aftertheregularexpressiondefinitionyouhaveag,whichspecifiesthatthisisaglobalmatch.
Sothe<[^>\r\n]+>regularexpressionwillmatchanystartorclosetags,suchas<p>or</p>.Thealternativepatternis[^<>\r\n]+,whichwillmatchanycharacterpatternthatisnotanopeningorclosingtag.
Inthefollowingline,youassigntheresultsvariabletotheArrayobjectreturnedbythematch()method:
varresults=html.match(regex);
Theremainderofthecodepopulatesa<div/>elementwiththesplitHTML:
document.getElementById("output").innerText=results.join("\r\n");
Thiscodeusesfeaturesyouhaven’tyetseen.Itessentiallyretrievestheelementthathasanidvalueofoutput;thisisthe<div/>elementatthetopofthebody.TheinnerTextpropertyenablesyoutosetthetextinsideofthe<div/>element.Youlearnmoreinlaterchapters.
YouthenusetheArrayobject’sjoin()methodtojoinallthearray’selementsintoonestringwitheachelementseparatedbya\r\ncharacter,sothateachtagorpieceoftextgoesonaseparateline.
USINGTHEREGEXPOBJECT’SCONSTRUCTORSofaryou’vebeencreatingRegExpobjectsusingthe/and/characterstodefinethestartandendoftheregularexpression,asshowninthefollowingexample:
varmyRegExp=/[a-z]/;
Althoughthisisthegenerallypreferredmethod,itwasbrieflymentionedthataRegExpobjectcanalsobecreatedbymeansoftheRegExp()constructor.Youmightusethefirstwaymostofthetime.However,onsomeoccasionsthesecondwayofcreatingaRegExpobjectisnecessary(forexample,whenaregularexpressionistobeconstructedfromuserinput).
Asanexample,theprecedingregularexpressioncouldequallywellbedefinedas:
varmyRegExp=newRegExp("[a-z]");
HereyoupasstheregularexpressionasastringparametertotheRegExp()constructorfunction.
Averyimportantdifferencewhenyouareusingthismethodisinhowyouusespecialregularexpressioncharacters,suchas\b,thathaveabackwardslashinfrontofthem.TheproblemisthatthebackwardslashindicatesanescapecharacterinJavaScriptstrings—forexample,youmayuse\b,whichmeansabackspace.Todifferentiatebetween\bmeaningabackspaceinastringandthe\bspecialcharacterinaregularexpression,youhavetoputanotherbackwardslashinfrontoftheregularexpressionspecialcharacter.So\bbecomes\\bwhenyoumeantheregularexpression\bthatmatchesawordboundary,ratherthanabackspacecharacter.
Forexample,sayyouhavedefinedyourRegExpobjectusingthefollowing:
varmyRegExp=/\b/;
TodeclareitusingtheRegExp()constructor,youwouldneedtowritethis:
varmyRegExp=newRegExp("\\b");
andnotthis:
varmyRegExp=newRegExp("\b");
Allspecialregularexpressioncharacters,suchas\w,\b,\d,andsoon,musthaveanextra\infrontwhenyoucreatethemusingRegExp().
Whenyoudefineregularexpressionswiththe/and/method,afterthefinal/youcouldaddthespecialflagsm,g,anditoindicatethatthepatternmatchingshouldbemulti-line,global,orcase-insensitive,respectively.WhenusingtheRegExp()constructor,howcanyoudothesamething?
Easy.TheoptionalsecondparameteroftheRegExp()constructortakestheflagsthatspecifyaglobalorcase-insensitivematch.Forexample,thiswilldoaglobalcase-insensitivepatternmatch:
varmyRegExp=newRegExp("hello\\b","gi");
Youcanspecifyjustoneoftheflagsifyouwant—suchasthefollowing:
varmyRegExp=newRegExp("hello\\b","i");
or
varmyRegExp=newRegExp("hello\\b","g");
TRYITOUTFormValidationModuleInthisTryItOut,youcreateasetofusefulJavaScriptfunctionsthatuseregularexpressionstovalidatethefollowing:
Telephonenumbers
Postalcodes
E-mailaddresses
Thevalidationonlycheckstheformat.So,forexample,itcan’tcheckthatthetelephonenumberactuallyexists,onlythatitwouldbevalidifitdid.
Firstisthe.jscodefilewiththeinputvalidationcode.Pleasenotethatthelinesofcodeinthefollowingblockaretoowideforthebook—makesureeachregularexpressioniscontainedononeline:
functionisValidTelephoneNumber(telephoneNumber){
vartelRegExp=/^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})
?\d{3}?\d{0,7}((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-
5})?$/i;
returntelRegExp.test(telephoneNumber);
}
functionisValidPostalCode(postalCode){
varpcodeRegExp=/^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-
z])
?\d[a-z][a-z])$/i;
returnpcodeRegExp.test(postalCode);
}
functionisValidEmail(emailAddress){
varemailRegExp=/^(([^<>()\[\]\\.,;:@"\x00-\x20\x7F]|\\.)+|("""
([^\x0A\x0D"\\]
|\\\\)+"""))@(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]
|#\d+?)\.)+([a-z]{2,4})$/i;
returnemailRegExp.test(emailAddress);
}
Savethisasch6_example6.js.
Totestthecode,youneedasimplepage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6,Example6</title>
</head>
<body>
<scriptsrc="ch6_example6.js"></script>
<script>
varphoneNumber=prompt("Pleaseenteraphonenumber.",
"");
if(isValidTelephoneNumber(phoneNumber)){
alert("ValidPhoneNumber");
}else{
alert("InvalidPhoneNumber");
}
varpostalCode=prompt("Pleaseenterapostalcode.","");
if(isValidPostalCode(postalCode)){
alert("ValidPostalCode");
}else{
alert("InvalidPostalCode");
}
varemail=prompt("Pleaseenteranemailaddress.","");
if(isValidEmail(email)){
alert("ValidEmailAddress");
}else{
alert("InvalidEmailAddress");
}
</script>
</body>
</html>
Savethisasch6 _ example6.htmlandloaditintoyourbrowser,andyou’llbepromptedtoenteraphonenumber.Enteravalidtelephonenumber(forexample,+1(123)1234567),andyou’llseeamessagethatstateswhetherornotthephonenumberisvalid.
You’llthenbepromptedtoenterapostalcodeandane-mail.Enterthosevaluestotestthosefunctions.Thisisprettybasic,butit’ssufficientfortestingyourcode.
Theactualcodeisverysimple,buttheregularexpressionsaretrickytocreate,solet’slookatthoseindepthstartingwithtelephonenumbervalidation.
TelephoneNumberValidationTelephonenumbersaremoreofachallengetovalidate.Theproblemsare:
Phonenumbersdifferfromcountrytocountry.
Avalidnumbercanbeenteredindifferentways(forexample,withorwithoutthenationalorinternationalcode).
Forthisregularexpression,youneedtospecifymorethanjustthevalidcharacters;youalsoneedtospecifytheformatofthedata.Forexample,allofthefollowingarevalid:
+1(123)1234567
+1123123456
+44(123)1234567
+44(123)1234567ext123
+442078934567
Thevariationsthatyourregularexpressionneedstodealwith(optionallyseparatedbyspaces)areshowninthefollowingtable:
Theinternationalnumber
“+”followedbyonetothreedigits(optional)
Thelocalareacode Twotofivedigits,sometimesinparentheses(compulsory)Theactualsubscribernumber
Threeto10digits,sometimeswithspaces(compulsory)
Anextensionnumber
Twotofivedigits,precededbyx,xtn,extn,pax,pbx,orextension,andsometimesinparentheses
Obviously,thiswon’tworkinsomecountries,whichissomethingyou’dneedtodealwithbasedonwhereyourcustomersandpartnerswouldbe.Thefollowingregularexpressionisrathercomplex(itslengthmeantithadtobesplitacrosstwolines;makesureyoutypeitinononeline):
^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})?\d{3}?\d{0,7}
((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-5})?$
Youwillneedtosetthecase-insensitiveflagwiththis,aswellastheexplicitcaptureoption.Althoughthisseemscomplex,ifbrokendown,it’squitestraightforward.
Let’sstartwiththepatternthatmatchesaninternationaldialingcode:
(\+\d{1,3}?)?
Sofar,you’rematchingaplussign(\+)followedbyonetothreedigits(\d{1,3})andanoptionalspace(?).Rememberthatbecausethe+characterisaspecialcharacter,youadda\characterinfrontofittospecifythatyoumeananactual+character.Thecharactersarewrappedinsideparenthesestospecifyagroupofcharacters.Youallowanoptionalspaceandmatchthisentiregroupofcharacterszerooronetime,asindicatedbythe?characteraftertheclosingparenthesisofthegroup.
Nextisthepatterntomatchanareacode:
(\(\d{1,5}\)|\d{1,5})
Thispatterniscontainedinparentheses,whichdesignateitasagroupofcharacters,andmatcheseitheronetofivedigitsinparentheses((\d{1,5}))orjustonetofivedigits(\d{1,5}).Again,becausetheparenthesischaractersarespecialcharactersinregular
expressionsyntaxandyouwanttomatchactualparentheses,youneedthe\characterinfrontofthem.Alsonotetheuseofthepipesymbol(|),whichmeans“OR”or“matcheitherofthesetwopatterns.”
Next,let’smatchthesubscribernumber:
?\d{3,4}?\d{0,7}
NOTETheinitialspaceand?mean“matchzerooronespace.”Thisisfollowedbythreeorfourdigits(\d{3,4})—althoughU.S.numbersalwayshavethreedigits,UKnumbersoftenhavefour.Thenthere’sanother“zerooronespace,”and,finally,betweenzeroandsevendigits(\d{0,7}).
Finally,addtheparttocopewithanoptionalextensionnumber:
((x|xtn|ext|extn|extension)?\.??\d{2-5})?
Thisgroupisoptionalbecauseitsparenthesesarefollowedbyaquestionmark.Thegroupitselfchecksforaspace,optionallyfollowedbyx,ext,xtn,extn,orextension,followedbyzerooroneperiod(notethe\character,because.isaspecialcharacterinregularexpressionsyntax),followedbyzerooronespace,followedbybetweentwoandfivedigits.Puttingthesefourpatternstogether,youcanconstructtheentireregularexpression,apartfromthesurroundingsyntax.Theregularexpressionstartswith^andendswith$.The^characterspecifiesthatthepatternmustbematchedatthebeginningofthestring,andthe$characterspecifiesthatthepatternmustbematchedattheendofthestring.Thismeansthatthestringmustmatchthepatterncompletely;itcannotcontainanyothercharactersbeforeorafterthepatternthatismatched.
Therefore,withtheregularexpressionexplained,let’slookonceagainattheisValidTelephoneNumber()functioninch6_example6.js:
functionisValidTelephoneNumber(telephoneNumber){
vartelRegExp=/^(\+\d{1,3}?)?(\(\d{1,5}\)|\d{1,5})?\d{3}
?\d{0,7}((x|xtn|ext|extn|pax|pbx|extension)?\.??\d{2-5})?$/i;
returntelRegExp.test(telephoneNumber);
}
Noteinthiscasethatitisimportanttosetthecase-insensitiveflagbyaddinganiontheendoftheexpressiondefinition;otherwise,theregularexpressioncouldfailtomatchtheextparts.Pleasealsonotethattheregularexpressionitselfmustbeononelineinyourcode—it’sshowninmultiplelineshereduetothepage-widthrestrictionsofthisbook.
ValidatingaPostalCodeWejustaboutmanagedtocheckworldwidetelephonenumbers,butdoingthesameforpostalcodeswouldbesomethingofamajorchallenge.Instead,you’llcreateafunctionthatonlychecksforU.S.ZIPcodesandUKpostcodes.Ifyouneededtocheckforothercountries,thecodewouldneedmodifying.Youmayfindthatcheckingmorethanoneortwopostalcodesinoneregularexpressionbeginstogetunmanageable,anditmaywellbe
easiertohaveanindividualregularexpressionforeachcountry’spostalcodeyouneedtocheck.Forthispurposethough,let’scombinetheregularexpressionfortheUnitedKingdomandtheUnitedStates:
^(\d{5}(-\d{4})?|[a-z][a-z]?\d\d??\d[a-z][a-z])$
Thisisactuallyintwoparts.ThefirstpartchecksforZIPcodes,andthesecondpartchecksforUKpostcodes.StartbylookingattheZIPcodepart.
ZIPcodescanberepresentedinoneoftwoformats:asfivedigits(12345),orfivedigitsfollowedbyadashandfourdigits(12345-1234).TheZIPcoderegularexpressiontomatchtheseisasfollows:
\d{5}(-\d{4})?
Thismatchesfivedigits,followedbyanoptionalnon-capturinggroupthatmatchesadash,followedbyfourdigits.
ForaregularexpressionthatcoversUKpostcodes,let’sconsidertheirvariousformats.UKpostcodeformatsareoneortwolettersfollowedbyeitheroneortwodigits,followedbyanoptionalspace,followedbyadigit,andthentwoletters.Additionally,somecentralLondonpostcodeslooklikeSE2V3ER,withaletterattheendofthefirstpart.Currently,onlysomeofthosepostcodesstartwithSE,WC,andW,butthatmaychange.ValidexamplesofUKpostcodesinclude:CH39DR,PR291XX,M271AE,WC1V2ER,andC273AH.
Basedonthis,therequiredpatternisasfollows:
([a-z][a-z]?\d\d?|[a-z]{2}\d[a-z])?\d[a-z][a-z]
Thesetwopatternsarecombinedusingthe|characterto“matchoneortheother”andgroupedusingparentheses.Youthenaddthe^characteratthestartandthe$characterattheendofthepatterntobesurethattheonlyinformationinthestringisthepostalcode.Althoughpostalcodesshouldbeuppercase,itisstillvalidforthemtobelowercase,soyoualsosetthecase-insensitiveoptionasfollowswhenyouusetheregularexpression:
^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-z])?\d[a-z][a-z])$
Justforreference,let’slookonceagainattheisValidPostalCode()function:
functionisValidPostalCode(postalCode){
varpcodeRegExp=/^(\d{5}(-\d{4})?|([a-z][a-z]?\d\d?|[a-z{2}\d[a-z])
?\d[a-z][a-z])$/i;
returnpcodeRegExp.test(postalCode);
}
Again,rememberthattheregularexpressionmustbeononelineinyourcode.
ValidatinganE-mailAddressBeforeworkingonaregularexpressiontomatche-mailaddresses,youneedtolookatthetypesofvalide-mailaddressesyoucanhave.Forexample:
Also,ifyouexaminetheSMTPRFC(http://www.ietf.org/rfc/rfc0821.txt),youcanhavethefollowing:
"""PaulWilton"""@somedomain.com
That’squitealist,anditcontainsmanyvariationstocopewith.It’sbesttostartbybreakingitdown.First,notethatthelattertwoversionsareexceptionallyrareandnotprovidedforintheregularexpressionyou’llcreate.
Second,youneedtobreakupthee-mailaddressintoseparateparts.Let’slookatthepartafterthe@symbolfirst.
ValidatingaDomainNameEverythinghasbecomemorecomplicatedsinceUnicodedomainnameshavebeenallowed.However,thee-mailRFCstilldoesn’tallowthese,solet’sstickwiththetraditionaldefinitionofhowadomaincanbedescribedusingASCII.Adomainnameconsistsofadot-separatedlistofwords,withthelastwordbeingbetweentwoandfourcharacterslong.Itwasoftenthecasethatifatwo-lettercountrywordwasused,therewouldbeatleasttwopartstothedomainnamebeforeit:agroupingdomain(.co,.ac,andsoon)andaspecificdomainname.However,withtheadventofthe.tvnames,thisisnolongerthecase.Youcouldmakethisveryspecificandprovidefortheallowedtop-leveldomains(TLDs),butthatwouldmaketheregularexpressionverylarge,anditwouldbemoreproductivetoperformaDNSlookupinstead.
Eachpartofadomainnamemustfollowcertainrules.Itcancontainanyletterornumberorahyphen,butitmuststartwithaletter.Theexceptionisthat,atanypointinthedomainname,youcanusea#,followedbyanumber,whichrepresentstheASCIIcodeforthatletter,orinUnicode,the16-bitUnicodevalue.Knowingthis,let’sbegintobuilduptheregularexpression,firstwiththenamepart,assumingthatthecase-insensitiveflagwillbesetlaterinthecode:
([a-z]|#\d+)([a-z0-9-]|#\d+)*([a-z0-9]|#\d+)
Thisbreaksthedomainintothreeparts.TheRFCdoesn’tspecifyhowmanydigitscanbe
containedhere,soneitherwillwe.ThefirstpartmustonlycontainanASCIIletter;thesecondmustcontainzeroormoreofaletter,number,orhyphen;andthethirdmustcontaineitheraletterornumber.Thetop-leveldomainhasmorerestrictions,asshownhere:
[a-z]{2,4}
Thisrestrictsyoutoatwo-,three-,orfour-lettertop-leveldomain.So,puttingitalltogether,withtheperiodsyouendupwiththis:
^(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]|#\d+?)\.)+([a-z]{2,4})$
Again,thedomainnameisanchoredatthebeginningandendofthestring.Thefirstthingistoaddanextragrouptoallowoneormorename.portionsandthenanchoratwo-tofour-letterdomainnameattheendinitsowngroup.Wehavealsomademostofthewildcardslazy.Becausemuchofthepatternissimilar,itmakessensetodothis;otherwise,itwouldrequiretoomuchbacktracking.However,wehaveleftthesecondgroupwitha“greedy”wildcard:Itwillmatchasmuchasitcan,upuntilitreachesacharacterthatdoesnotmatch.Thenitwillonlybacktrackonepositiontoattemptthethirdgroupmatch.Thisismoreresource-efficientthanalazymatchisinthiscase,becauseitcouldbeconstantlygoingforwardtoattemptthematch.Onebacktrackpernameisanacceptableamountofextraprocessing.
ValidatingaPerson’sAddressYoucannowattempttovalidatethepartbeforethe@sign.TheRFCspecifiesthatitcancontainanyASCIIcharacterwithacodeintherangefrom33to126.YouareassumingthatyouarematchingagainstASCIIonly,soyoucanassumethattheenginewillmatchagainstonly128characters.Thisbeingthecase,itissimplertojustexcludetherequiredvaluesasfollows:
[^<>()\[\],;:@"\x00-\x20\x7F]+
Usingthis,you’resayingthatyouallowanynumberofcharacters,aslongasnoneofthemarethosecontainedwithinthesquarebrackets.Thesquarebracketandbackslashcharacters([,],and\)havetobeescaped.However,theRFCallowsforotherkindsofmatches.
ValidatingtheCompleteAddressNowthatyouhaveseenalltheprevioussections,youcanbuilduparegularexpressionfortheentiree-mailaddress.First,here’severythinguptoandincludingthe@sign:
^([^<>()\[\],;:@"\x00-\x20\x7F]|\\.)+@
Thatwasstraightforward.Nowforthedomainnamepart:
^([^<>()\[\],;:@"\x00-\x20\x7F]|\\.)+@(([a-z]|#\d+?)([a-z0-9-]
|#\d+?)*([a-z0-9]|#\d+?)\.)+([a-z]{2,4})$
We’vehadtoputitontwolinestofitthisbook’spagewidth,butinyourcodethismust
allbeononeline.
Finally,here’stheisValidEmail()functionforreference:
functionisValidEmail(emailAddress){
varemailRegExp=
/^(([^<>()\[\]\\.,;:@"\x00-\x20\x7F]|\\.)+|("""
([^\x0A\x0D"\\]|\\\\)+"""))
@(([a-z]|#\d+?)([a-z0-9-]|#\d+?)*([a-z0-9]|#\d+?)\.)
+([a-z]{2,4})$/i;
returnemailRegExp.test(emailAddress);
}
Again,notetheregularexpressionmustallbeononelineinyourcode.
SUMMARYInthischapteryou’velookedatsomemoreadvancedmethodsoftheStringobjectandhowyoucanoptimizetheirusewithregularexpressions.
Torecap,thechaptercoveredthefollowingpoints:
Thesplit()methodsplitsasinglestringintoanarrayofstrings.Youpassastringoraregularexpressiontothemethodthatdetermineswherethesplitoccurs.
Thereplace()methodenablesyoutoreplaceapatternofcharacterswithanotherpatternthatyouspecifyasasecondparameter.
Thesearch()methodreturnsthecharacterpositionofthefirstpatternmatchingtheonegivenasaparameter.
Thematch()methodmatchespatterns,returningthetextofthematchesinanarray.
Regularexpressionsenableyoutodefineapatternofcharactersthatyouwanttomatch.Usingthispattern,youcanperformsplits,searches,textreplacement,andmatchesonstrings.
InJavaScript,theregularexpressionsareintheformofaRegExpobject.YoucancreateaRegExpobjectusingeithermyRegExp=/myRegularExpression/ormyRegExp=newRegExp(“myRegularExpression”).Thesecondformrequiresthatcertainspecialcharactersthatnormallyhaveasingle\infrontnowhavetwo.
Thegandicharactersattheendofaregularexpression(asin,forexample,myRegExp=/Pattern/gi;)ensurethataglobalandcase-insensitivematchismade.
Aswellasspecifyingactualcharacters,regularexpressionshavecertaingroupsofspecialcharactersthatallowanyofcertaingroupsofcharacters,suchasdigits,words,ornon-wordcharacters,tobematched.
Youcanalsousespecialcharacterstospecifypatternorcharacterrepetition.Additionally,youcanspecifywhatthepatternboundariesmustbe—forexample,atthebeginningorendofthestring,ornexttoawordornon-wordboundary.
Finally,youcandefinegroupsofcharactersthatcanbeusedlaterintheregularexpressionorintheresultsofusingtheexpressionwiththereplace()method.
Inthenextchapter,youtakealookatusingandmanipulatingdatesandtimesusingJavaScript,andtimeconversionbetweendifferentworldtimezones.Alsocoveredishowtocreateatimerthatexecutescodeatregularintervalsafterthepageisloaded.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. Whatproblemdoesthefollowingcodesolve?
varmyString="Thissentencehashasafaultandandweneedtofix
it."
varmyRegExp=/(\b\w+\b)\1/g;
myString=myString.replace(myRegExp,"$1");
Nowimaginethatyouchangethatcode,sothatyoucreatetheRegExpobjectlikethis:
varmyRegExp=newRegExp("(\b\w+\b)\1");
Whywouldthisnotwork,andhowcouldyourectifytheproblem?
2. Writearegularexpressionthatfindsalloftheoccurrencesoftheword“a”inthefollowingsentenceandreplacesthemwith“the”:
“adogwalkedinoffastreetandorderedafinestbeer”
Thesentenceshouldbecome:
“thedogwalkedinoffthestreetandorderedthefinestbeer”
3. Imagineyouhaveawebsitewithamessageboard.Writearegularexpressionthatwouldremovebarredwords.(Youcanmakeupyourownwords!)
7Date,Time,andTimersWHATYOUWILLLEARNINTHISCHAPTER:
RetrievingspecificdateandtimeinformationfromaDateobject
ModifyingthedateandtimeofaDateobject
Delayingtheexecutionofafunction
Executingafunctionatasetintervaloftime
Chapter5discussedthattheconceptsofdateandtimeareembodiedinJavaScriptthroughtheDateobject.YoulookedatsomeofthepropertiesandmethodsoftheDateobject,includingthefollowing:
ThemethodsgetDate(),getDay(),getMonth(),andgetFullYear()enableyoutoretrievedatevaluesfrominsideaDateobject.
ThesetDate(),setMonth(),andsetFullYear()methodsenableyoutosetthedatevaluesofanexistingDateobject.
ThegetHours(),getMinutes(),getSeconds(),andgetMilliseconds()methodsretrievethetimevaluesinaDateobject.
ThesetHours(),setMinutes(),setSeconds(),andsetMilliseconds()methodsenableyoutosetthetimevaluesofanexistingDateobject.
Onethingnotcoveredinthatchapteristheideathatthetimedependsonyourlocationaroundtheworld.Inthischapteryoucorrectthatomissionbylookingatdateandtimeinrelationtoworldtime.
Forexample,imagineyouhaveachatroomonyourwebsiteandwanttoorganizeachatforacertaindateandtime.Simplystating15:30isnotgoodenoughifyourwebsiteattractsinternationalvisitors.Thetime15:30couldbeEasternStandardTime,PacificStandardTime,thetimeintheUnitedKingdom,oreventhetimeinKualaLumpur.Youcould,ofcourse,say15:30ESTandletyourvisitorsworkoutwhatthatmeans,buteventhatisn’tfoolproof.ThereisanESTinAustraliaaswellasintheUnitedStates.Wouldn’titbegreatifyoucouldautomaticallyconvertthetimetotheuser’stimezone?Inthischapter,youseehow.
Inadditiontolookingatworldtime,youalsolookathowtocreateatimerinawebpage.You’llseethatbyusingthetimeryoucantriggercode,eitheratregularintervalsorjustonce(forexample,fivesecondsafterthepagehasloaded).You’llseehowyoucanusetimerstoaddareal-timeclocktoawebpage.Timerscanalsobeusefulforcreatinganimationsorspecialeffectsinyourwebapplications,whichyouexploreinlaterchapters.
WORLDTIMETheconceptofnowmeansthesamepointintimeeverywhereintheworld.However,whenthatpointintimeisrepresentedbynumbers,thosenumbersdifferdependingonwhereyouare.Whatisneededisastandardnumbertorepresentthatmomentintime.ThisisachievedthroughCoordinatedUniversalTime(UTC),whichisaninternationalbasisofcivilandscientifictimeandwasimplementedin1964.ItwaspreviouslyknownasGMT(GreenwichMeanTime),and,indeed,at0:00UTCitismidnightinGreenwich,London.
Thefollowingtableshowslocaltimesaroundtheworldat0:00UTCtime:
SANFRANCISCO
NEWYORK(EST)
GREENWICH,LONDON
BERLIN,GERMANY
TOKYO,JAPAN
4:00pm 7:00pm 0:00(midnight) 1:00am 9:00am
NOTEthatthetimesgivenarewintertimes—nodaylightsavingshoursaretakenintoaccount.
ThesupportforUTCinJavaScriptcomesfromanumberofmethodsoftheDateobjectthataresimilartothoseyouhavealreadyseen.Foreachoftheset-dateandget-date–typemethodsyou’veseensofar,thereisaUTCequivalent.Forexample,setHours()setsthelocalhourinaDateobject,andsetUTCHours()doesthesamethingforUTCtime.Youlookatthesemethodsinmoredetailinthenextsection.
Inaddition,threemoremethodsoftheDateobjectinvolveworldtime.
YouhavethemethodstoUTCString()andtoLocaleString(),whichreturnthedateandtimestoredintheDateobjectasastringbasedoneitherUTCorlocaltime.Mostmodernbrowsersalsohavetheseadditionalmethods:toLocaleTimeString(),toTimeString(),toLocaleDateString(),andtoDateString().
Ifyousimplywanttofindoutthedifferenceinminutesbetweenthecurrentlocale’stimeandUTC,youcanusethegetTimezoneOffset()method.IfthetimezoneisbehindUTC,suchasintheUnitedStates,itwillreturnapositivenumber.Ifthetimezoneisahead,suchasinAustraliaorJapan,itwillreturnanegativenumber.
TRYITOUTTheWorldTimeMethodoftheDateObject
InthefollowingcodeyouusethetoLocaleString(),toUTCString(),getTimezoneOffset(),toLocaleTimeString(),toTimeString(),toLocaleDateString(),andtoDateString()methodsandwritetheirvaluesouttothepage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Example1</title>
</head>
<body>
<script>
varlocalTime=newDate();
varhtml="<p>UTCTimeis"+localTime.toUTCString()+"
</p>";
html+="LocalTimeis"+localTime.toLocaleString()+"</p>";
html+="<p>TimeZoneOffsetis"+
localTime.getTimezoneOffset()+"</p>";
html+="<p>UsingtoLocalTimeString()gives:"+
localTime.toLocaleTimeString()+"</p>";
html+="<p>UsingtoTimeString()gives:"+
localTime.toTimeString()+"</p>";
html+="<p>UsingtoLocaleDateString()gives:"+
localTime.toLocaleDateString()+"</p>";
html+="<p>UsingtoDateString()gives::"+
localTime.toDateString()+"</p>";
document.write(html);
</script>
</body>
</html>
Savethisasch7_example1.htmlandloaditintoyourbrowser.Whatyousee,ofcourse,dependsonwhichtimezoneyourcomputerissetto,butyourbrowsershouldshowsomethingsimilartoFigure7.1.
Figure7.1
Herethecomputer’stimeissetto09:28:318PMonMarch30,2014,inAmerica’sEasternDaylightTime(forexample,NewYork).
Sohowdoesthiswork?Atthetopofthepage’sscriptblock,youhavejust:
varlocalTime=newDate();
ThiscreatesanewDateobjectandinitializesittothecurrentdateandtimebasedontheclientcomputer’sclock.(NotethattheDateobjectsimplystoresthenumberofmillisecondsbetweenthedateandtimeonyourcomputer’sclockandmidnightUTConJanuary1,1970.)
Withintherestofthescriptblock,youobtaintheresultsfromvarioustimeanddatefunctions.Theresultsarestoredinvariablehtml,andthisisthendisplayedinthepage.
Inthefollowingline,youstorethestringreturnedbythetoUTCString()methodinthehtmlvariable:
varhtml="<p>UTCTimeis"+localTime.toUTCString()+"</p>";
ThisconvertsthedateandtimestoredinsidethelocalTimeDateobjecttotheequivalentUTCdateandtime.
Thenthefollowinglinestoresastringwiththelocaldateandtimevalue:
html+="LocalTimeis"+localTime.toLocaleString()+"</p>";
Becausethistimeisjustbasedontheuser’sclock,thestringreturnedbythismethodalsoadjustsfordaylightsavingstime(aslongastheclockadjustsforit).
Next,thiscodestoresastringwiththedifference,inminutes,betweenthelocaltime
zone’stimeandthatofUTC:
html+="<p>TimeZoneOffsetis"+localTime.getTimezoneOffset()+"
</p>";
YoumaynoticeinFigure7.1thatthedifferencebetweenNewYorktimeandUTCtimeiswrittentobe240minutes,or4hours.Yetintheprevioustable,yousawthatNewYorktimeis5hoursbehindUTC.Sowhatishappening?
Well,inNewYorkonMarch30,daylightsavingshoursareinuse.Whereasinthesummerit’s8:00p.m.inNewYorkwhenit’s0:00UTC,inthewinterit’s7:00p.m.inNewYorkwhenit’s0:00UTC.Therefore,inthesummerthegetTimezoneOffset()methodreturns240,whereasinthewinterthegetTimezoneOffset()methodreturns300.
Toillustratethis,compareFigure7.1toFigure7.2,wherethedateonthecomputer’sclockhasbeenadvancedtoDecember,whichisinthewinterwhendaylightsavingsisnotineffect.
Figure7.2
ThenexttwomethodsaretoLocaleTimeString()andtoTimeString(),asfollows:
html+="<p>UsingtoLocalTimeString()gives:"+
localTime.toLocaleTimeString()+"</p>";
html+="<p>UsingtoTimeString()gives:"+
localTime.toTimeString()+"</p>";
ThesemethodsdisplayjustthetimepartofthedateandtimeheldintheDateobject.ThetoLocaleTimeString()methoddisplaysthetimeasspecifiedbytheuseronhiscomputer.Thesecondmethoddisplaysthetimebutalsogivesanindicationofthetimezone(intheexample,ESTforEasternStandardTimeinAmerica).
Thefinaltwomethodsdisplaythedatepartofthedateandtime.ThetoLocaleDateString()displaysthedateintheformattheuserhasspecifiedonhiscomputer.OnWindowsoperatingsystems,thisissetintheregionalsettingsofthePC’sControlPanel.However,becauseitreliesontheuser’sPCsetup,thelookofthedatevariesfromcomputertocomputer.ThetoDateString()methoddisplaysthecurrentdatecontainedinthePCdateinastandardformat.
Ofcourse,thisexamplereliesonthefactthattheuser’sclockissetcorrectly,notsomethingyoucanbe100percentsureof—it’samazinghowmanyusershavetheirlocaltimezonesettingssetcompletelywrong.
SettingandGettingaDateObject’sUTCDateandTimeWhenyoucreateanewDateobject,youcaneitherinitializeitwithavalueorletJavaScriptsetittothecurrentdateandtime.Eitherway,JavaScriptassumesyouaresettingthelocaltimevalues.IfyouwanttospecifyUTCtime,youneedtousethesetUTCtypemethods,suchassetUTCHours().
FollowingarethesevenmethodsforsettingUTCdateandtime:
setUTCDate()
setUTCFullYear()
setUTCHours()
setUTCMilliseconds()
setUTCMinutes()
setUTCMonth()
setUTCSeconds()
Thenamesprettymuchgiveawayexactlywhateachmethoddoes,solet’slaunchstraightintoasimpleexample,whichsetstheUTCtime.
TRYITOUTWorkingwithUTCDateandTimeLet’slookataquickexample.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Example2</title>
</head>
<body>
<script>
varmyDate=newDate();
myDate.setUTCHours(12);
myDate.setUTCMinutes(0);
myDate.setUTCSeconds(0);
varhtml="<p>"+myDate.toUTCString()+"</p>";
html+="<p>"+myDate.toLocaleString()+"</p>";
document.write(html);
</script>
</body>
</html>
Savethisasch7_example2.html.Whenyouloaditinyourbrowser,youshouldseesomethinglikewhatisshowninFigure7.3inyourwebpage,althoughtheactualdatewilldependonthecurrentdateandwhereyouareintheworld.
Figure7.3
Youmightwanttochangeyourcomputer’stimezoneandtimeofyeartoseehowitvariesindifferentregionsandwithdaylightsavingschanges.InWindowsyoucanmakethechangesbyopeningtheControlPanelandthendouble-clickingtheDate/Timeicon.
Sohowdoesthisexamplework?Youdeclareavariable,myDate,andsetittoanewDateobject.Becauseyouhaven’tinitializedtheDateobjecttoanyvalue,itcontainsthelocalcurrentdateandtime.
Then,usingthesetUTCmethods,yousetthehours,minutes,andsecondssothatthetimeis12:00:00UTC(midday,notmidnight).
Now,whenyouwriteoutthevalueofmyDateasaUTCstring,youget12:00:00andtoday’sdate.WhenyouwriteoutthevalueoftheDateobjectasalocalstring,yougettoday’sdateandatimethatistheUTCtime12:00:00convertedtotheequivalentlocaltime.Thelocalvaluesyou’llsee,ofcourse,dependonyourtimezone.For
example,NewYorkerswillsee08:00:00duringthesummerand07:00:00duringthewinterbecauseofdaylightsavings.IntheUnitedKingdom,inthewinteryou’llsee12:00:00,butinthesummeryou’llsee13:00:00.
ForgettingUTCdatesandtimes,youhavethesamefunctionsyouwoulduseforsettingUTCdatesandtimes,exceptthatthistime,forexample,it’sgetUTCHours(),notsetUTCHours():
getUTCDate()
getUTCDay()
getUTCFullYear()
getUTCHours()
getUTCMilliseconds()
getUTCMinutes()
getUTCMonth()
getUTCSeconds()
toISOString()
Noticethatthistimeyouhavetwoadditionalmethods,getUTCDay()andtoISOString().ThegetUTCDay()methodworksinthesamewayasthegetDay()methodandreturnsthedayoftheweekasanumber,from0forSundayto6forSaturday.Becausethedayoftheweekisdecidedbythedayofthemonth,themonth,andtheyear,thereisnosetUTCDay()method.
ThetoISOString()methodisrelativelynewtoJavaScript,anditreturnsthedateandtimeinanISO-formattedstring.Theformatis:
YYYY-MM-DDTHH:mm:ss.sssZ
TheISOformatseparatesthedatefromthetimewiththeliteralcharacterT.SoYYYY-MM-DDisthedate,andHH:mm:ss.sssisthetime.TheZattheenddenotestheUTCtimezone.TheISOformattedstringforMarch30,2014at3:10PMUTCis:
2014-03-30T15:10:00Z
WhenyoulearnaboutformsinChapter11,you’llrevisitdatesandtimestobuildatimeconverter.
TIMERSINAWEBPAGEYoucancreatetwotypesoftimers:one-shottimersandcontinuallyfiringtimers.Theone-shottimertriggersjustonceafteracertainperiodoftime,andthesecondtypeoftimercontinuallytriggersatsetintervals.Youinvestigateeachofthesetypesoftimersinthenexttwosections.
Withinreasonablelimits,youcanhaveasmanytimersasyouwantandcansetthemgoingatanypointinyourcode,suchaswhentheuserclicksabutton.Commonusesfortimersincludeanimatingelements,creatingadvertisementbannerpicturesthatchangeatregularintervals,anddisplayingthechangingtimeinawebpage.
One-ShotTimerSettingaone-shottimerisveryeasy;youjustusethesetTimeout()function:
vartimerId=setTimeout(yourFunction,millisecondsDelay)
ThesetTimeout()methodtakestwoparameters.Thefirstisafunctionyouwantexecuted,andthesecondisthedelay,inmilliseconds(thousandthsofasecond),untilthecodeisexecuted.
Themethodreturnsavalue(aninteger),whichisthetimer’suniqueID.Ifyoudecidelaterthatyouwanttostopthetimerfiring,youusethisIDtotellJavaScriptwhichtimeryouarereferringto.
TRYITOUTDelayingaMessageInthisexample,yousetatimerthatfiresthreesecondsafterthepagehasloaded:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Example3</title>
</head>
<body>
<script>
functiondoThisLater(){
alert("Time'sup!");
}
setTimeout(doThisLater,3000);
</script>
</body>
</html>
Savethisfileasch7_example3.html,andloaditintoyourbrowser.
ThispagedisplaysamessageboxthreesecondsafterthebrowserexecutestheJavaScriptcodeinthebodyofthepage.Let’slookatthatcodestartingwiththedoThisLater()function:
functiondoThisLater(){
alert("Time'sup!");
}
Thisfunction,whencalled,simplydisplaysamessageinanalertbox.YoudelaythecallofthisfunctionbyusingsetTimeout():
setTimeout(doThisLater,3000);
TakenotehowdoThisLater()ispassedtosetTimeout()—theparenthesesareomitted.YoudonotwanttocalldoThisLater()here;yousimplywanttorefertothefunctionobject.
ThesecondparametertellsJavaScripttoexecutedoThisLater()after3,000milliseconds,or3seconds,havepassed.
It’simportanttonotethatsettingatimerdoesnotstopthescriptfromcontinuingtoexecute.Thetimerrunsinthebackgroundandfireswhenitstimeisup.Inthemeantimethepagerunsasusual,andanyscriptafteryoustartthetimer’scountdownwillrunimmediately.So,inthisexample,thealertboxtellingyouthatthetimerhasbeensetappearsimmediatelyafterthecodesettingthetimerhasbeenexecuted.
Whatifyoudecidedthatyouwantedtostopthetimerbeforeitfired?
ToclearatimeryouusetheclearTimeout()function.Thistakesjustoneparameter:the
uniquetimerIDreturnedbythesetTimeout()function.
TRYITOUTStoppingaTimerInthisexample,you’llaltertheprecedingexampleandprovideabuttonthatyoucanclicktostopthetimer:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Example4</title>
</head>
<body>
<script>
functiondoThisLater(){
alert("Time'sup!");
}
vartimerId=setTimeout(doThisLater,3000);
clearTimeout(timerId);
</script>
</body>
</html>
Savethisasch7_example4.htmlandloaditintoyourbrowser.YouwillnotseeanalertboxdisplayingtheTime'sup!messagebecauseyoucalledclearTimeout()andpassedthetimerIDbeforethetimeoutcouldexpire.
SettingaTimerthatFiresatRegularIntervalsThesetInterval()andclearInterval()functionsworksimilarlytosetTimeout()andclearTimeout(),exceptthatthetimerfirescontinuallyatregularintervalsratherthanjustonce.
ThesetInterval()functiontakesthesameparametersassetTimeout(),exceptthatthesecondparameternowspecifiestheinterval,inmilliseconds,betweeneachfiringofthetimer,ratherthanjustthelengthoftimebeforethetimerfires.
Forexample,tosetatimerthatfiresthefunctionmyFunction()everyfiveseconds,thecodewouldbeasfollows:
varmyTimerID=setInterval(myFunction,5000);
AswithsetTimeout(),thesetInterval()methodreturnsauniquetimerIDthatyou’llneedifyouwanttoclearthetimerwithclearInterval(),whichworksidenticallytoclearTimeout().Sotostopthetimerstartedintheprecedingcode,youwouldusethefollowing:
clearInterval(myTimerID);
TRYITOUTACountingClockInthisexample,youwriteasimplepagethatdisplaysthecurrentdateandtime.That’snotveryexciting,soyou’llalsomakeitupdateeverysecond:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Example5</title>
</head>
<body>
<divid="output"></div>
<script>
functionupdateTime(){
document.getElementById("output").innerHTML=new
Date();
}
setInterval(updateTime,1000);
</script>
</body>
</html>
Savethisfileasch7_example5.html,andloaditintoyourbrowser.
Inthebodyofthispageisa<div/>element,anditsidattributehasthevalueofoutput:
<divid="output"></div>
Theupdateddateandtimewillbedisplayedinsidethiselement,andthecontentsofthiselementareupdatedbytheupdateTime()function:
functionupdateTime(){
document.getElementById("output").innerText=newDate();
}
Thisfunctionusesthedocument.getElementById()methodtoretrievetheaforementioned<div/>element,anditusestheinnerTextpropertytosettheelement’stexttoanewDateobject.Whendisplayedinthebrowser,JavaScriptconvertstheDateobjecttoahuman-readablestringcontainingboththedateandtime.
Tochangethedateandtime,youusethesetInterval()function,passingitareferencetotheupdateTime()function,andsettingittoexecuteeverysecond(1,000milliseconds).This,inturn,changesthetextinsideofthe<div/>element,thusshowingthecurrentdateandtimeeverysecond.
Thatcompletesyourlookatthisexampleandalsoyourintroductiontotimers.YouusethesetInterval()andclearInterval()functionsinlaterchapters.
SUMMARYYoustartedthechapterbylookingatCoordinatedUniversalTime(UTC),whichisaninternationalstandardtime.Youthenlookedathowtocreatetimersinwebpages.
Theparticularpointscoveredwerethefollowing:
TheDateobjectenablesyoutosetandgetUTCtimeinawaysimilartosettingaDateobject’slocaltimebyusingmethods(suchassetUTCHours()andgetUTCHours())forsettingandgettingUTChourswithsimilarmethodsformonths,years,minutes,seconds,andsoon.
AusefultoolininternationaltimeconversionisthegetTimezoneOffset()method,whichreturnsthedifference,inminutes,betweentheuser’slocaltimeandUTC.Onepitfallofthisisthatyouareassumingtheuserhascorrectlysethistimezoneonhiscomputer.Ifnot,getTimezoneOffset()isrendereduseless,aswillbeanylocaldateandtimemethodsiftheuser’sclockisincorrectlyset.
UsingthesetTimeout()method,youfoundyoucouldstartatimerthatwouldfirejustonceafteracertainnumberofmilliseconds.setTimeout()takestwoparameters:Thefirstisthefunctionyouwantexecuted,andthesecondisthedelaybeforethatcodeisexecuted.Itreturnsavalue,theuniquetimerIDthatyoucanuseifyoulaterwanttoreferencethetimer;forexample,tostopitbeforeitfires,youusetheclearTimeout()method.
Tocreateatimerthatfiresatregularintervals,youusedthesetInterval()method,whichworksinthesamewayassetTimeout(),exceptthatitkeepsfiringunlesstheuserleavesthepageoryoucalltheclearInterval()method.
Inthenextchapter,youturnyourattentiontothewebbrowseritselfand,particularly,thevariousobjectsthatitmakesavailableforyourJavaScriptprogramming.Youseethattheuseofbrowserobjectsiskeytocreatingpowerfulwebpages.
EXERCISES1. Createapagethatgetstheuser’sdateofbirth.Then,usingthatinformation,tellher
onwhatdayoftheweekshewasborn.
2. CreateawebpagesimilartoExample5inthe“ACountingClock”TryItOut,butmakeitdisplayonlythehour,minutes,andseconds.
8ProgrammingtheBrowserWHATYOUWILLLEARNINTHISCHAPTER:
Workingwiththebrowser’snativewindowobject
SendingthebrowsertoaURL
Manipulatingimagesaftertheyareloadedinthepage
Retrievingthebrowser’scurrentgeographicalposition
Detectingtheuser’sbrowser
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Overthepastfewchapters,you’veexaminedthecoreJavaScriptlanguage.You’veseenhowtoworkwithvariablesanddata,performoperationsonthatdata,makedecisionsinyourcode,looprepeatedlyoverthesamesectionofcode,andevenhowtowriteyourownfunctions.YoumovedontolearnhowJavaScriptisanobject-basedlanguage,andyousawhowtoworkwiththenativeJavaScriptobjects.However,youarenotinterestedonlyinthelanguageitself;youwanttofindouthowtowritescriptsforthewebbrowser.Usingthisability,youcanstarttocreatemoreimpressivewebpages.
NotonlyisJavaScriptobject-based,butthebrowserisalsomadeupofobjects.WhenJavaScriptisrunninginthebrowser,youcanaccessthebrowser’sobjectsinexactlythesamewaythatyouusedJavaScript’snativeobjects.Butwhatkindsofobjectsdoesthebrowserprovide?
Thebrowsermakesavailablearemarkablenumberofobjects.Forexample,thereisawindowobjectcorrespondingtothewindowofthebrowser.Youhavealreadybeenusingtwomethodsofthisobject,namelythealert()andprompt()methods.Forsimplicity,wepreviouslyreferredtotheseasfunctions,buttheyare,infact,methodsofthebrowser’swindowobject.
Anotherobjectmadeavailablebythebrowseristhepageitself,representedbythedocumentobject.Again,youhavealreadyusedmethodsandpropertiesofthisobject.Recallfrompreviouschaptersthatyouusedthedocumentobject’swrite()methodtowriteinformationtothepage.
Avarietyofotherobjectsexist,representativeoftheHTMLyouwriteinthepage.Forexample,thereisanimgobjectforeach<img/>elementthatyouusetoinsertanimageintoyourdocument.
ThecollectionofobjectsthatthebrowsermakesavailabletoyouforusewithJavaScript
isgenerallycalledthebrowserobjectmodel(BOM).
NOTEYouwilloftenseethistermedthedocumentobjectmodel(DOM);itisincorrecttodoso.Throughoutthisbook,we’llusethetermDOMtorefertotheW3C’sstandarddocumentobjectmodel,whichisdiscussedinthenextchapter.
AllthisaddedfunctionalityofJavaScriptcomeswithapotentialdownside:ThereisnostandardBOMimplementation(althoughsomeattemptisbeingmadewiththeHTML5specification).Whichcollectionsofobjectsaremadeavailabletoyouishighlydependentonthebrandandversionofthebrowserthatyouareusing.Someobjectsaremadeavailableinsomebrowsersandnotinothers,whereasotherobjectshavedifferentpropertiesandmethodsindifferentbrowsers.Thegoodnewsisthatbrowsermakerstypicallydonotchangemuchoftheirbrowser’sBOM,becausedoingsowouldcreateariftininteroperability.ThismeansifyousticktothecorefunctionalityoftheBOM(thecommonobjectsinallbrowsers),yourcodeismorelikelytoworkbetweenthedifferentbrowsersandversions.Thischapter’sfocusistheBOMcorefunctionality.YoucanachievealotinJavaScriptbyjuststickingtothecore.
INTRODUCTIONTOTHEBROWSER’SOBJECTSThissectionintroducestheobjectsoftheBOMthatarecommontoallbrowsers.
InChapter5,yousawthatJavaScripthasanumberofnativeobjectsthatyoucanaccessanduse.Mostoftheobjectsarethosethatyouneedtocreateyourself,suchastheStringandDateobjects.Others,suchastheMathobject,existwithoutyouneedingtocreatethemandarereadyforuseimmediatelywhenthepagestartsloading.
WhenJavaScriptisrunninginawebpage,ithasaccesstoalargenumberofotherobjectsmadeavailablebythewebbrowser.LiketheMathobject,thesearecreatedforyouratherthanyourneedingtocreatethemexplicitly.Asmentioned,theobjects,theirmethods,properties,andeventsareallmappedoutintheBOM.
TheBOMisverylargeandpotentiallyoverwhelmingatfirst.However,you’llfindthatinitiallyyouwon’tbeusingmorethan10percentoftheavailableobjects,methods,andpropertiesintheBOM.YoustartinthischapterbylookingatthemorecommonlyusedpartsoftheBOM,asshowninFigure8.1.ThesepartsoftheBOMare,toacertainextent,commonacrossallbrowsers.Laterchaptersbuildonthissothatbytheendofthebookyou’llbeabletoreallymaketheBOMworkforyou.
Figure8.1
TheBOMhasahierarchy.Attheverytopofthishierarchyisthewindowobject.Youcanthinkofthisasrepresentingtheframeofthebrowserandeverythingassociatedwithit,suchasthescrollbars,navigatorbaricons,andsoon.
Containedinsidethewindowframeisthepage.ThepageisrepresentedintheBOMbythedocumentobject.YoucanseethesetwoobjectsrepresentedinFigure8.2.
Figure8.2
Nowlet’slookateachoftheseobjectsinmoredetail.
ThewindowObjectThewindowobjectrepresentsthebrowser’sframeorwindow,inwhichyourwebpageiscontained.Tosomeextent,italsorepresentsthebrowseritselfandincludesanumberofpropertiesthataretheresimplybecausetheydon’tfitanywhereelse.Forexample,viathepropertiesofthewindowobject,youcanfindoutwhatbrowserisrunning,thepagestheuserhasvisited,thesizeofthebrowserwindow,thesizeoftheuser’sscreen,andmuchmore.Youcanalsousethewindowobjecttoaccessandchangethetextinthebrowser’sstatusbar,changethepagethatisloaded,andevenopennewwindows.
Thewindowobjectisaglobalobject,whichmeansyoudon’tneedtouseitsnametoaccessitspropertiesandmethods.Infact,theglobalfunctionsandvariables(theonesaccessibleforyoutoscriptanywhereinapage)areallcreatedaspropertiesoftheglobalobject.Forexample,thealert()functionyouhavebeenusingsincethebeginningofthebookis,infact,thealert()methodofthewindowobject.Althoughyouhavebeenusingthissimplyasthis:
alert("Hello!");
Youcouldwritethiswiththesame,exactresults:
window.alert("Hello!");
However,becausethewindowobjectistheglobalobject,itisperfectlycorrecttousethefirstversion.
Someofthepropertiesofthewindowobjectarethemselvesobjects.Thosecommontoallbrowsersincludethedocument,navigator,history,screen,andlocationobjects.Thedocumentobjectrepresentsyourpage,thehistoryobjectcontainsthehistoryofpagesvisitedbytheuser,thenavigatorobjectholdsinformationaboutthebrowser,thescreen
objectcontainsinformationaboutthedisplaycapabilitiesoftheclient,andthelocationobjectcontainsdetailsonthecurrentpage’slocation.Youlookattheseimportantobjectsindividuallylaterinthechapter.
Atthispointit’sworthhighlightingthefactthat,withinawebpage,youshouldn’tusenamesforyourfunctionsorvariablesthatconflictwithnamesofBOMobjectsortheirpropertiesandmethods.Ifyoudo,youmaynotgetanerror,butinsteadgetunexpectedresults.Forexample,thefollowingcodedeclaresavariablenamedhistory,andtriestousethehistorypropertyofthewindowobjecttogobacktothepreviouspage.This,however,won’tworkbecausehistoryhasbeenchangedtoholdadifferentvalue:
varhistory="Hello,BOM!";
window.history.back();//error;stringobjectsdon'thaveaback()method
Inthissituationyouneedtouseadifferentvariablename.Thishappensbecauseanyfunctionorvariableyoudefinewithintheglobalscopeactuallygetsappendedtothewindowobject.Lookatthiscodeasanexample:
varmyVariable="Hello,World!";
alert(window.myVariable);
Ifyouweretoexecutethiscodeinabrowser,thealertwindowwoulddisplaythemessage“Hello,World.”
AswithalltheBOMobjects,youcanlookatlotsofpropertiesandmethodsforthewindowobject.However,inthischapteryouconcentrateonthehistory,location,navigator,screen,anddocumentproperties.Allfiveofthesepropertiescontainobjects(thehistory,location,navigator,screen,anddocumentobjects),eachwithitsownpropertiesandmethods.Inthenextfewpages,youlookateachoftheseobjectsinturnandfindouthowtheycanhelpyoumakefulluseoftheBOM.
ThehistoryObjectThehistoryobjectkeepstrackofeachpagethattheuservisits.Thislistofpagesiscommonlycalledthehistorystackforthebrowser.Itenablestheusertoclickthebrowser’sBackandForwardbuttonstorevisitpages.Youhaveaccesstothisobjectviathewindowobject’shistoryproperty.
LikethenativeJavaScriptArraytype,thehistoryobjecthasalengthproperty.Youcanusethistofindouthowmanypagesareinthehistorystack.
Asyoumightexpect,thehistoryobjecthastheback()andforward()methods.Whentheyarecalled,thelocationofthepagecurrentlyloadedinthebrowserischangedtothepreviousornextpagethattheuserhasvisited.
Thehistoryobjectalsohasthego()method.Thistakesoneparameterthatspecifieshowfarforwardorbackwardinthehistorystackyouwanttogo.Forexample,ifyouwantedtoreturntheusertothepagebeforethepreviouspage,you’dwritethis:
history.go(-2);
Togoforwardthreepages,you’dwritethis:
history.go(3);.
Notethatgo(-1)andback()areequivalent,asarego(1)andforward().
ThelocationObjectThelocationobjectcontainslotsofpotentiallyusefulinformationaboutthecurrentpage’slocation.Notonlydoesitcontaintheuniformresourcelocator(URL)forthepage,butalsotheserverhostingthepage,theportnumberoftheserverconnection,andtheprotocolused.Thisinformationismadeavailablethroughthelocationobject’shref,hostname,port,andprotocolproperties.However,manyofthesevaluesareonlyreallyrelevantwhenyouareloadingthepagefromaserverandnot,asyouaredoinginthepresentexamples,loadingthepagedirectlyfromalocalharddrive.
Inadditiontoretrievingthecurrentpage’slocation,youcanusethemethodsofthelocationobjecttochangethelocationandrefreshthecurrentpage.
Youcannavigatetoanotherpageintwoways.Youcaneithersetthelocationobject’shrefpropertytopointtoanotherpage,oryoucanusethelocationobject’sreplace()method.Theeffectofthetwoisthesame;thepagechangeslocation.However,theydifferinthatthereplace()methodremovesthecurrentpagefromthehistorystackandreplacesitwiththenewpageyouaremovingto,whereasusingthehrefpropertysimplyaddsthenewpagetothetopofthehistorystack.Thismeansthatifthereplace()methodhasbeenusedandtheuserclickstheBackbuttoninthebrowser,theusercan’tgobacktotheoriginalpageloaded.Ifthehrefpropertyhasbeenused,theusercanusetheBackbuttonasnormal.
Forexample,toreplacethecurrentpagewithanewpagecalledmyPage.html,you’dusethereplace()methodandwritethefollowing:
location.replace("myPage.html");
ThisloadsmyPage.htmlandreplacesanyoccurrenceofthecurrentpageinthehistorystackwithmyPage.html.
Toloadthesamepageandtoaddittothehistoryofpagesnavigatedto,youusethehrefproperty:
location.href="myPage.html";
Thisaddsthecurrentlyloadedpagetothehistory.Inbothoftheprecedingcases,windowisinfrontoftheexpression,butbecausethewindowobjectisglobalthroughoutthepage,youcouldhavewrittenoneofthefollowing:
location.replace("myPage.html");
location.href="myPage.html";
ThenavigatorObjectThenavigatorobjectisanotherobjectthatisapropertyofwindowandisavailableinallbrowsers.Itsnameismorehistoricalthandescriptive.Perhapsabetternamewouldbethe
“browserobject,”becausethenavigatorobjectcontainslotsofinformationaboutthebrowserandtheoperatingsysteminwhichit’srunning.
Historically,themostcommonuseofthenavigatorobjectisforhandlingbrowserdifferences.Usingitsproperties,youcanfindoutwhichbrowser,version,andoperatingsystemtheuserhas.Youcanthenactonthatinformationandmakesureyourcodeworksonlyinbrowsersthatsupportit.Thisisreferredtoasbrowsersniffing,andthoughithasitsuses,itdoeshavelimitations.
Abetteralternativetobrowsersniffingisfeaturedetection,theactofdeterminingifabrowsersupportsaparticularfeature.Wewon’tgointothesesubjectshere;latersectionsofthischapteraredevotedtobrowsersniffingandfeaturedetection.
ThegeolocationObjectTheHTML5specificationaddsthegeolocationpropertytonavigator.Itspurposeissimple:toenabledeveloperstoobtainandusethepositionofthedeviceorcomputer.Thatsoundslikeascaryproposition,butusersmustgivepermissionforthatinformationtoberetrievedandused.
AttheheartofthegeolocationobjectisitsgetCurrentPosition()method.Whenyoucallthismethod,youmustpassitacallbackfunction,whichisafunctionthatexecuteswhengetCurrentPosition()successfullycompletesitswork.InChapter4,youlearnedthatfunctionsarevalues.Youcanassignthemtovariablesandpassthemtootherfunctions,andthelatteriswhatyoudowiththegetCurrentPosition()method.Forexample:
functionsuccess(position){
alert("Ihaveyounow!");
}
navigator.geolocation.getCurrentPosition(success);
Inthiscode,success()isthecallbackfunctionthatexecuteswhennavigator.geolocation.getCurrentPosition()determinesthecomputer’sordevice’slocation.Theparameter,position,isanobjectthatcontainstheEarthlypositionandaltitudeofthecomputerordevice,andyoucanretrievethesepiecesofinformationthroughitscoordsproperty,likethis:
functionsuccess(position){
varlatitude=position.coords.latitude;
varlongitude=position.coords.longitude;
varaltitude=position.coords.altitude;
varspeed=position.coords.speed;
}
Thelatitude,longitude,andaltitudepropertiesareself-explanatory;theyaresimplynumericvaluesrepresentingthelatitude,longitude,andaltitudeofthedeviceorcomputer,respectively.Thespeedpropertyretrievesthespeed,orratherthevelocity,ofthedevice/computerinmeterspersecond.
Ifyouneedtoretrievemorethanoneofthesevalues,itmakessensetoassign
position.coordstoavariableandthenusethevariabletoretrievethepositionalvalues.Forexample:
functionsuccess(position){
varcrds=position.coords;
varlatitude=crds.latitude;
varlongitude=crds.longitude;
varaltitude=crds.altitude;
varspeed=crds.speed;
}
Thisreducestheamountofcodeyouhavetotype.Italsohastheadvantageofreducingthesizeofyourcode,resultinginaslightlyfasterdownloadtime.
ThegetCurrentPosition()methodacceptsasecondparameter,anothercallbackfunctionthatexecuteswhenanerroroccurs:
functiongeoError(errorObj){
alert("Uhoh,somethingwentwrong");
}
navigator.geolocation.getCurrentPosition(success,geoError);
TheerrorcallbackfunctionhasasingleparameterthatrepresentsthereasonforgetCurrentPosition()’sfailure.Itisanobjectcontainingtwoproperties.Thefirst,code,isanumericvalueindicatingthereasonoffailure.Thefollowingtableliststhepossiblevaluesandtheirmeanings:
VALUE DESCRIPTION1 Failureoccurredbecausethepagedidnothavepermissiontoacquirethe
positionofthedevice/computer.2 Aninternalerroroccurred.3 Thetimeallowedtoretrievethedevice’s/computer’spositionwasreached
beforethepositionwasobtained.
Thesecondpropertyiscalledmessage;it’sahuman-readablemessagethatdescribestheerror.
TRYITOUTUsingGeolocationInthisexample,youusethegeolocationobjecttoretrievethelatitudeandlongitudeofthedevice/computer:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Example1</title>
</head>
<body>
<script>
functiongeoSuccess(position){
varcoords=position.coords;
varlatitude=coords.latitude;
varlongitude=coords.longitude;
varmessage="You'reat"+latitude+","+
longitude
alert(message);
}
functiongeoError(errorObj){
alert(errorObj.message);
}
navigator.geolocation.getCurrentPosition(geoSuccess,
geoError);
</script>
</body>
</html>
Savethepageasch8_example1.htmlandloaditintoyourbrowser.
Thepagerequirestheuser’sconsentinordertoretrievehisorhergeographicalposition.Sothefirstthingyouwillseeisapromptaskingyoutoallowordenythepagepermissiontoretrievethatinformation.Everybrowserdisplaysthisrequestdifferently;Figure8.3isChrome’srequest.
Figure8.3
Ifyouallowthepagetoaccessyourposition,you’llseethelatitudeandlongitudeofyourdeviceorcomputerdisplayedinanalertbox.Ifyouchoosetodenyaccess,
you’llseeamessagesimilartothatshowninFigure8.4.
Figure8.4
Twofunctionsinthispageareresponsiblefortheaforementionedbehavior.Thefirstfunction,geoSuccess(),isthecallbackfunctionthatexecuteswhenthebrowsercansuccessfullyretrieveyourdevice’s/computer’sposition:
functiongeoSuccess(position){
varcoords=position.coords;
varlatitude=coords.latitude;
varlongitude=coords.longitude;
Thefirststatementinthisfunctionstoresposition.coordsinthecoordsvariabletoaccessthepositionalinformationwithfewerkeystrokes.Thesecondandthirdstatementsretrievethelatitudeandlongitude,respectively.
Nowthatyouhavethelatitudeandlongitude,youassembleamessagethatcontainsthisinformationanddisplayittotheuser:
varmessage="You'reat"+latitude+","+longitude
alert(message);
}
Ifyoudeniedthepageaccesstoyourposition,orifthebrowsercannotobtainyourposition,thegeoError()callbackfunctionexecutes:
functiongeoError(errorObj){
alert(errorObj.message);
}
Thissimplefunctionsimplyusestheerrorobject’smessagepropertytotelltheuserwhygetCurrentPosition()failed.
ThescreenObjectThescreenobjectpropertyofthewindowobjectcontainsalotofinformationaboutthedisplaycapabilitiesoftheclientmachine.Itspropertiesincludetheheightandwidthproperties,whichindicatetheverticalandhorizontalrangeofthescreen,respectively,in
pixels.
Anotherpropertyofthescreenobject,whichyouuseinanexamplelater,isthecolorDepthproperty.Thistellsyouthenumberofbitsusedforcolorsontheclient’sscreen.
ThedocumentObjectAlongwiththewindowobject,thedocumentobjectisprobablyoneofthemostimportantandcommonlyusedobjectsintheBOM.ViathisobjectyoucangainaccesstotheHTMLelements,theirproperties,andtheirmethodsinsideyourpage.
Thischapterconcentratesonthebasicpropertiesandmethodsthatarecommontoallbrowsers.MoreadvancedmanipulationofthedocumentobjectiscoveredinChapter9.
Thedocumentobjecthasanumberofpropertiesassociatedwithit,whicharealsoarray-likestructurescalledcollections.Themaincollectionsaretheforms,images,andlinkscollections.InternetExplorersupportsanumberofothercollectionproperties,suchastheallcollectionproperty,whichisanarrayofalltheelementsrepresentedbyobjectsinthepage.However,you’llconcentrateonusingobjectsthathavestandardcross-browsersupport,sothatyouarenotlimitingyourwebpagestojustonebrowser.
Youlookattheimagesandlinkscollectionsshortly.Athirdcollection,theformscollection,isoneofthetopicsofChapter11whenyoulookatformsinwebbrowsers.First,though,youlookatanice,simpleexampleofhowtousethedocumentobject’smethodsandproperties.
UsingthedocumentObjectYou’vealreadycomeacrosssomeofthedocumentobject’spropertiesandmethods—forexample,thewrite()methodandthebgColorproperty.
TRYITOUTSettingColorsAccordingtotheUser’sScreenColorDepth
Inthisexample,yousetthebackgroundcolorofthepageaccordingtohowmanycolorstheuser’sscreensupports.Thisistermedscreencolordepth.Iftheuserhasadisplaythatsupportsjusttwocolors(blackandwhite),there’snopointinyousettingthebackgroundcolortobrightred.YouaccommodatedifferentdepthsbyusingJavaScripttosetacolortheusercanactuallysee.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Example2</title>
</head>
<body>
<script>
varcolorDepth=window.screen.colorDepth;
switch(colorDepth){
case1:
case4:
document.bgColor="white";
break;
case8:
case15:
case16:
document.bgColor="blue";
break;
case24:
case32:
document.bgColor="skyblue";
break;
default:
document.bgColor="white";
}
document.write("Yourscreensupports"+colorDepth+
"bitcolor");
</script>
</body>
</html>
Savethepageasch8_example2.html.Whenyouloaditintoyourbrowser,thebackgroundcolorofthepagewillbedeterminedbyyourcurrentscreencolordepth.Also,amessageinthepagewilltellyouwhatthecolordepthcurrentlyis.
Youcantestthatthecodeisworkingproperlybychangingthecolorssupportedbyyourscreen.Byrefreshingthebrowser,youcanseewhatdifferencethismakestothecolorofthepage.
NOTEInFirefox,Safari,andChromebrowsers,it’snecessarytoshutdownandrestartthebrowsertoobserveanyeffect.
Asyousawearlier,thewindowobjecthasthescreenobjectproperty.OneofthepropertiesofthisobjectisthecolorDepthproperty,whichreturnsavalueof1,4,8,15,16,24,or32.Thisrepresentsthenumberofbitsassignedtoeachpixelonyourscreen.(Apixelisjustoneofthemanydotsthatmakeupyourscreen.)Toworkouthowmanycolorsyouhave,youjustcalculatethevalueof2tothepowerofthecolorDepthproperty.Forexample,acolorDepthof1meansthattwocolorsareavailable,acolorDepthof8meansthat256colorsareavailable,andsoon.Currently,mostpeoplehaveascreencolordepthofatleast8,butusually24or32.
Thefirsttaskofthescriptblockistosetthecolorofthebackgroundofthepagebasedonthenumberofcolorstheusercanactuallysee.Youdothisinabigswitchstatement.TheconditionthatischeckedforintheswitchstatementisthevalueofthecolorDepthvariable,whichissettowindow.screen.colorDepth:
varcolorDepth=window.screen.colorDepth;
switch(colorDepth){
Youdon’tneedtosetadifferentcolorforeachcolorDepthpossible,becausemanyofthemaresimilarwhenitcomestogeneralwebuse.Instead,yousetthesamebackgroundcolorfordifferent,butsimilar,colorDepthvalues.ForacolorDepthof1or4,yousetthebackgroundtowhite.Youdothisbydeclaringthecase1:statement,butyoudon’tgiveitanycode.IfthecolorDepthmatchesthiscasestatement,itwillfallthroughtothecase4:statementbelowit,whereyoudosetthebackgroundcolortowhite.Youthencallabreakstatement,sothatthecasematchingwillnotfallanyfurtherthroughtheswitchstatement:
case1:
case4:
document.bgColor="white";
break;
YoudothesamewithcolorDepthvaluesof8,15,and16,settingthebackgroundcolortoblueasfollows:
case8:
case15:
case16:
document.bgColor="blue";
break;
Finally,youdothesameforcolorDepthvaluesof24and32,settingthebackgroundcolortoskyblue:
case24:
case32:
document.bgColor="skyblue";
break;
Youendtheswitchstatementwithadefaultcase,justincasetheothercasestatementsdidnotmatch.Inthisdefaultcase,youagainsetthebackgroundcolortowhite:
default:
document.bgColor="white";
}
Inthenextbitofscript,youusethedocumentobject’swrite()method,somethingyou’vebeenusingintheseexamplesforawhilenow.Youuseittowritetothedocument—thatis,thepage—thenumberofbitsatwhichthecolordepthiscurrentlyset,asfollows:
document.write("Yourscreensupports"+colorDepth+
"bitcolor")
You’vealreadybeenusingthedocumentobjectintheexamplesthroughoutthebook.YouuseditsbgColorpropertyinChapter1tochangethebackgroundcolorofthepage,andyou’vealsomadegooduseofitswrite()methodintheexamplestowrite
HTMLandtextouttothepage.
Nowlet’slookatsomeoftheslightlymorecomplexpropertiesofthedocumentobject.Thesepropertieshaveincommonthefactthattheyallcontaincollections.Thefirstoneyoulookatisacollectioncontaininganobjectforeachimageinthepage.
TheimagesCollectionAsyouknow,youcaninsertanimageintoanHTMLpageusingthefollowingtag:
<imgalt="USA"name="myImage"src="usa.gif"/>
ThebrowsermakesthisimageavailableforyoutomanipulatewithJavaScriptbycreatinganimgobjectforitwiththenamemyImage.Infact,eachimageonyourpagehasanimgobjectcreatedforit.
Eachoftheimgobjectsinapageisstoredintheimagescollection,whichisapropertyofthedocumentobject.Youusethis,andothercollections,asyouwouldanarray.Thefirstimageonthepageisfoundintheelementdocument.images[0],thesecondindocument.images[1],andsoon.
Ifyouwantto,youcanassignavariabletoreferenceanimgobjectintheimagescollection.Itcanmakecodeeasiertotypeandread.Forexample,thefollowingcodeassignsareferencetotheimgobjectatindexposition1tothemyImage2variable:
varmyImage2=document.images[1];
NowyoucanwritemyImage2insteadofdocument.images[1]inyourcode,withexactlythesameeffect.
Becausethedocument.imagespropertyisacollection,ithaspropertiessimilartothenativeJavaScriptArraytype,suchasthelengthproperty.Forexample,ifyouwanttoknowhowmanyimagesareonthepage,thecodedocument.images.lengthwilltellyou.
TRYITOUTImageSelectionTheimgobjectitselfhasanumberofusefulproperties.Themostimportantoftheseisitssrcproperty.Bychangingthis,youcanchangetheimagethat’sloaded.Thisexampledemonstratesthis:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Example3</title>
</head>
<body>
<imgsrc=""width="200"height="150"alt="MyImage"/>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
varimgIndex=prompt("Enteranumberfrom0to3","");
document.images[0].src=myImages[imgIndex];
</script>
</body>
</html>
Savethisasch8_example3.html.Youwillalsoneedfourimagefiles,calledusa.gif,canada.gif,jamaica.gif,andmexico.gif.Youcancreatetheseimagesyourselforobtaintheonesprovidedwiththecodedownloadforthebook.
Apromptboxasksyoutoenteranumberfrom0to3whenthispageloadsintothebrowser.Adifferentimageisdisplayeddependingonthenumberyouenter.
AtthetopofthepageyouhaveyourHTML<img/>element.Noticethatthesrcattributeisleftempty:
<imgsrc=""width="200"height="150"alt="MyImage"/>
Nextyoucometothescriptblockwheretheimagetobedisplayedisdecided.Onthefirstline,youdefineanarraycontainingalistofimagesources.Inthisexample,theimagesareinthesamedirectoryastheHTMLfile,soapathisnotspecified.Ifyoursarenot,makesureyouenterthefullpath(forexample,C:\myImages\mexico.gif).
Thenyouasktheuserforanumberfrom0to3,whichwillbeusedasthearrayindextoaccesstheimagesourceinthemyImagesarray:
varimgIndex=prompt("Enteranumberfrom0to3","");
Finally,yousetthesrcpropertyoftheimgobjecttothesourcetextinsidethemyImagesarrayelementwiththeindexnumberprovidedbytheuser:
document.images[0].src=myImages[imgIndex];
Don’tforgetthatwhenyouwritedocument.images[0],youareaccessingtheimgobjectstoredintheimagescollection.It’sanindexpositionof0,becauseit’sthefirst(andonly)imageonthispage.
ThelinksCollectionForeachhyperlinkelement<a/>definedwithanhrefattribute,thebrowsercreatesanaobject.Themostimportantpropertyoftheaobjectisthehrefproperty,correspondingtothehrefattributeofthetag.Usingthis,youcanfindoutwherethelinkpointsto,andyoucanchangethisevenafterthepagehasloaded.
Thecollectionofallaobjectsinapageiscontainedwithinthelinkscollection,muchastheimgobjectsarecontainedintheimagescollection,asyousawearlier.
DETERMININGTHEUSER’SBROWSERManybrowsers,versionsofthosebrowsers,andoperatingsystemsareoutthereontheInternet,eachwithitsownversionoftheBOM,itsownsetoffeatures,anditsownparticularquirks.It’sthereforeimportantthatyoumakesureyourpageswillworkcorrectlyonallbrowsers,oratleastdegradegracefully,suchasbydisplayingamessagesuggestingthattheuserupgradehisorherbrowser.
Youhavetwowaystotestifthebrowsercanexecuteyourcode:featuredetectionandbrowsersniffing.Theyshareasimilarendgoal(toexecutecodeforagivenbrowser),buttheyareusedfordifferentpurposes.
FeatureDetectionNotallbrowserssupportthesamefeatures(althoughtoday’smodernbrowsersdoaverygoodjobofit).Whenwesay“feature,”we’renotreferringtotabbedbrowsing,downloadmanagers,andsoon.Wemeanfeaturesthatwe,asJavaScriptdevelopers,canaccessanduseinourcode.
Featuredetectionistheprocessofdeterminingifabrowsersupportsagivenfeature,anditisthepreferredmethodofbrowserdetection.Itrequireslittlemaintenance,anditisusedtoexecutecodeacrossallbrowsersthatimplement(ordon’timplement)aspecificfeature.
Forexample,allmodernbrowserssupportnavigator.geolocation.Youcanuseitinyourpage,andvisitorsusingthosebrowserswillnotexperienceanyissues.However,visitorsusingInternetExplorer8wouldexperiencescripterrorsbecauseIE8doesnotsupportgeolocation.
Thisisacommonproblembecauseeventhelatestversionsofbrowsersdon’talwayssupportthesamefeatures,butyoucanavoidthesetypesofissueswithfeaturedetection.Thepatternissimple:Checkifthefeatureexists,andonlyusethefeatureifitdoes.Therefore,allyouneedisanifstatement,likethis:
if(navigator.geolocation){
//usegeolocation
}
Whoa!Waitaminute!Thiscodeusesnavigator.geolocationastheifstatement’scondition!Isn’ttheifstatementsupposedtoworkontrueorfalsevalues?Yes,butJavaScriptcantreatanyvalueastrueorfalse.Wecallthesetruthyandfalsey.Theyaren’ttruebooleanvalues,buttheyevaluatetotrueandfalsewhenusedinaconditionalstatement.
Here’showthisworks;thefollowingvaluesarefalsey:
0
""(anemptystring)
null
undefined
[](anemptyarray)
false
Justabouteverythingelseistruthy.
Inbrowsersthatdon’tsupportgeolocation,navigator.geolocationisundefinedandisthereforefalsey.
Weknowthatthiscanbeconfusing,anditcanaddsomeambiguitytoyourcode.SomanyJavaScriptdevelopersliketoavoidusingtruthy/falseystatements,andoptforaclearercomparisonbyusingthetypeofoperator,likethis:
if(typeofnavigator.geolocation!="undefined"){
//usegeolocation
}
Thetypeofoperatorreturnsastringthattellsyouthetypeofavalueorobject.Inthiscode,thetypeofoperatorisusedonnavigator.geolocation.Inbrowsersthatsupportgeolocation,thetypeis"object";inbrowsersthatdon’t,it’s"undefined".
Youcanusethetypeofoperatoronanyobjectorvalue.Refertothefollowingtableforthepossiblevaluesreturnedbytypeof:
STATEMENT RESULTtypeof1 numbertypeof"hello" stringtypeoftrue booleantypeof[](oranyarray) objecttypeof{}(oranyobject) objecttypeofundefined undefinedtypeofnull object
TRYITOUTUsingFeatureDetectionInthisexample,youmodifych8_example1.htmlandensurethatthepageworksinbrowsersthatdonotsupportgeolocation.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Example4</title>
</head>
<body>
<script>
functiongeoSuccess(position){
varcoords=position.coords;
varlatitude=coords.latitude;
varlongitude=coords.longitude;
varmessage="You'reat"+latitude+","+
longitude
alert(message);
}
functiongeoError(errorObj){
alert(errorObj.message);
}
if(typeofnavigator.geolocation!="undefined"){
navigator.geolocation.getCurrentPosition(geoSuccess,
geoError);
}else{
alert("Thispageusesgeolocation,andyour"+
"browserdoesn'tsupportit.");
}
</script>
</body>
</html>
Savethisexampleasch8_example4.html.
Thekeydifferenceinthisexampleistheif…elsestatementatthebottomoftheJavaScriptcode:
if(typeofnavigator.geolocation!="undefined"){
navigator.geolocation.getCurrentPosition(geoSuccess,geoError);
}else{
alert("Thispageusesgeolocation,andyour"+
"browserdoesn'tsupportit.");
}
Here,youusethetypeofoperatoronnavigator.geolocationtodetermineifthebrowsersupportsthatfeature.Ifitdoes,thegetCurrentPosition()methodiscalled.
Ifthebrowserdoesn’tsupportgeolocation,thecodedisplaysamessagetotheuserstatingthathisorherbrowserdoesn’tsupportthenecessaryfeature.Ifyouhadattemptedtousegeolocationwithoutensuringthatthebrowsersupportsit,thebrowserwouldthrowanerror.
Featuredetectionisextremelyuseful,anditenablesyoutoisolatebrowsersbasedonthefeaturestheydoordon’tsupport.Butbrowsermakersarenotperfect,andtheysometimesreleaseaversionofabrowserthatexhibitsuniqueandquirkybehavior.Inthesecases,youneedtoisolateanindividualbrowser,andfeaturedetectionrarelygivesyouthatfinelevelofcontrol.
BrowserSniffingFirst,letusreiteratethispoint:Mostofthetime,youwanttousefeaturedetection.Browsersniffinghasmanydrawbacks,oneofwhichisthatsomelesscommonbrowsersmayfalselyidentifythemselvesasamorecommonbrowser.Anotherproblemisthatbrowsersniffingreliesonthebrowser’suser-agentstring,whichisastringthatidentifiesthebrowser,andbrowsermakerscandrasticallychangetheuser-agentstringbetween
differentversions(youseeanexampleofthislater).Youshouldusethetechniquescontainedinthissectiononlywhenyouneedtotargetasinglebrowserforitsownquirkybehavior.
Thenavigatorobjectexposestwopropertiesthatareusefulinidentifyingabrowser:appNameanduserAgent.TheappNamepropertyreturnsthemodelofthebrowser,suchas“MicrosoftInternetExplorer”forIEor“Netscape”forFirefox,Chrome,andSafari.
TheuserAgentpropertyreturnsastringcontainingvariousbitsofinformation,suchasthebrowserversion,operatingsystem,andbrowsermodel.However,thevaluereturnedbythispropertyvariesfrombrowsertobrowser,soyouhavetobevery,verycarefulwhenusingit.Forexample,thebrowser’sversionisembeddedindifferentlocationsofthestring.
TRYITOUTCheckingforandDealingwithDifferentBrowsersInthisexample,youcreateapagethatusestheaforementionedpropertiestodiscovertheclient’sbrowserandbrowserversion.Thepagecanthentakeactionbasedontheclient’sspecifications.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Example5</title>
</head>
<body>
<script>
functiongetBrowserName(){
varlsBrowser=navigator.userAgent;
if(lsBrowser.indexOf("MSIE")>=0){
return"MSIE";
}elseif(lsBrowser.indexOf("Firefox")>=0){
return"Firefox";
}elseif(lsBrowser.indexOf("Chrome")>=0){
return"Chrome";
}elseif(lsBrowser.indexOf("Safari")>=0){
return"Safari";
}elseif(lsBrowser.indexOf("Opera")>=0){
return"Opera";
}else{
return"UNKNOWN";
}
}
functiongetBrowserVersion(){
varua=navigator.userAgent;
varbrowser=getBrowserName();
varfindIndex=ua.indexOf(browser)+browser.length+1;
varbrowserVersion=parseFloat(
ua.substring(findIndex,findIndex+3));
returnbrowserVersion;
}
varbrowserName=getBrowserName();
varbrowserVersion=getBrowserVersion();
if(browserName=="MSIE"){
if(browserVersion<9){
document.write("YourversionofIEistooold");
}else{
document.write("YourversionofIEisfully
supported");
}
}elseif(browserName=="Firefox"){
document.write("Firefoxisfullysupported");
}elseif(browserName=="Safari"){
document.write("Safariisfullysupported");
}elseif(browserName=="Chrome"){
document.write("Chromeisfullysupported");
}elseif(browserName=="Opera"){
document.write("Operaisfullysupported");
}else{
document.write("Sorrythisbrowserversionisnot
supported");
}
</script>
</body>
</html>
Savethisfileasch8_example5.html.
IfthebrowserisFirefox,IE9or10,Safari,Chrome,orOpera,amessageappearstellingusersthatthebrowserissupported.Ifit’sanearlierversionofIE,theuserseesamessagetellinghimorhertheversionofthatbrowserisnotsupported.
Ifit’snotoneofthosebrowsers(includingIE11+),theuserseesamessagesayingthebrowserisunsupported.
Atthetopofthescriptblockaretwoimportantfunctions.ThegetBrowserName()functionfindsoutthenameofthebrowserandthegetBrowserVersion()functionfindsoutthebrowserversion.
Thekeytothebrowser-checkingcodeisthevaluereturnedbythenavigator.userAgentproperty.Hereareafewexampleuser-agentstringsfromcurrentbrowsers:
1. Mozilla/5.0(WindowsNT6.3;WOW64;Trident/7.0;.NET4.0E;.NET4.0C;.NETCLR3.5.30729;.NETCLR2.0.50727;.NETCLR
3.0.30729;rv:11.0)likeGecko
2. Mozilla/5.0(compatible;MSIE10.0;WindowsNT6.3;WOW64;Trident/7.0;.NET4.0E;.NET4.0C;.NETCLR3.5.30729;.NETCLR
2.0.50727;.NETCLR3.0.30729)
3. Mozilla/5.0(WindowsNT6.3;WOW64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/34.0.1847.131Safari/537.36
4. Mozilla/5.0(WindowsNT6.3;WOW64;rv:32.0)Gecko/20100101Firefox/32.0
HereeachlineoftheuserAgentstringshasbeennumbered.Lookingcloselyateachline,it’snothardtoguesswhichbrowsereachagentstringrelatesto.Inorder:
1. MicrosoftIE11
2. MicrosoftIE10
3. Chrome34.0.1847.131
4. Firefox32
Usingthisinformation,let’sstartonthefirstfunction,getBrowserName().Firstyougetthenameofthebrowser,asfoundinnavigator.userAgent,andstoreitinthevariablelsBrowser:
functiongetBrowserName(){
varlsBrowser=navigator.userAgent;
Thestringreturnedbythispropertytendstobequitelonganddoesvary.However,bycheckingfortheexistenceofcertainkeywords,suchasMSIEorFirefox,youcanusuallydeterminethebrowsername.Startwiththefollowinglines:
if(lsBrowser.indexOf("MSIE")>=0){
return"MSIE";
}
TheselinessearchthelsBrowserstringforMSIE.IftheindexOfvalueofthissubstringis0orgreater,youknowyouhavefoundit,andsoyousetthereturnvaluetoMSIE.
Thefollowingelseifstatementdoesthesame,exceptthatitismodifiedforFirefox:
elseif(lsBrowser.indexOf("Firefox")>=0){
return"Firefox";
}
Thisprinciplecarriesonforanotherthreeifstatements,inwhichyoualsocheckforChrome,Safari,andOpera.Ifyouhaveabrowseryouwanttocheckfor,thisistheplacetoadditsifstatement.Justviewthestringitreturnsinnavigator.userAgentandlookforitsnameorsomethingthatuniquelyidentifiesit.
Ifnoneoftheifstatementsmatch,youreturnUNKNOWNasthebrowsername:
else{
return"UNKNOWN";
}
Nowturntothefinalfunction,getBrowserVersion().
ThebrowserversiondetailsoftenappearintheuserAgentstringrightafterthenameofthebrowser.Forthesereasons,yourfirsttaskinthefunctionistofindoutwhichbrowseryouaredealingwith.Youdeclareandinitializethebrowservariabletothenameofthebrowser,usingthegetBrowserName()functionyoujustwrote:
functiongetBrowserVersion(){
varua=navigator.userAgent;
varbrowser=getBrowserName();
IfthebrowserisMSIE(InternetExplorer),youneedtousetheuserAgentpropertyagain.UnderIE,theuserAgentpropertyalwayscontainsMSIEfollowedbythebrowserversion.SowhatyouneedtodoissearchforMSIE,andthengetthenumberfollowingthat.
YousetfindIndextothecharacterpositionofthebrowsernameplusthelengthofthename,plusone.Doingthisensuresyoutogetthecharacterafterthenameandjustbeforetheversionnumber.browserVersionissettothefloating-pointvalueofthatnumber,whichyouobtainusingthesubstring()method.ThisselectsthecharactersstartingatfindIndexandendingwiththeonebeforefindIndex,plusthree.Thisensuresthatyoujustselectthreecharactersfortheversionnumber:
varfindIndex=ua.indexOf(browser)+browser.length+1;
varbrowserVersion=parseFloat(ua.substring(findIndex,findIndex+
3));
IfyoulookbacktotheuserAgentstrings,youseethatIE10’sissimilartothis:
Mozilla/5.0(compatible;MSIE10.0;WindowsNT6.3;WOW64;Trident/7.0)
SofindIndexwillbesettothecharacterindexofthenumber10followingthebrowsername.browserVersionwillbesettothreecharactersfromandincludingthe10,givingtheversionnumberas10.0.
Attheendofthefunction,youreturnbrowserVersiontothecallingcode,asshownhere:
returnbrowserVersion;
}
You’veseenthesupportingfunctions,buthowdoyoumakeuseofthem?Well,inthefollowingcodeyouobtaintwobitsofinformation—browsernameandversion—andusethesetofilterwhichbrowsertheuserisrunning:
varbrowserName=getBrowserName();
varbrowserVersion=getBrowserVersion();
if(browserName=="MSIE"){
if(browserVersion<9){
document.write("YourversionofInternetExploreristooold");
}else{
document.write("YourversionofInternetExplorerisfully
supported");
}
}
ThefirstoftheifstatementsisshownintheprecedingcodeandcheckstoseeiftheuserhasIE.Iftrue,itthencheckstoseeiftheversionislowerthan9.Ifitis,theuserseesthemessagestatinghisorherbrowseristooold.Ifitis9or10,themessagetellstheuserthathisorherbrowserisfullysupported.Somethinggoeswrongwiththis
codewithIE11,andyou’llfindoutwhatthatisshortly.
YoudothisagainforFirefox,Chrome,Safari,andOpera.Theversionsofthesebrowsersaren’tcheckedinthisexample,butyoucandosoifyouwantto:
elseif(browserName=="Firefox"){
document.write("Firefoxisfullysupported");
}elseif(browserName=="Safari"){
document.write("Safariisfullysupported");
}elseif(browserName=="Chrome"){
document.write("Chromeisfullysupported");
}elseif(browserName=="Opera"){
document.write("Operaisfullysupported");
}else{
document.write("Sorrythisbrowserversionisnotsupported.");
}
Onthefinalpartoftheifstatementsistheelsestatementthatcoversallotherbrowsersandtellstheuserthebrowserisnotsupported.
IfyourunthispageinIE11,you’llseethemessage“Sorrythisbrowserversionisnotsupported.”Atfirstglance,thisappearstobeanerror,butlookatIE11’suser-agentstring:
Mozilla/5.0(WindowsNT6.3;WOW64;Trident/7.0;rv:11.0)likeGecko
ThereisnomentionofMSIEanywhere,butforthoseversedinthebrowsermaker’scodewords,weknowthatTridentisMicrosoft’srenderingengineandtheversionis11.0.Microsofthadverygoodreasonsforchangingitsuser-agentstringwithversion11,butthisjustdrivesthepointhome:Youcannotrelyonbrowsersniffingbeyondtargetingasinglebrowser.
SUMMARYYou’vecoveredalotinthischapter,butnowyouhaveallthegroundingyouneedtomoveontomoreusefulthings,suchasinteractingwiththepageandformsandhandlinguserinput.
Youturnedyourattentiontothebrowser,theenvironmentinwhichJavaScriptexists.JustasJavaScripthasnativeobjects,sodowebbrowsers.Theobjectswithinthewebbrowser,andthehierarchyinwhichtheyareorganized,aredescribedbysomethingcalledthebrowserobjectmodel(BOM).Thisisessentiallyamapofabrowser’sobjects.Usingit,youcannavigateyourwayaroundeachoftheobjectsmadeavailablebythebrowser,togetherwiththeirproperties,methods,andevents.
Thefirstofthemainobjectsyoulookedatwasthewindowobject.ThissitsattheverytopoftheBOM’shierarchy.Thewindowobjectcontainsanumberofimportantsub-objects,includingthelocationobject,thenavigatorobject,thehistoryobject,thescreenobject,andthedocumentobject.
Thelocationobjectcontainsinformationaboutthecurrentpage’slocation,suchasitsfilename,theserverhostingthepage,andtheprotocolused.Eachoftheseisapropertyofthelocationobject.Somepropertiesareread-only,butothers,suchasthehrefproperty,notonlyenableyoutofindthelocationofthepage,butcanbechangedsothatyoucannavigatethepagetoanewlocation.
Thehistoryobjectisarecordofallthepagestheuserhasvisitedsinceopeninghisorherbrowser.Sometimespagesarenotnoted(forexample,whenthelocationobject’sreplace()methodisusedfornavigation).Youcanmovethebrowserforwardandbackwardinthehistorystackanddiscoverwhatpagestheuserhasvisited.
Thenavigatorobjectrepresentsthebrowseritselfandcontainsusefuldetailsofwhattypeofbrowser,version,andoperatingsystemtheuserhas.Thesedetailsenableyoutowritepagesdealingwithvarioustypesofbrowsers,evenwheretheymaybeincompatible.
Thescreenobjectcontainsinformationaboutthedisplaycapabilitiesoftheuser’scomputer.
Thedocumentobjectisoneofthemostimportantobjects.It’sanobjectrepresentationofyourpageandcontainsalltheelements,alsorepresentedbyobjects,withinthatpage.Thedifferencesbetweenthevariousbrowsersareparticularlyprominenthere,butsimilaritiesexistbetweenthebrowsersthatenableyoutowritecross-browsercode.
Thedocumentobjectcontainsthreepropertiesthatareactuallycollections.Thesearethelinks,images,andformscollections.Eachcontainsalltheobjectscreatedbythe<a/>,<img/>,and<form/>elementsonthepage,andit’sawayofaccessingthoseelements.
Theimagescollectioncontainsanimgobjectforeach<img/>elementonthepage.
Youfoundthatevenafterthepagehasloaded,youcanchangethepropertiesofimages.Forexample,youcanmaketheimagechangewhenclicked.Thesameprinciplesforusingtheimagescollectionapplytothelinkscollection.
Finally,youlookedathowyoucancheckwhattypeofbrowsertheuserhas,therebygivingyouthepowertousenewfeatureswithoutcausingerrorsinolderbrowsers.Youalsolearnedhowtosniffthebrowserwiththenavigatorobject’sappNameanduserAgentproperties,andhowunreliablethatinformationcanbe.
That’sitforthischapter.Inthenextchapter,youmoveontothemoreexcitingdocumentobjectmodel,whereyoucanaccessandmanipulatetheelementsinyourpage.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. Createtwopages,onecalledlegacy.htmlandtheothercalledmodern.html.Eachpageshouldhaveaheadingtellingyouwhatpageisloaded.Forexample:
<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>
Usingfeaturedetectionandthelocationobject,sendbrowsersthatdonotsupportgeolocationtolegacy.html;sendbrowsersthatdosupportgeolocationtomodern.html.
2. ModifyExample3fromthe“ImageSelection”TryItOuttodisplayoneofthefourimagesrandomly.Hint:refertoChapter5andtheMath.random()method.
9DOMScriptingWHATYOUWILLLEARNINTHISCHAPTER:
Findingelementsinthepage
Creatingandinsertingelementsintothepagedynamically
Navigatingthewebpage,travellingfromoneelementtoanother
Changingelements’styleaftertheyareloadedinthepage
Animatingelementsbymanipulatingtheirpositioning
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
JavaScript’sprimaryroleinwebdevelopmentistointeractwiththeuser,toaddsomekindofbehaviortoyourwebpage.JavaScriptenablesyoutocompletelychangeallaspectsofawebpageafterit’sloadedinthebrowser.WhatgivesJavaScriptthispoweroverawebpageisthedocumentobjectmodel(DOM),atree-likerepresentationofthewebpage.
TheDOMisoneofthemostmisunderstoodstandardssetforthbytheWorldWideWebConsortium(W3C),abodyofdeveloperswhorecommendstandardsforbrowsermakersandwebdeveloperstofollow.TheDOMgivesdevelopersawayofrepresentingeverythingonawebpagesothatitisaccessibleviaacommonsetofpropertiesandmethodsinJavaScript.Byeverything,wemeaneverything.Youcanliterallychangeanythingonthepage:thegraphics,tables,forms,style,andeventextitselfbyalteringarelevantDOMpropertywithJavaScript.
TheDOMshouldnotbeconfusedwiththebrowserobjectmodel(BOM)thatwasintroducedinChapter8.You’llseethedifferencesbetweenthetwoindetailshortly.Fornow,though,thinkoftheBOMasabrowser-dependentrepresentationofeveryfeatureofthebrowser,fromthebrowserbuttons,URLaddressline,andtitlebartothebrowserwindowcontrols,aswellaspartsofthewebpage,too.TheDOM,however,dealsonlywiththecontentsofthebrowserwindoworwebpage(inotherwords,theHTMLdocument).Itmakesthedocumentavailableinsuchawaythatanybrowsercanuseexactlythesamecodetoaccessandmanipulatethecontentofthedocument.Tosummarize,theBOMgivesyouaccesstothebrowserandsomeofthedocument,whereastheDOMgivesyouaccesstoallofthedocument,butonlythedocument.
ThegreatthingabouttheDOMisthatitisbrowser-andplatform-independent.ThismeansthatdeveloperscanwriteJavaScriptcodethatdynamicallyupdatesthepage,andthatwillworkonanyDOM-compliantbrowserwithoutanytweaking.Youshouldnotneedtocodefordifferentbrowsersortakeexcessivecarewhencoding.
TheDOMachievesthisindependencebyrepresentingthecontentsofthepageasagenerictreestructure.WhereasintheBOMyoumightexpecttoaccesssomethingbylookingupapropertyrelevanttothatpartofthebrowserandadjustingit,theDOMrequiresnavigationthroughitsrepresentationofthepagethroughnodesandpropertiesthatarenotspecifictothebrowser.Youexplorethisstructurealittlelater.
However,tousetheDOMstandard,ultimatelydevelopersrequirebrowsersthatcompletelyimplementthestandard,somethingthatnobrowserdoes100percentefficiently,unfortunately.Tomakemattersworse,noonebrowserimplementstheexactsameDOMfeaturesthatotherbrowserssupport,butdon’tbescaredoffyet.AllmodernbrowserssupportmanyofthesamefeaturesoutlinedbytheDOMstandard.
ToprovideatrueperspectiveonhowtheDOMfitsin,weneedtotakeabrieflookatitsrelationshipwithsomeoftheothercurrentlyexistingwebstandards.WeshouldalsotalkaboutwhythereismorethanoneversionoftheDOMstandard,aswellasdifferentsectionswithinthestandarditself.Afterunderstandingtherelationships,youcanlookatusingJavaScripttonavigatetheDOMandtodynamicallychangeawebpage’scontentinmorethanonebrowser.Thefollowingitemsareonyouragenda:
TheHTMLandECMAScriptstandards
TheDOMstandards
ManipulatingtheDOM
Writingcross-browserJavaScript
NOTERememberthattheexampleswithinthischapteraretargetedonlyattheDOM(withveryfewexceptions)andwillbesupportedbymodernbrowsers(IE9+,Chrome,Firefox,Opera,andSafari).Legacybrowsers(IE8andbelow,earlierversionsofChrome,andsimilarearlybrowsers)mayormaynotsupportthem.
THEWEBSTANDARDSWhenTimBerners-LeecreatedHTMLin1991,heprobablyhadlittleideathatthistechnologyformarkingupscientificpapersviaasetoftagsforhisownglobalhypertextproject,knownastheWorldWideWeb,would,withinamatterofyears,becomeabattlegroundbetweenthetwogiantsofthesoftwarebusinessofthemid-1990s.HTMLwasasimplederivationfromthemeta-languageStandardGeneralizedMarkupLanguage(SGML)thathadbeenkickingaroundacademicinstitutionsfordecades.Itspurposewastopreservethestructureofthedocumentscreatedwithit.HTMLdependsonaprotocol,HyperTextTransferProtocol(HTTP),totransmitdocumentsbackandforthbetweentheresourceandtheviewer(forexample,theserverandtheclientcomputer).Thesetwotechnologiesformedthefoundationoftheweb,anditquicklybecameobviousintheearly1990sthatthereneededtobesomesortofpolicingofbothspecificationstoensureacommonimplementationofHTMLandHTTPsothatcommunicationscouldbeconductedworldwide.
In1994,TimfoundedtheWorldWideWebConsortium(W3C),abodythatsetouttooverseethetechnicalevolutionoftheweb.Ithasthreemainaims:
Toprovideuniversalaccess,sothatanybodycanusetheweb
Todevelopasoftwareenvironmenttoallowuserstomakeuseoftheweb
Toguidethedevelopmentoftheweb,takingintoconsiderationthelegal,social,andcommercialissuesthatarise
EachnewversionofaspecificationofawebtechnologyhastobecarefullyvettedbyW3Cbeforeitcanbecomeastandard.TheHTMLandHTTPspecificationsaresubjecttothisprocess,andeachnewsetofupdatestothesespecificationsyieldsanewversionofthestandard.Eachstandardhastogothroughaworkingdraft,acandidaterecommendation,andaproposedrecommendationstagebeforeitcanbeconsideredafullyoperationalstandard.Ateachstageoftheprocess,membersoftheW3Cconsortiumvoteonwhichamendmentstomake,orevenonwhethertocancelthestandardcompletelyandsenditbacktosquareone.
Itsoundslikeaverypainfulandlaboriousmethodofcreatingastandardformat,andnotsomethingyou’dthinkofasspearheadingthecuttingedgeoftechnicalrevolution.Indeed,thesoftwarecompaniesofthemid-1990sfoundtheprocessesinvolvedtooslow,sotheysetthetonebyimplementingnewinnovationsthemselvesandthensubmittingthemtothestandardsbodyforapproval.Netscapestartedbyintroducingnewelementsinitsbrowser,suchasthe<font/>element,toaddpresentationalcontenttothewebpages.Thisprovedpopular,soNetscapeaddedawholeraftofelementsthatenableduserstoalteraspectsofpresentationandstyleonwebpages.Indeed,JavaScriptitselfwassuchaninnovationfromNetscape.
WhenMicrosoftenteredthefray,itwasplayingcatchupforthefirsttwoiterationsofitsInternetExplorerbrowser.However,withInternetExplorer3in1996,MicrosoftestablishedaroughlyequalsetoffeaturestocompetewithNetscapeandsowasabletoadditsownbrowser-specificelements.Veryquickly,thewebpolarizedbetweenthesetwo
browsers,andpagesviewableononebrowserquiteoftenwouldn’tworkonanother.OneproblemwasthatMicrosofthaduseditsmuchstrongerpositioninthemarkettogiveawayitsbrowserforfree,whereasNetscapestillneededtosellitsownbrowserbecauseitcouldn’taffordtofreelydistributeitsflagshipproduct.Tomaintainacompetitiveposition,NetscapeneededtooffernewfeaturestomaketheuserwanttopurchaseitsbrowserratherthanusethefreeMicrosoftbrowser.
Thingscametoaheadwithbothcompanies’version4browsers,whichintroduceddynamicpagefunctionality.Unfortunately,Netscapedidthisbythemeansofa<layer/>element,whereasMicrosoftchosetoimplementitviascriptinglanguagepropertiesandmethods.TheW3Cneededtotakeafirmstandhere,becauseoneofitsthreeprincipalaimshadbeencompromised:thatofuniversalaccess.Howcouldaccessbeuniversalifusersneededaspecificvendor’sbrowsertoviewaparticularsetofpages?TheydecidedonasolutionthatusedexistingstandardHTMLelementsandcascadingstylesheets,bothofwhichhadbeenadoptedaspartoftheMicrosoftsolution.Asaresult,Microsoftgainedadominantpositioninthebrowserwar,anditheldthatpositionformanyyears.Today,Microsoft’sInternetExplorerisstillthedominantbrowser,butithaslostalotofitsmarketsharetoChromeandFirefox.
WitharelativelystableversionoftheHTMLstandardinplacewithversion4.01,whichboastsasetoffeaturesthatwilltakeanybrowsermanufactureralongtimetoimplementcompletely,attentionwasturnedtootherareasoftheweb.Anewsetofstandardswasintroducedinthelate1990stogovernthemeansofpresentingHTML(stylesheets)andtherepresentationoftheHTMLdocumentinscript(theDOM).Otherstandardsemerged,suchasExtensibleMarkupLanguage(XML),whichoffersacommonformatforrepresentingdatainawaythatpreservesitsstructure.
TheW3Cwebsite(www.w3.org)hasahugenumberofstandardsinvaryingstagesofcreation.Notallofthesestandardsconcernus,andnotalloftheonesthatconcernuscanbefoundatthiswebsite.However,thevastmajorityofstandardsthatdoconcernuscanbefoundthere.
You’regoingtotakeabrieflooknowatthetechnologiesandstandardsthathaveanimpactonJavaScriptandfindoutalittlebackgroundinformationabouteach.Someofthetechnologiesmaybeunfamiliar,butyouneedtobeawareoftheirexistenceattheveryleast.
HTMLTheHTMLstandardismaintainedbyW3C.Thisstandardmightseemfairlystraightforward,giventhateachversionshouldhaveintroducedjustafewnewelements,butinrealitythelifeofthestandardsbodywasvastlycomplicatedbythebrowserwars.The1.0and2.0versionsofHTMLweresimple,smalldocuments,butwhentheW3CcametodebateHTMLversion3.0,theyfoundthatmuchofthenewfunctionalityitwasdiscussinghadalreadybeensupersededbynewadditions(suchasthe<applet/>and<style/>elements)totheversion3.0browser’sappletstyle.Version3.0wasdiscarded,andanewversion,3.2,becamethestandard.
However,alotofthefeaturesthatwentintoHTML3.2hadbeenintroducedatthebehest
ofthebrowsermanufacturersandrancontrarytothespiritofHTML,whichwasintendedsolelytodefinestructure.Thenewfeatures,stemmingfromthe<font/>element,justconfusedtheissueandaddedunnecessarypresentationalfeaturestoHTML.Thesefeaturesreallybecameredundantwiththeintroductionofstylesheets.Sosuddenly,intheversion3browsers,therewerethreedistinctwaystodefinethestyleofanitemoftext.Whichwasthecorrectway?Andifallthreewayswereused,whichstyledidthetextultimatelyassume?Version4.0oftheHTMLstandardwasleftwiththejobofunmuddlingthischaoticmessanddesignatedalotofelementsfordeprecation(removal)inthenextversionofthestandards.ItwasthelargestversionofthestandardsofarandincludedfeaturesthatlinkedittostylesheetsandtheDOM,andalsoaddedfacilitiesforthevisuallyimpairedandotherunfairlyneglectedminorityinterestareas.
In2004,theW3CwasfocusingonXHTML2.0,aspecificationthatmany,andperhapsmost,inthewebdevelopmentcommunitythoughttobethewrongdirectionfortheweb.Soanotherbody,theWebHypertextApplicationTechnologyWorkingGroup(WHATWG)startedworkingonHTML5.In2009,theW3CofficiallydroppedXHTML2.0,andtodaytheW3CandtheWHATWGworktogetherondevelopingHTML5.
HTML5introducesmanynewfeatures.Firstarenewelementsthatidentifyapage’snavigation,header,andfooterwiththe<nav/>,<header/>,and<footer/>elements.Italsoadds<audio/>and<video/>elementstoreplace<object/>.HTML5alsoremoveselementslike<font/>and<center/>,elementsthatarepurelyusedforpresentationpurposes.HTML5alsodefinesnativesupportfordraganddrop,geolocation,storage,andmuchmore.
NoteTheHTML5specificationisnotcompletelyfinalized,butmanyofitsindividualfeaturesaresaidtobecomplete.Asaresult,you’llfindmanyfeaturesimplementedintoday’smodernbrowsers.YoucanvisittheW3Cwebsiteathttp://www.w3.org/TR/html5/ortheWHATWGlivingstandardathttp://html.spec.whatwg.org/multipage/ifyouwanttoreadtheactualspecifications.
ECMAScriptJavaScriptitselffollowedatrajectorysimilartothatofHTML.ItwasfirstusedinNetscapeNavigatorandthenaddedtoInternetExplorer.TheInternetExplorerversionofJavaScriptwaschristenedJScriptandwasn’tfarremovedfromtheversionofJavaScriptfoundinNetscapeNavigator.However,onceagain,thereweredifferencesbetweenthetwoimplementationsandalotofcarehadtobetakeninwritingscriptforbothbrowsers.
Oddlyenough,itwaslefttotheEuropeanComputerManufacturersAssociation(ECMA)toproposeastandardspecificationforJavaScript.Thisdidn’tappearuntilafewversionsofJavaScripthadalreadybeenreleased.UnlikeHTML,whichhadbeendevelopedfromthestartwiththeW3Cconsortium,JavaScriptwasaproprietarycreation.Thisisthereasonthatitisgovernedbyadifferentstandardsbody.MicrosoftandNetscapebothagreedtouseECMAasthestandardsvehicle/debatingforum,becauseofitsreputationforfast-trackingstandardsandperhapsalsobecauseofitsperceivedneutrality.Thename
ECMAScriptwaschosensoasnottobebiasedtowardeithervendor’screationandalsobecausethe“Java”partofJavaScriptwasatrademarkofSunlicensedtoNetscape.Thestandard,namedECMA-262,laiddownaspecificationthatwasroughlyequivalenttotheJavaScript1.1specification.
Thatsaid,theECMAScriptstandardcoversonlycoreJavaScriptfeatures,suchastheprimitivedatatypesofnumbers,strings,andbooleans,nativeobjectsliketheDate,Array,andMathobjects,andtheproceduralstatementslikeforandwhileloops,andifandelseconditionals.Itmakesnoreferencetoclient-sideobjectsorcollections,suchaswindow,document,forms,links,andimages.So,althoughthestandardhelpstomakecoreprogrammingtaskscompatiblewhenbothJavaScriptandJScriptcomplywithit,itisofnouseinmakingthescriptingofclient-sideobjectscompatiblebetweenthemainbrowsers.Someincompatibilitiesremain.
AllcurrentimplementationsofJavaScriptareexpectedtoconformtothecurrentECMAScriptstandard,whichisECMAScriptedition5,publishedinDecember2009.
AlthoughthereusedtobequiteafewirregularitiesbetweenthedifferentdialectsofJavaScript,they’renowsimilarenoughtobeconsideredthesamelanguage.Thisisagoodexampleofhowstandardshaveprovidedauniformlanguageacrossbrowserimplementations,althoughadebatethatissimilartotheonethattookplaceoverHTMLstillragestoalesserdegreeoverJavaScript.
It’snowtimeforyoutoconsiderthedocumentobjectmodelitself.
THEDOCUMENTOBJECTMODELThedocumentobjectmodel(DOM)is,aspreviouslymentioned,awayofrepresentingthedocumentindependentofbrowsertype.Itallowsadevelopertoaccessthedocumentviaacommonsetofobjects,properties,methods,andevents,andtoalterthecontentsofthewebpagedynamicallyusingscripts.
YoushouldbeawarethatsomesmallvariationsareusuallyaddedtotheDOMbythebrowservendor.So,toguaranteethatyoudon’tfallafoulofaparticularimplementation,theW3Chasprovidedagenericsetofobjects,properties,andmethodsthatshouldbeavailableinallbrowsers,intheformoftheDOMstandard.
TheDOMStandardWehaven’ttalkedabouttheDOMstandardsofar,andforaparticularreason:It’snottheeasieststandardtofollow.Supportingagenericsetofpropertiesandmethodshasprovedtobeaverycomplextask,andtheDOMstandardhasbeenbrokendownintoseparatelevelsandsectionstodealwiththedifferentareas.Thedifferentlevelsofthestandardareallatdifferingstagesofcompletion.
Level0Level0isabitofamisnomer,becausetherewasn’treallyalevel0ofthestandard.Thisterminfactreferstothe“oldway”ofdoingthings—themethodsimplementedbythebrowservendorsbeforetheDOMstandard.Someonementioninglevel0propertiesisreferringtoamorelinearnotationofaccessingpropertiesandmethods.Forexample,typicallyyou’dreferenceitemsonaformwiththefollowingcode:
document.forms[0].elements[1].value="button1";
We’renotgoingtocoversuchpropertiesandmethodsinthischapter,becausetheyhavebeensupersededbynewermethods.
Level1Level1isthefirstversionofthestandard.Itissplitintotwosections:Oneisdefinedascore(objects,properties,andmethodsthatcanapplytobothXMLandHTML)andtheotherasHTML(HTML-specificobjects,properties,andmethods).Thefirstsectiondealswithhowtogoaboutnavigatingandmanipulatingthestructureofthedocument.Theobjects,properties,andmethodsinthissectionareveryabstract.ThesecondsectiondealswithHTMLonlyandoffersasetofobjectscorrespondingtoalltheHTMLelements.Thischaptermainlydealswiththesecondsection—level1ofthestandard.
In2000,level1wasrevampedandcorrected,thoughitonlymadeittoaworkingdraftandnottoafullW3Crecommendation.
Level2Level2iscompleteandmanyoftheproperties,methods,andeventshavebeen
implementedbytoday’sbrowsers.IthassectionsthataddspecificationsforeventsandstylesheetstothespecificationsforcoreandHTML-specificpropertiesandevents.(Italsoprovidessectionsonviewsandtraversalranges,neitherofwhichiscoveredinthisbook;youcanfindmoreinformationatwww.w3.org/TR/2000/PR-DOM-Level-2-Views-20000927/andwww.w3.org/TR/2000/PR-DOM-Level-2-Traversal-Range-20000927/.)
Level3Level3achievedrecommendationstatusin2004.Itisintendedtoresolvealotofthecomplicationsthatstillexistintheeventmodelinlevel2ofthestandard,andaddssupportforXMLfeatures,suchascontentmodelsandbeingabletosavetheDOMasanXMLdocument.
Level4InMay2014,DOMlevel4reachedcandidaterecommendationstatus.ItconsolidatesDOMlevel3withseveralindependentcomponents.Atthetimeofthiswriting,nomodernbrowsersupportsDOMlevel4,althoughthatwillchangeinthefuture.
BrowserCompliancewiththeStandardsAlmostnobrowserhas100percentcompliancewithanystandard.Therefore,thereisnoguaranteethatalltheobjects,properties,andmethodsoftheDOMstandardwillbeavailableinagivenversionofabrowser.However,allmodernbrowsersdoaverygoodjobofsupportingthestandardDOM.TheonlybrowsersyoutrulyhavetowatchoutforareIE8andbelow.
MuchofthematerialintheDOMstandardhasonlyrecentlybeenclarified,andalotofDOMfeaturesandsupporthavebeenaddedtoonlythelatestbrowserversions.Forthisreason,examplesinthischapterwillbeguaranteedtoworkononlythelatestversionsofIE,Chrome,Firefox,Opera,andSafari.Althoughcross-browserscriptingisarealisticgoal,backward-compatiblesupportisn’tatall.
Althoughthestandardsmightstillnotbefullyimplemented,theydogiveyouanideaastohowaparticularpropertyormethodshouldbeimplemented,andprovideaguidelineforallbrowsermanufacturerstoagreetoworktowardinlaterversionsoftheirbrowsers.TheDOMdoesn’tintroduceanynewHTMLelementsorstylesheetpropertiestoachieveitsends.TheideaoftheDOMistomakeuseoftheexistingtechnologies,andquiteoftentheexistingpropertiesandmethodsofoneorotherofthebrowsers.
DifferencesbetweentheDOMandtheBOMAsmentionedearlier,twomaindifferencesexistbetweenthedocumentobjectmodelandthebrowserobjectmodel.However,complicatingtheissueisthefactthataBOMissometimesreferredtounderthenameDOM.Lookoutforthisinanyliteratureonthesubject.
First,theDOMcoversonlythedocumentofthewebpage,whereastheBOMoffersscriptingaccesstoallareasofthebrowsers,fromthebuttonstothetitlebar,includingsomepartsofthepage.
Second,theBOMisuniquetoaparticularbrowser.Thismakessenseifyouthinkaboutit:youcan’texpecttostandardizebrowsers,becausetheyhavetooffercompetitivefeatures.Therefore,youneedadifferentsetofpropertiesandmethodsandevenobjectstobeabletomanipulatethemwithJavaScript.
RepresentingtheHTMLDocumentasaTreeStructureBecauseHTMLisstandardizedsothatwebpagescancontainonlythestandardfeaturessupportedinthelanguage,suchasforms,tables,images,andthelike,acommonmethodofaccessingthesefeaturesisneeded.ThisiswheretheDOMcomesin.ItprovidesauniformrepresentationoftheHTMLdocument,anditdoesthisbyrepresentingtheentireHTMLdocument/webpageasatreestructure.
Infact,itispossibletorepresentanyHTMLasatreestructure,andforbestresults,theHTMLdocumentshouldbewellformed.Browserstolerate,toagreaterorlesserextent,quirkssuchasunclosedtags,orHTMLformcontrolsnotbeingenclosedwithina<form/>element;however,forthestructureoftheHTMLdocumenttobeaccuratelydepicted,youneedtobeabletoalwayspredictthestructureofthedocument.TheabilitytoaccesselementsviatheDOMdependsontheabilitytorepresentthepageasahierarchy.
WhatIsaTreeStructure?Ifyou’renotfamiliarwiththeconceptoftrees,don’tworry.They’rejustadiagrammaticmeansofrepresentingahierarchicalstructure.
Let’sconsidertheexampleofabookwithseveralchapters.Ifinstructedto,youcouldfindthethirdlineonpage543afteralittlesearching.Ifanupdatededitionofthebookwereprintedwithextrachapters,morelikelythannotyou’dfailtofindthesametextifyoufollowedthosesameinstructions.However,iftheinstructionswerechangedto,say,“Findthechapteronstill-lifepainting,thesectiononusingwatercolors,andtheparagraphonpositioninglightsources,”you’dbeabletofindthateveninareprintededitionwithextrapagesandchapters,albeitwithperhapsalittlemoreeffortthanthefirstrequestrequired.
Booksaren’tparticularlydynamicexamples,butgivensomethinglikeawebpage,wheretheinformationcouldbechangeddaily,orevenhourly,canyouseewhyitwouldbeofmoreusetogivethesecondsetofdirectionsthanthefirst?ThesameprincipleapplieswiththeDOM.NavigatingtheDOMinahierarchicalfashion,ratherthaninastrictlylinearway,makesmuchmoresense.WhenyoutreattheDOMasatree,itbecomeseasytonavigatethepageinthisfashion.Considerhowyoulocatefilesonyourcomputer.Thefile/foldermanager(WindowsExplorerinWindows,FinderinMacOS,andsoon)createsatreeviewoffoldersthroughwhichyoucandrilldown.Insteadoflookingforafilealphabetically,youlocateitbygoingintoaparticularfolder.
Therulesforcreatingtreesaresimple.Youstartatthetopofthetreewiththedocumentandtheelementthatcontainsallotherelementsinthepage.Thedocumentistherootnode.Anodeisjustapointonthetreerepresentingaparticularelementorattributeofanelement,oreventhetextthatanelementcontains.Therootnodecontainsallothernodes,suchastheDTDdeclarationandtherootelement(theHTMLorXMLelementthatcontainsallotherelements).Therootelementshouldalwaysbethe<html/>elementinan
HTMLdocument.UnderneaththerootelementaretheHTMLelementsthattherootelementcontains.Typically,anHTMLpagewillhave<head/>and<body/>elementsinsidethe<html/>element.Theseelementsarerepresentedasnodesunderneaththerootelement’snode,whichitselfisunderneaththerootnodeatthetopofthetree(seeFigure9.1).
Figure9.1
Thetwonodesrepresentingthe<head/>and<body/>elementsareexamplesofchildnodes,andthe<html/>element’snodeabovethemisaparentnode.Becausethe<head/>and<body/>elementsarebothchildnodesofthe<html/>element,theybothgoonthesamelevelunderneaththeparentnode<html/>element.The<head/>and<body/>elementsinturncontainotherchildnodes/HTMLelements,whichwillappearatalevelunderneaththeirnodes.Sochildnodescanalsobeparentnodes.EachtimeyouencounterasetofHTMLelementswithinanotherelement,theyeachformaseparatenodeatthesamelevelonthetree.Theeasiestwayofexplainingthisclearlyiswithanexample.
AnExampleHTMLPageLet’sconsiderabasicHTMLpagesuchasthis:
<!DOCTYPEhtml>
<htmllang="en">
<head>
</head>
<body>
<h1>MyHeading</h1>
<p>Thisissometextinaparagraph.</p>
</body>
</html>
The<html/>elementcontains<head/>and<body/>elements.The<body/>elementcontainsan<h1/>elementanda<p/>element.The<h1/>elementcontainsthetextMyHeading.Whenyoureachanitem,suchastext,animage,oranelement,thatcontainsnoothers,thetreestructurewillterminateatthatnode.Suchanodeistermedaleafnode.Youthencontinuetothe<p/>node,whichcontainssometext,whichisalsoanodeinthedocument.YoucandepictthiswiththetreestructureshowninFigure9.2.
Figure9.2
Simple,eh?Thisexampleisalmosttoostraightforward,solet’smoveontoaslightlymorecomplexonethatinvolvesatableaswell:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Thisisatestpage</title>
</head>
<body>
<span>Belowisatable</span>
<table>
<tr>
<td>Row1Cell1</td>
<td>Row1Cell2</td>
</tr>
</table>
</body>
</html>
Thereisnothingoutoftheordinaryhere;thedocumentcontainsatablewithtworowswithtwocellsineachrow.Youcanonceagainrepresentthehierarchicalstructureofyourpage(forexample,thefactthatthe<html/>elementcontainsa<head/>anda<body/>element,andthatthe<head/>elementcontainsa<title/>element,andsoon)usingyourtreestructure,asshowninFigure9.3.
Figure9.3
Thetoplevelofthetreeissimpleenough;the<html/>elementcontains<head/>and<body/>elements.The<head/>elementinturncontainsa<title/>elementandthe<title/>elementcontainssometext.Thistextnodeisachildnodethatterminatesthebranch(aleafnode).Youcanthengobacktothenextnode,the<body/>elementnode,andgodownthatbranch.Hereyouhavetwoelementscontainedwithinthe<body/>element:the<span/>and<table/>elements.Althoughthe<span/>elementcontainsonlytextandterminatesthere,the<table/>elementcontainsonerow(<tr/>),anditcontainstwotablecell(<td/>)elements.Onlythendoyougettothebottomofthetreewiththetextcontainedineachtablecell.YourtreeisnowacompleterepresentationofyourHTMLcode.
TheCoreDOMObjectsWhatyouhaveseensofarhasbeenhighlytheoretical,solet’sgetalittlemorepracticalnow.
TheDOMprovidesyouwithaconcretesetofobjects,properties,andmethodsthatyoucanaccessthroughJavaScripttonavigatethetreestructureoftheDOM.Let’sstartwiththesetofobjects,withintheDOM,thatisusedtorepresentthenodes(elements,attributes,ortext)onyourtree.
BaseDOMObjectsThreeobjects,showninthefollowingtable,areknownasthebaseDOMobjects.
OBJECT DESCRIPTIONNode EachnodeinthedocumenthasitsownNodeobject.NodeList ThisisalistofNodeobjects.NamedNodeMap ThisprovidesaccessbynameratherthanbyindextoalltheNodeobjects.
ThisiswheretheDOMdiffersfromtheBOMquiteextensively.TheBOMobjectshavenamesthatrelatetoaspecificpartofthebrowser,suchasthewindowobject,ortheformsandimagescollections.Asmentionedearlier,tobeabletonavigateinthewebpageasthoughitwereatree,youhavetodoitabstractly.Youcanhavenopriorknowledgeofthestructureofthepage;everythingultimatelyisjustanode.TomovearoundfromHTMLelementtoHTMLelement,orelementtoattribute,youhavetogofromnodetonode.Thisalsomeansyoucanadd,replace,orremovepartsofyourwebpagewithoutaffectingthestructureasawhole,becauseyou’rejustchangingnodes.Thisiswhyyouhavethreeratherobscure-soundingobjectsthatrepresentyourtreestructure.
I’vealreadymentionedthatthetopofyourtreestructureistherootnode,andthattherootnodecontainstheDTDandrootelement.Therefore,youneedmorethanjustthesethreeobjectstorepresentyourdocument.Infact,therearedifferentobjectstorepresentthedifferenttypesofnodesonthetree.
High-LevelDOMObjectsBecauseeverythingintheDOMisanode,it’snowonderthatnodescomeinavarietyoftypes.Isthenodeanelement,anattribute,orjustplaintext?TheNodeobjecthasdifferentobjectstorepresenteachpossibletypeofnode.ThefollowingisacompletelistofallthedifferentnodetypeobjectsthatcanbeaccessedviatheDOM.Alotofthemwon’tconcernyouinthisbook,becausethey’rebettersuitedforXMLdocumentsandnotHTMLdocuments,butyoushouldnoticethatyourthreemaintypesofnodes,namelyelement,attribute,andtext,areallcovered.
OBJECT DESCRIPTIONDocument TherootnodeofthedocumentDocumentType TheDTDorschematypeoftheXMLdocumentDocumentFragment AtemporarystoragespaceforpartsofthedocumentEntityReference AreferencetoanentityintheXMLdocumentElement AnelementinthedocumentAttr AnattributeofanelementinthedocumentProcessingInstruction AprocessinginstructionComment AcommentinanXMLdocumentorHTMLdocumentText TextthatmustformachildnodeofanelementCDATASection ACDATAsectionwithintheXMLdocumentEntity AnunparsedentityintheDTDNotation AnotationdeclaredwithinaDTD
Wewon’tgoovermostoftheseobjectsinthischapter.
EachoftheseobjectsinheritsallthepropertiesandmethodsoftheNodeobject,butalsohassomepropertiesandmethodsofitsown.Youlookatsomeexamplesinthenextsection.
DOMObjectsandTheirPropertiesandMethodsIfyoutriedtolookatthepropertiesandmethodsofalltheobjectsintheDOM,itwouldtakeuphalfthebook.Insteadyou’regoingtoactivelyconsideronlythreeoftheobjects,namelytheNodeobject,theElementobject,andtheDocumentobject.Thisisallyou’llneedtobeabletocreate,amend,andnavigateyourtreestructure.Also,you’renotgoingtospendagestrawlingthrougheachofthepropertiesandmethodsoftheseobjects,butratherlookonlyatsomeofthemostusefulpropertiesandmethodsandusethemtoachievespecificends.
NOTEAppendixCcontainsarelativelycompletereferencetotheDOM,itsobjects,andtheirproperties.
TheDocumentObjectanditsMethodsTheDocumentreferencetypeexposesvariouspropertiesandmethodsthatareveryhelpfultosomeonescriptingtheDOM.Itsmethodsenableyoutofindindividualorgroupsofelementsandcreatenewelements,attributes,andtextnodes.AnyDOMscriptershouldknowthesemethodsandproperties,becausethey’reusedquitefrequently.
TheDocumentobject’smethodsareprobablythemostimportantmethodsyou’lllearn.Althoughmanytoolsareatyourdisposal,theDocumentobject’smethodsletyoufind,create,anddeleteelementsinyourpage.
FindingElementsoranElementLet’ssayyouhaveanHTMLwebpage—howdoyougoaboutgettingbackaparticularelementonthepageinscript?TheDocumentreferencetypeexposesthefollowingmethodstoperformthistask.
METHODSOFTHEDOCUMENTOBJECT
DESCRIPTION
getElementById(idValue) Returnsareference(anode)ofanelement,whensuppliedwiththevalueoftheidattributeofthatelement
getElementsByTagName(tagName) Returnsareference(anodelist)toasetofelementsthathavethesametagastheonesuppliedintheargument
querySelector(cssSelector) Returnsareference(anode)ofthefirstelementthatmatchesthegivenCSSselector
querySelectorAll(cssSelector) Returnsareference(anodelist)toasetofelementsthatmatchthegivenCSSselector
Thefirstofthesemethods,getElementById(),requiresyoutoensurethateveryelementyouwanttoquicklyaccessinthepageusesanidattribute,otherwiseanullvalue(awordindicatingamissingorunknownvalue)willbereturnedbyyourmethod.Let’sgobacktothefirstexampleandaddsomeidattributestotheelements.
<!DOCTYPEhtml>
<htmllang="en">
<head>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph.</p>
</body>
</html>
NowyoucanusethegetElementById()methodtoreturnareferencetoanyoftheHTMLelementswithidattributesonyourpage.Forexample,ifyouaddthefollowingcodeinthehighlightedsection,youcanfindandreferencethe<h1/>element:
<!DOCTYPEhtml>
<htmllang="en">
<head>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph.</p>
<script>
alert(document.getElementById("heading1"));
</script>
</body>
</html>
Figure9.4showstheresultofthiscodeinFirefox.
Figure9.4
NOTEHTMLHeadingElementisanobjectoftheHTMLDOM.AllHTMLelementshaveacorrespondingreferencetypeintheDOM.SeeAppendixCformoreobjectsoftheHTMLDOM.
Youmighthavebeenexpectingittoreturnsomethingalongthelinesof<h1/>or<h1id="heading1">,butallit’sactuallyreturningisareferencetothe<h1/>element.Thisreferencetothe<h1/>elementismoreusefulthough,becauseyoucanuseittoalterattributesoftheelement,suchasbychangingthecolororsize.Youcandothisviathestyleobject:
<!DOCTYPEhtml>
<htmllang="en">
<head>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph.</p>
<script>
varh1Element=document.getElementById("heading1");
h1Element.style.color="red";
</script>
</body>
</html>
Ifyoudisplaythisinthebrowser,youseethatyoucandirectlyinfluencetheattributesofthe<h1/>elementinscript,asyouhavedoneherebychangingitstextcolortored.
NOTEThestyleobjectpointstothestyleattributeofanelement;itenablesyoutochangetheCSSstyleassignedtoanelement.Thestyleobjectiscoveredlaterinthechapter.
Thesecondmethod,getElementsByTagName(),worksinthesameway,but,asitsnameimplies,itcanreturnmorethanoneelement.IfyouweretogobacktotheexampleHTMLdocumentwiththetableandusethismethodtoreturnthetablecells(<td/>)inyourcode,youwouldgetanodelistcontainingatotaloffourtables.You’dstillhaveonlyoneobjectreturned,butthisobjectwouldbeacollectionofelements.Rememberthatcollectionsarearray-likestructures,sospecifytheindexnumberforthespecificelementyouwantfromthecollection.Youcanusethesquarebracketsifyouwant;anotheralternativeistousetheitem()methodoftheNodeListobject,likethis:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Thisisatestpage</title>
</head>
<body>
<span>Belowisatable</span>
<table>
<tr>
<td>Row1Cell1</td>
<td>Row1Cell2</td>
</tr>
</table>
<script>
vartdElement=document.getElementsByTagName("td").item(0);
tdElement.style.color="red";
</script>
</body>
</html>
Ifyouranthisexample,onceagainusingthestyleobject,itwouldalterthestyleofthecontentsofthefirstcellinthetable.Ifyouwantedtochangethecolorofallthecellsinthisway,youcouldloopthroughthenodelist,likethis:
<script>
vartdElements=document.getElementsByTagName("td");
varlength=tdElements.length;
for(vari=0;i<length;i++){
tdElements[i].style.color="red";
}
</script>
OnethingtonoteaboutthegetElementsByTagName()methodisthatittakestheelementnameswithinquotationmarksandwithouttheanglebrackets(<>)thatnormallysurroundtags.
Thethirdmethod,querySelector(),retrievesthefirstelementthatmatchestheprovided
CSSselector.Thisisaconvenientwayofretrievinganelementthatdoesnothaveanidattribute(ifitdoeshaveanidattribute,youwanttousegetElementById()).
Forexample,considerthefollowingHTML:
<pclass="sub-title">Thisisa<span>special</span>paragraphelement
thatcontains<span>sometext</span></p>.
UsingthequerySelector()method,youcanretrievethefirst<span/>elementinthisHTMLwiththefollowingcode:
varfirstSpan=document.querySelector(".sub-titlespan");
TheprovidedCSSselectormatchesall<span/>elementscontainedwithinaparentelementwithaCSSclassofsub-title.ThisHTMLcontainstwosuch<span/>elements,butquerySelector()onlyreturnsthefirst:the<span/>elementcontainingthetext“special.”Justaswiththepreviousexamples,youcanmodifytheelement’stextcolorwithitsstyleproperty:
<script>
varfirstSpan=document.querySelector(".sub-titlespan");
firstSpan.style.color="red";
</script>
Ifyouwantedtoretrieveallofthe<span/>elementsinthisHTML,youwanttousethefourthmethod,querySelectorAll(),likethis:
varspans=document.querySelectorAll(".sub-titlespan");
AndjustaswiththegetElementsByTagName()example,youcanusealoopandmodifyalltheelementscontainedwithinthespansNodeList:
<script>
varspans=document.querySelectorAll(".sub-titlespan");
varlength=spans.length;
for(vari=0;i<length;i++){
spans[i].style.color="red";
}
</script>
NOTEThequerySelector()andquerySelectorAll()methodsaren’tactuallypartoftheDOMstandard.They’redefinedwithintheW3C’sSelectorsAPI,whichisoneofthecomponentstobeconsolidatedwithDOMlevel3intoDOMlevel4.YoucanusethesemethodsonElementobjects,too.
CreatingElementsandTextTheDocumentobjectalsoboastssomemethodsforcreatingelementsandtext,showninthefollowingtable.
METHODSOFTHEDOCUMENTOBJECT
DESCRIPTION
createElement(elementName) Createsanelementnodewiththespecifiedtagname.Returnsthecreatedelement
createTextNode(text) Createsandreturnsatextnodewiththesuppliedtext
Thefollowingcodedemonstratestheuseofthesemethods:
varpElement=document.createElement("p");
vartext=document.createTextNode("Thisissometext.");
Thiscodecreatesa<p/>elementandstoresitsreferenceinthepElementvariable.ItthencreatesatextnodecontainingthetextThisissometext.andstoresitsreferenceinthetextvariable.
It’snotenoughtocreatenodes,however;youhavetoaddthemtothedocument.We’lldiscusshowtodothisinjustabit.
PropertyoftheDocumentObject:GettingtheDocument’sRootElementYounowhaveareferencetoindividualelementsonthepage,butwhataboutthetreestructurementionedearlier?Thetreestructureencompassesalltheelementsandnodesonthepageandgivesthemahierarchicalstructure.Ifyouwanttoreferencethatstructure,youneedaparticularpropertyofthedocumentobjectthatreturnstheoutermostelementofyourdocument.InHTML,thisshouldalwaysbethe<html/>element.ThepropertythatreturnsthiselementisdocumentElement,asshowninthefollowingtable.
PROPERTYOFTHEDOCUMENTOBJECT
DESCRIPTION
documentElement Returnsareferencetotheoutermostelementofthedocument(therootelement;forexample,<html/>)
YoucanusedocumentElementasfollows.IfyougobacktothesimpleHTMLpage,youcantransferyourentireDOMintoonevariablelikethis:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title></title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varcontainer=document.documentElement;
</script>
</body>
</html>
Thevariablecontainernowcontainstherootelement,whichis<html/>.The
documentElementpropertyreturnedareferencetothiselementintheformofanobject,anElementobjecttobeprecise.TheElementobjecthasitsownsetofpropertiesandmethods.Ifyouwanttousethem,youcanrefertothembyusingthevariablename,followedbythemethodorpropertyname:
container.elementObjectProperty
Fortunately,theElementobjecthasonlyoneproperty.
TheElementObjectTheElementobjectisquitesimple,especiallycomparedtotheNodeobject(whichyouareintroducedtolater).Itexposesonlyahandfulofmembers(propertiesandmethods).
MEMBERNAME DESCRIPTIONtagName Getstheelement’stagnamegetAttribute() GetsthevalueofanattributesetAttribute() SetsanattributewithaspecifiedvalueremoveAttribute() Removesaspecificattributeanditsvaluefromtheelement
GettingtheElement’sTagName:ThetagNamePropertyThesolepropertyoftheElementobjectisareferencetothetagnameoftheelement:thetagNameproperty.
Inthepreviousexample,thevariablecontainercontainedthe<html/>element.Addthefollowinghighlightedline,whichmakesuseofthetagNameproperty:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title></title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varcontainer=document.documentElement;
alert(container.tagName);
</script>
</body>
</html>
Thiscodewillnowreturnproofthatyourvariablecontainerholdstheoutermostelement,andbyimplicationallotherelementswithinit(seeFigure9.5).
Figure9.5
MethodsoftheElementObject:GettingandSettingAttributesIfyouwanttosetanyelementattributes,otherthanthestyleattribute,youshouldusetheDOM-specificmethodsoftheElementobject.
ThethreemethodsyoucanusetoreturnandalterthecontentsofanHTMLelement’sattributesaregetAttribute(),setAttribute(),andremoveAttribute(),asshowninthefollowingtable.
METHODSOFTHEELEMENTOBJECT
DESCRIPTION
getAttribute(attributeName) ReturnsthevalueofthesuppliedattributeReturnsnulloranemptystringiftheattributedoesnotexist
setAttribute(attributeName,
value)
Setsthevalueofanattribute
removeAttribute(attributeName) Removesthevalueofanattributeandreplacesitwiththedefaultvalue
Let’stakeaquicklookathowthesemethodsworknow.
TRYITOUTPlayingwithAttributesOpenyourtexteditorandtypethefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example1</title>
</head>
<body>
<pid="paragraph1">Thisissometext.</p>
<script>
varpElement=document.getElementById("paragraph1");
pElement.setAttribute("align","center");
alert(pElement.getAttribute("align"));
pElement.removeAttribute("align");
</script>
</body>
</html>
Savethisasch9 _ example1.htmlandopenitinabrowser.You’llseethetextofthe<p/>elementinthecenterofthescreenandanalertboxdisplayingthetextcenter(Figure9.6).
Figure9.6
WhenyouclicktheOKbutton,you’llseethetextbecomeleft-aligned(Figure9.7).
Figure9.7
ThisHTMLpagecontainsone<p/>elementwithanidvalueofparagraph1.YouusethisvalueintheJavaScriptcodetofindtheelementnodeandstoreitsreferenceinthepElementvariablewiththegetElementById()method:
varpElement=document.getElementById("paragraph1");
Nowthatyouhaveareferencetotheelement,youusethesetAttribute()methodtosetthealignattributetocenter:
pElement.setAttribute("align","center");
Theresultofthiscodemovesthetexttothecenterofthebrowser’swindow.
YouthenusethegetAttribute()methodtogetthealignattribute’svalueanddisplayitinanalertbox:
alert(pElement.getAttribute("align"));
Thiscodedisplaysthevalue"center"inthealertbox.
Finally,youremovethealignattributewiththeremoveAttribute()method,effectivelymakingthetextleft-aligned.
NOTEStrictlyspeaking,thealignattributeisdeprecated,butyouuseditbecauseitworksandbecauseithasoneofthemosteasilydemonstrablevisualeffectsonawebpage.
TheNodeObjectYounowhaveyourelementorelementsfromthewebpage,butwhathappensifyouwant
tomovethroughyourpagesystematically,fromelementtoelementorfromattributetoattribute?Thisiswhereyouneedtostepbacktoalowerlevel.Tomoveamongelements,attributes,andtext,youhavetomoveamongnodesinyourtreestructure.Itdoesn’tmatterwhatiscontainedwithinthenode,orrather,whatsortofnodeitis.ThisiswhyyouneedtogobacktooneoftheobjectsofthecoreDOMspecification.Yourwholetreestructureismadeupofthesebase-levelNodeobjects.
TheNodeObject:NavigatingtheDOMThefollowingtablelistssomecommonpropertiesoftheNodeobjectthatprovideinformationaboutthenode,whetheritisanelement,attribute,ortext,andenableyoutomovefromonenodetoanother.
PROPERTIESOFTHENODEOBJECT
DESCRIPTIONOFPROPERTY
firstChild ReturnsthefirstchildnodeofanelementlastChild ReturnsthelastchildnodeofanelementpreviousSibling Returnsthepreviouschildnodeofanelementatthesame
levelasthecurrentchildnodenextSibling Returnsthenextchildnodeofanelementatthesamelevelas
thecurrentchildnodeownerDocument Returnstherootnodeofthedocumentthatcontainsthenode
(notethisisnotavailableinIE5or5.5)parentNode Returnstheelementthatcontainsthecurrentnodeinthetree
structurenodeName ReturnsthenameofthenodenodeType ReturnsthetypeofthenodeasanumbernodeValue Getsorsetsthevalueofthenodeinplaintextformat
Let’stakeaquicklookathowsomeofthesepropertieswork.Considerthisfamiliarexample:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title></title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varh1Element=document.getElementById("heading1");
h1Element.style.color="red";
</script>
</body>
</html>
Youcannowuseh1Elementtonavigateyourtreestructureandmakewhateverchangesyoudesire.Thefollowingcodeusesh1Elementasastartingpointtofindthe<p/>elementandchangeitstextcolor:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title></title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varh1Element=document.getElementById("heading1");
h1Element.style.color="red";
varpElement;
if(h1Element.nextSibling.nodeType==1){
pElement=h1Element.nextSibling;
}else{
pElement=h1Element.nextSibling.nextSibling;
}
pElement.style.color="red";
</script>
</body>
</html>
ThiscodedemonstratesafundamentaldifferencebetweentheDOMpresentinmodernbrowsersandthatinolderversionsofIE.TheDOMinmodernbrowserstreatseverythingasanodeintheDOMtree,includingthewhitespacebetweenelements.Ontheotherhand,olderversionsofIEstripoutthiswhitespace.Sotolocatethe<p/>elementinthepreviousexample,asiblingtothe<h1/>element,youmustcheckthenextsibling’snodeTypeproperty.Anelement’snodetypeis1(textnodesare3).IfthenextSibling’snodeTypeis1,youassignthatsibling’sreferencetopElement.Ifnot,yougetthenextsibling(the<p/>element)ofh1Element’ssibling(thewhitespacetextnode).
Ineffect,youarenavigatingthroughthetreestructureasshowninFigure9.8.
Figure9.8
Thesameprinciplesalsoworkinreverse.Youcangobackandchangethecodetonavigatefromthe<p/>elementtothe<h1/>element:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title></title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varpElement=document.getElementById("paragraph1");
pElement.style.color="red";
varh1Element;
if(pElement.previousSibling.nodeType==1){
h1Element=pElement.previousSibling;
}else{
h1Element=pElement.previousSibling.previousSibling;
}
h1Element.style.color="red";
</script>
</body>
</html>
Whatyou’redoinghereistheexactopposite;youfindthe<p/>bypassingthevalueofitsidattributetothegetElementById()methodandstoringthereturnedelementreferencetothepElementvariable.Youthenfindthecorrectprevioussiblingsothatyourcodeworksinallbrowsers,andyouchangeitstextcolortored.
TRYITOUTNavigatingYourHTMLDocumentUsingtheDOM
Upuntilnow,you’vebeencheating,becauseyouhaven’ttrulynavigatedyourHTMLdocument.You’vejustuseddocument.getElementById()toreturnanelementandnavigatedtodifferentnodesfromthere.Nowlet’susethedocumentElementpropertyofthedocumentobjectanddothisproperly.You’llstartatthetopofyourtreeandmovedownthroughthechildnodestogetatthoseelements;thenyou’llnavigatethroughyourchildnodesandchangethepropertiesinthesamewayasbefore.
Typethefollowingintoyourtexteditor:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example2</title>
</head>
<body>
<h1id="heading1">MyHeading</h1>
<pid="paragraph1">Thisissometextinaparagraph</p>
<script>
varhtmlElement;//htmlElementstoresreferenceto<html>
varheadElement;//headingElementstoresreferenceto<head>
varbodyElement;//bodyElementstoresreferenceto<body>
varh1Element;//h1Elementstoresreferenceto<h1>
varpElement;//pElementstoresreferenceto<p>
htmlElement=document.documentElement;
headElement=htmlElement.firstChild;
alert(headElement.tagName);
if(headElement.nextSibling.nodeType==3){
bodyElement=headElement.nextSibling.nextSibling;
}else{
bodyElement=headElement.nextSibling;
}
alert(bodyElement.tagName);
if(bodyElement.firstChild.nodeType==3){
h1Element=bodyElement.firstChild.nextSibling;
}else{
h1Element=bodyElement.firstChild;
}
alert(h1Element.tagName);
h1Element.style.fontFamily="Arial";
if(h1Element.nextSibling.nodeType==3){
pElement=h1Element.nextSibling.nextSibling;
}else{
pElement=h1Element.nextSibling;
}
alert(pElement.tagName);
pElement.style.fontFamily="Arial";
if(pElement.previousSibling.nodeType==3){
h1Element=pElement.previousSibling.previousSibling;
}else{
h1Element=pElement.previousSibling;
}
h1Element.style.fontFamily="Courier";
</script>
</body>
</html>
Savethisasch9 _ example2.htmlandopenitinyourbrowser.
ClickOKineachofthemessageboxesuntilyouseethepageshowninFigure9.9(unfortunately,IEdoesnotrenderthestylechangesuntilallalertboxeshavebeenopenedandclosed).
Figure9.9
You’vehopefullymadethisexampleverytransparentbyaddingseveralalertstodemonstratewhereyouarealongeachsectionofthetree.You’vealsonamedthevariableswiththeirvariouselements,togiveaclearerideaofwhatisstoredineachvariable.(Youcouldjustaseasilyhavenamedthema,b,c,d,ande,sodon’tthinkyouneedtobeboundbythisnamingconvention.)
YoustartatthetopofthescriptblockbyretrievingthewholedocumentusingthedocumentElementproperty:
varhtmlElement=document.documentElement;
Therootelementisthe<html/>element,hencethenameofyourfirstvariable.Nowifyourefertoyourtree,you’llseethattheHTMLelementmusthavetwochildnodes:onecontainingthe<head/>elementandtheothercontainingthe<body/>element.Youstartbymovingtothe<head/>element.YougetthereusingthefirstChildpropertyoftheNodeobject,whichcontainsyour<html/>element.Youuseyourfirstalerttodemonstratethatthisistrue:
alert(headingElement.tagName);
Your<body/>elementisyournextsiblingacrossfromthe<head/>element,soyounavigateacrossbycreatingavariablethatisthenextsiblingfromthe<head/>element:
if(headingElement.nextSibling.nodeType==3){
bodyElement=headingElement.nextSibling.nextSibling;
}else{
bodyElement=headingElement.nextSibling;
}
alert(bodyElement.tagName);
HereyouchecktoseewhatthenodeTypeofthenextSiblingofheadingElementis.Ifitreturns3,(nodeType3isatextnode),yousetbodyElementtobethenextSiblingofthenextSiblingofheadingElement;otherwise,youjustsetittobethenextSiblingofheadingElement.
Youuseanalerttoprovethatyouarenowatthe<body/>element:
alert(bodyElement.tagName);
The<body/>elementinthispagealsohastwochildren,the<h1/>and<p/>elements.UsingthefirstChildproperty,youmovedowntothe<h1/>element.Againyoucheckwhetherthechildnodeiswhitespaceforstandard-compliantbrowsers.Youuseanalertagaintoshowthatyouhavearrivedat<h1/>:
if(bodyElement.firstChild.nodeType==3){
h1Element=bodyElement.firstChild.nextSibling;
}else{
h1Element=bodyElement.firstChild;
}
alert(h1Element.tagName);
Afterthethirdalert,thestylewillbealteredonyourfirstelement,changingthefonttoArial:
h1Element.style.fontFamily="Arial";
Youthennavigateacrosstothe<p/>elementusingthenextSiblingproperty,againcheckingforwhitespace:
if(h1Element.nextSibling.nodeType==3){
pElement=h1Element.nextSibling.nextSibling;
}else{
pElement=h1Element.nextSibling;
}
alert(pElement.tagName);
Youchangethe<p/>element’sfonttoArialalso:
pElement.style.fontFamily="Arial";
Finally,youusethepreviousSiblingpropertytomovebackinyourtreetothe<h1/>elementandthistimechangethefonttoCourier:
if(pElement.previousSibling.nodeType==3){
h1Element=pElement.previousSibling.previousSibling;
}else{
h1Element=pElement.previousSibling;
}
h1Element.style.fontFamily="Courier";
Thisisafairlyeasyexampletofollowbecauseyou’reusingthesametreestructureyoucreatedwithdiagrams,butitdoesshowhowtheDOMeffectivelycreatesthishierarchyandthatyoucanmovearoundwithinitusingscript.
MethodsoftheNodeObjectWhereastheNodeobject’spropertiesenableyoutonavigatetheDOM,itsmethodsprovidethecompletelydifferentabilitytoaddandremovenodesfromtheDOM,thusfundamentallyalteringthestructureoftheHTMLdocument.Thefollowingtableliststhesemethods.
METHODSOFNODEOBJECTS
DESCRIPTION
appendChild(newNode) AddsanewNodeobjecttotheendofthelistofchildnodes.Thismethodreturnstheappendednode.
cloneNode(cloneChildren) Returnsaduplicateofthecurrentnode.Itacceptsabooleanvalue.Ifthevalueistrue,themethodclonesthecurrentnodeandallchildnodes.Ifthevalueisfalse,onlythecurrentnodeisclonedandchildnodesareleftoutoftheclone.
hasChildNodes() ReturnstrueifanodehasanychildnodesandfalseifnotinsertBefore(newNode,
referenceNode)
InsertsanewNodeobjectintothelistofchildnodesbeforethenodestipulatedbyreferenceNode.Returnstheinsertednode
removeChild(childNode) RemovesachildnodefromalistofchildnodesoftheNodeobject.Returnstheremovednode
TRYITOUTCreatingHTMLElementsandTextwithDOMMethodsInthisTryItOutyoucreateawebpagewithjustparagraph<p/>andheading<h1/>elements,butinsteadofHTMLyou’llusetheDOMpropertiesandmethodstoplacetheseelementsonthewebpage.Startupyourpreferredtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example3</title>
</head>
<body>
<script>
varnewText=document.createTextNode("MyHeading");
varnewElem=document.createElement("h1");
newElem.appendChild(newText);
document.body.appendChild(newElem);
newText=document.createTextNode("Thisissometextina
paragraph");
newElem=document.createElement("p");
newElem.appendChild(newText);
document.body.appendChild(newElem);
</script>
</body>
</html>
Savethispageasch9_example3.htmlandopenitinabrowser(Figure9.10).
Figure9.10
Italllooksabitdullandtedious,doesn’tit?Andyes,youcouldhavedonethismuchmoresimplywithHTML.Thatisn’tthepoint,though.TheideaisthatyouuseDOMpropertiesandmethods,accessedwithJavaScript,toinserttheseelements.Thefirsttwolinesofthescriptblockareusedtodefinethevariablesinyourscript,whichareinitializedtoholdthetextyouwanttoinsertintothepageandtheHTMLelementyouwanttoinsert:
varnewText=document.createTextNode("MyHeading");
varnewElem=document.createElement("h1");
Youstartatthebottomofyourtreefirst,bycreatingatextnodewiththecreateTextNode()method.ThenusethecreateElement()methodtocreateanHTMLheading.
Atthispoint,thetwovariablesareentirelyseparatefromeachother.Youhaveatextnode,andyouhavean<h1/>element,butthey’renotconnected.ThenextlineenablesyoutoattachthetextnodetoyourHTMLelement.YoureferencetheHTMLelementyouhavecreatedwiththevariablenamenewElem,usetheappendChild()methodofyournode,andsupplythecontentsofthenewTextvariableyoucreatedearlierasaparameter:
newElem.appendChild(newText);
Let’srecap.YoucreatedatextnodeandstoreditinthenewTextvariable.Youcreatedan<h1/>elementandstoreditinthenewElemvariable.Thenyouappendedthetextnodeasachildnodetothe<h1/>element.Thatstillleavesyouwithaproblem:You’vecreatedanelementwithavalue,buttheelementisn’tpartofyourdocument.Youneedtoattachtheentiretyofwhatyou’vecreatedsofartothedocumentbody.Again,youcandothiswiththeappendChild()method,butthistimecallitonthedocument.bodyobject(which,too,isaNode):
document.body.appendChild(newElem);
Thiscompletesthefirstpartofyourcode.Nowallyouhavetodoisrepeattheprocessforthe<p/>element:
newText=document.createTextNode("Thisissometextinaparagraph");
newElem=document.createElement("p");
newElem.appendChild(newText);
document.body.appendChild(newElem);
Youcreateatextnodefirst;thenyoucreateanelement.Youattachthetexttotheelement,andfinallyyouattachtheelementandtexttothebodyofthedocument.
It’simportanttonotethattheorderinwhichyoucreatenodesdoesnotmatter.Thisexamplehadyoucreatethetextnodesbeforetheelementnodes;ifyouwanted,youcouldhavecreatedtheelementsfirstandthetextnodessecond.
However,theorderinwhichyouappendnodesisveryimportantforperformancereasons.UpdatingtheDOMcanbeanexpensiveprocess,andperformancecansufferifyoumakemanychangestotheDOM.Forexample,thisexampleupdatedtheDOMonlytwotimesbyappendingthecompletedelementstothedocument’sbody.Itwouldrequirefourupdatesifyouappendedtheelementtothedocument’sbodyandthenappendedthetextnodetotheelement.Asaruleofthumb,onlyappendcompletedelementnodes(thatis,theelement,itsattributes,andanytext)tothedocumentwheneveryoucan.
NowthatyoucannavigateandmakechangestotheDOM,let’slookfurtherintomanipulatingDOMnodes.
MANIPULATINGTHEDOMDOMscriptingisthemanipulationofanHTMLpageafterit’sloadedintothebrowser.Uptothispoint,you’veexaminedthepropertiesandmethodsofthebasicDOMobjectsandlearnedhowtotraversetheDOMthroughJavaScript.
Throughouttheprevioussection,yousawsomeexamplesofmanipulatingtheDOM;morespecifically,yousawthatyoucanchangethecolorandfontfamilyoftextcontainedwithinanelement.Inthissection,youexpandonthatknowledge.
AccessingElementsAsyousawintheprevioussection,theDOMholdsthetoolsyouneedtofindandaccessHTMLelements;youusedthegetElementById()methodquitefrequently,andthroughexamplesyousawhoweasyitwastofindspecificelementsinthepage.
WhenscriptingtheDOM,chancesareyouhaveaprettygoodideaofwhatelementsyouwanttomanipulate.TheeasiestwaystofindthoseelementsarewiththegetElementById(),querySelector(),andquerySelectorAll()methods.Ifanelementhasanidattribute,usegetElementById()becauseitisthefastestwaytofindanelementinthepage.Otherwise,you’llneedtousethequerySelector()andquerySelectorAll()methods.
ChangingAppearancesProbablythemostcommonDOMmanipulationistochangethewayanelementlooks.Suchachangecancreateaninteractiveexperienceforvisitorstoyourwebsiteandcanevenbeusedtoalertthemtoimportantinformationorthatanactionisrequiredbythem.ChangingthewayanelementlooksconsistsalmostexclusivelyofchangingCSSpropertiesforanHTMLelement.YoucandothistwowaysthroughJavaScript:
ChangeeachCSSpropertywiththestyleproperty.
Changethevalueoftheelement’sclassattribute.
UsingthestylePropertyTochangespecificCSSproperties,youmustlooktothestyleproperty.Allbrowsersimplementthisobject,whichmapsdirectlytotheelement’sstyleattribute.ThisobjectcontainsCSSproperties,andbyusingityoucanchangeanyCSSpropertythatthebrowsersupports.You’vealreadyseenthestylepropertyinuse,buthere’saquickrefresher:
element.style.cssProperty=value;
TheCSSpropertynamesgenerallymatchthoseusedinaCSSstylesheet;therefore,changingthetextcolorofanelementrequirestheuseofthecolorproperty,likethis:
vardivAdvert=document.getElementById("divAdvert");
divAdvert.style.color="blue";
Insomecases,however,thepropertynameisalittledifferentfromtheoneseeninaCSSfile.CSSpropertiesthatcontainahyphen(-)areaperfectexampleofthisexception.Inthecaseoftheseproperties,youremovethehyphenandcapitalizethefirstletterofthewordthatfollowsthehyphen.Thefollowingcodeshowstheincorrectandcorrectwaystodothis:
divAdvert.style.background-color="gray";//wrong
divAdvert.style.backgroundColor="gray";//correct
Youcanalsousethestyleobjecttoretrievestylesthathavepreviouslybeendeclared.However,ifthestylepropertyyoutrytoretrievehasnotbeensetwiththestyleattribute(inlinestyles)orwiththestyleobject,youwillnotretrievetheproperty’svalue.ConsiderthefollowingHTMLcontainingastylesheetand<div/>element:
<style>
#divAdvert{
background-color:gray;
}
</style>
<divid="divAdvert"style="color:green">Iamanadvertisement.</div>
Whenthebrowserrendersthiselement,itwillhavegreentextonagraybackground.Ifyouhadusedthestyleobjecttoretrievethevalueofboththebackground-colorandcolorproperties,you’dgetthefollowingmixedresults:
vardivAdvert=document.getElementById("divAdvert");
alert(divAdvert.style.backgroundColor);//alertsanemptystring
alert(divAdvert.style.color);//alertsgreen
Yougettheseresultsbecausethestyleobjectmapsdirectlytothestyleattributeoftheelement.Ifthestyledeclarationissetina<style/>element,orinanexternalstylesheet,youcannotretrievethatproperty’svaluewiththestyleobject.
TRYITOUTUsingthestyleObjectLet’slookatasimpleexampleofchangingtheappearanceofsometextbyusingthestyleobject.Typethefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example4</title>
<style>
#divAdvert{
font:12ptarial;
}
</style>
</head>
<body>
<divid="divAdvert">
Hereisanadvertisement.
</div>
<script>
vardivAdvert=document.getElementById("divAdvert");
divAdvert.style.fontStyle="italic";
divAdvert.style.textDecoration="underline";
</script>
</body>
</html>
Savethisasch9_example4.html.Whenyourunthisinyourbrowser,youshouldseeasinglelineoftextthatisitalicizedandunderlined,asshowninFigure9.11.
Figure9.11
Inthepage’sbody,a<div/>elementisdefinedwithanidofdivAdvert.The<script/>elementappearsafterthe<div/>,anditcontainsthefollowingJavaScriptcode:
vardivAdvert=document.getElementById("divAdvert");
divAdvert.style.fontStyle="italic";
divAdvert.style.textDecoration="underline";
Beforeyoucandoanythingtothe<div/>element,youmustfirstretrieveit.YoudothissimplybyusingthegetElementById()method.Nowthatyouhavetheelement,youmanipulateitsstylebyfirstitalicizingthetextwiththefontStyleproperty.Next,youunderlinethetextbyusingthetextDecorationpropertyandassigningitsvaluetounderline.
It’sveryimportantthatthe<divid="divAdvert"/>elementisloadedintothebrowserbeforeyouretrieveitwithgetElementById().Thisiswhythe<script/>elementappearsafter<divid="divAdvert"/>.BythetimethebrowserloadsandexecutestheJavaScriptcode,the<div/>elementisloadedintotheDOM.
ChangingtheclassAttributeYoucanassignaCSSclasstoelementsbyusingtheelement’sclassattribute.ThisattributeisexposedintheDOMbytheclassNamepropertyandcanbechangedthroughJavaScripttoassociateadifferentstylerulewiththeelement:
element.className=sNewClassName;
UsingtheclassNamepropertytochangeanelement’sstyleisadvantageousintwoways:
ItreducestheamountofJavaScriptyouhavetowrite,whichnooneislikelytocomplainabout.
ItkeepsstyleinformationoutoftheJavaScriptfileandputsitintotheCSSfilewhereitbelongs.Makinganytypeofchangestothestylerulesiseasierbecauseyoudonothavetohaveseveralfilesopeninordertochangethem.
TRYITOUTUsingtheclassNamePropertyLet’srevisitthecodefromch9 _ example4.htmlfromtheprevioussectionandmakesomerevisions.Typethefollowingcode:
-transitional.dtd”>
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example5</title>
<style>
#divAdvert{
font:12ptarial;
}
.new-style{
font-style:italic;
text-decoration:underline;
}
</style>
</head>
<body>
<divid="divAdvert">
Hereisanadvertisement.
</div>
<script>
vardivAdvert=document.getElementById("divAdvert");
divAdvert.className="new-style";
</script>
</body>
</html>
Savethisasch9 _ example5.html.
Twokeydifferencesexistbetweench9 _ example4.htmlandch9 _ example5.html.ThefirstistheadditionofaCSSclasscallednew-style:
.newStyle{
font-style:italic;
text-decoration:underline;
}
Thisclasscontainsstyledeclarationstospecifyitalicizedandunderlinedtext.
ThesecondchangeisintheJavaScriptitself:
vardivAdvert=document.getElementById("divAdvert");
divAdvert.className="new-style";
}
Thefirststatementretrievesthe<div/>elementbyusingthegetElementById()method.ThesecondstatementchangestheclassNamepropertytothevaluenew-style.Withthisline,thedivAdvertelementtakesonanewstyleruleandthebrowserchangesthewayitlooks.
NOTEAlthoughitwasn’tdemonstratedhere,theHTMLclassattribute,andthustheclassNameproperty,cancontainmultipleCSSclassnames.YouseemoreaboutmultipleclassnamesinChapter16.
PositioningandMovingContentChangingtheappearanceofanelementisanimportantpatterninDOMscripting,anditfindsitsplaceinmanyscripts.However,thereismoretoDOMscriptingthanjustchangingthewaycontentappearsonthepage;youcanalsochangethepositionofanelementwithJavaScript.
MovingcontentwithJavaScriptisjustaseasyasusingthestyleobject.Youusethepositionpropertytochangethetypeofpositiondesired,andbyusingtheleftandtopproperties,youcanpositiontheelement:
vardivAdvert=document.getElementById("divAdvert");
divAdvert.style.position="absolute";
divAdvert.style.left="100px";//settheleftposition
divAdvert.style.top="100px";//settherightposition
ThiscodefirstretrievesthedivAdvertelement.Thenitsetstheelement’spositionto
absoluteandmovestheelement100pixelsfromtheleftandtopedges.Noticetheadditionofpxtothevalueassignedtothepositions.Youmustspecifyaunitwhenassigningapositionalvalue;otherwise,thebrowserwillnotpositiontheelement.
NOTEPositioningelementsrequiresthepositionofabsoluteorrelative.
Example:AnimatedAdvertisementPerhapsthemostcreativeuseofDOMscriptingisinanimatingcontentonthepage.Youcanperformavarietyofanimations:youcanfadetextelementsorimagesinandout,givethemaswipeanimation(makingitlooklikeasiftheyarewipedontothepage),andanimatethemtomovearoundonthepage.
Animationcangiveimportantinformationtheflairitneedstobeeasilyrecognizedbyyourreader,aswellasaddinga“that’scool”factor.PerforminganimationwithJavaScriptfollowsthesameprinciplesofanyothertypeofanimation:Youmakeseeminglyinsignificantchangesoneatatimeinasequentialorderuntilyoureachtheendoftheanimation.Essentially,withanyanimation,youhavethefollowingrequisites:
1. Thestartingstate
2. Themovementtowardthefinalgoal
3. Theendstate;stoppingtheanimation
Animatinganabsolutelypositionedelement,asyou’regoingtodointhissection,isnodifferent.First,withCSS,positiontheelementatthestartlocation.Thenperformtheanimationupuntilyoureachtheendpoint,whichsignalstheendoftheanimation.
Inthissection,youlearnhowtoanimatecontenttobouncebackandforthbetweentwopoints.Todothis,youneedoneimportantpieceofinformation:thecontent’scurrentlocation.
AreWeThereYet?TheDOMinmodernbrowsersexposestheoffsetTopandoffsetLeftpropertiesofanHTMLelementobject.Thesetwopropertiesreturnthecalculatedpositionrelativetotheelement’sparentelement:offsetToptellsyouthetoplocation,andoffsetLefttellsyoutheleftposition.Thevaluesreturnedbythesepropertiesarenumericalvalues,soyoucaneasilychecktoseewhereyourelementcurrentlyisintheanimation.Forexample:
varendPointX=394;
if(element.offsetLeft<endPointX){
//continueanimation
}
Theprecedingcodespecifiestheendpoint(inthiscase,394)andassignsittotheendPointXvariable.Youcanthenchecktoseeiftheelement’soffsetLeftvalueiscurrentlylessthanthatoftheendpoint.Ifitis,youcancontinuetheanimation.Thisexamplebringsustothenexttopicincontentmovement:performingtheanimation.
PerformingtheAnimationToperformananimation,youneedtomodifythetopandleftpropertiesofthestyleobjectincrementallyandquickly.Youdothiswithperiodicfunctionexecutionuntilit’stimetoendtheanimation.Todothis,useoneoftwomethodsofthewindowobject:setTimeout()orsetInterval().ThisexampleusesthesetInterval()methodtoperiodicallymoveanelement.
TRYITOUTAnimatingContentThispagemovesanelementacrossthepagefromrighttoleft.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Example6</title>
<style>
#divAdvert{
position:absolute;
font:12pxArial;
top:4px;
left:0px;
}
</style>
</head>
<body>
<divid="divAdvert">
Hereisanadvertisement.
</div>
<script>
varswitchDirection=false;
functiondoAnimation(){
vardivAdvert=document.getElementById("divAdvert");
varcurrentLeft=divAdvert.offsetLeft;
varnewLocation;
if(!switchDirection){
newLocation=currentLeft+2;
if(currentLeft>=400){
switchDirection=true;
}
}else{
newLocation=currentLeft-2;
if(currentLeft<=0){
switchDirection=false;
}
}
divAdvert.style.left=newLocation+"px";
}
setInterval(doAnimation,10);
</script>
</body>
</html>
Savethispageasch9 _ example6.htmlandloaditintoyourbrowser.Whenyouloadthepageintothebrowser,thecontentshouldstartmovingfromlefttoright,startingattheleftedgeoftheviewport.Whenthecontentreachesaleftpositionof400pixels,thecontentswitchesdirectionsandbeginstomovebacktowardtheleftedge.Thisanimationiscontinuous,soitshouldbouncebetweenthetwopoints(0and400)perpetually.
Insidethebodyofthepageisa<div/>element.ThiselementhasanidofdivAdvertsothatyoucanretrieveitwiththegetElementById()method,becausethisistheelementyouwanttoanimate:
<divid="divAdvert">
Hereisanadvertisement.
</div>
Thiselementhasnostyleattributesbecauseallthestyleinformationisinsidethestylesheetlocatedintheheadofthepage.Inthestylesheet,youdefineastartingpointforthis<div/>.Youwanttheanimationtogofirstfromlefttoright,andyouwantittostartattheleftedgeofthebrowser:
#divAdvert{
position:absolute;
font:12ptarial;
top:4px;
left:0px;
}
Thefirststyledeclarationpositionstheelementabsolutely,andthesecondspecifiesthefontas12-pointArial.Thenextdeclarationpositionstheelementfourpixelsfromthetopofthebrowser’sviewport.Settingthetoppositionawayfromthetopmostedgemakesthetextalittleeasiertoread.Finally,thelastlinepositionsthedivAdvertelementalongtheleftedgeoftheviewportwiththeleftproperty.
WithinthescriptblockisaglobalvariablecalledswitchDirection:
varswitchDirection=false;
Thisvariablekeepstrackofthedirectioninwhichthecontentiscurrentlygoing.IfswitchDirectionisfalse,thecontentismovingfromlefttoright,whichisthedefault.IfswitchDirectionistrue,thecontentismovingfromrighttoleft.
NextinthescriptblockisthedoAnimation()function,whichperformstheanimation:
functiondoAnimation(){
vardivAdvert=document.getElementById("divAdvert");
varcurrentLeft=divAdvert.offsetLeft;
varnewLocation;
First,youretrievethedivAdvertelementwiththegetElementById()method;youalsoretrievetheoffsetLeftpropertyandassignitsvaluetothecurrentLeftvariable.Youusethisvariabletocheckthecontent’scurrentposition.Next,createavariablecallednewLocationthatwillcontainthenewleftposition,butbeforeyouassignitsvalueyouneedtoknowthedirectioninwhichthecontentismoving:
if(!switchDirection){
newLocation=currentLeft+2;
if(currentLeft>=400){
switchDirection=true;
}
}
First,checkthedirectionbycheckingtheswitchDirectionvariable.Remember,ifitisfalse,theanimationismovingfromlefttoright;soassignnewLocationtocontainthecontent’scurrentpositionandadd2,thusmovingthecontenttwopixelstotheright.
Youthenneedtocheckifthecontenthasreachedtheleftpositionof400pixels.Ifithas,youneedtoswitchthedirectionoftheanimation,andyoudothisbychangingswitchDirectiontotrue.SothenexttimedoAnimation()runs,itwillbegintomovethecontentfromrighttoleft.
Thecodetomovetheelementinthisnewdirectionissimilartothepreviouscode,exceptforafewkeydifferences:
else{
newLocation=currentLeft-2;
if(currentLeft<=0){
switchDirection=false;
}
}
ThefirstdifferenceisthevalueassignedtonewLocation;insteadofadding2tothecurrentlocation,yousubtract2,thusmovingthecontenttwopixelstotheleft.Next,checkifcurrentLeftislessthanorequalto0.Ifitis,youknowyou’vereachedtheendingpointoftheright-to-leftmovementandneedtoswitchdirectionsagainbyassigningswitchDirectiontobefalse.
Finally,setthenewpositionofthecontent:
divAdvert.style.left=newLocation+"px";
}
Thisfinallineofthefunctionsetstheelement’sleftpropertytothevaluestoredinthenewLocationvariableplusthestring"px".
Toruntheanimation,usesetInterval()tocontinuouslyexecutedoAnimation().
ThefollowingcoderunsdoAnimation()every10milliseconds:
setInterval(doAnimation,10);
Atthisspeed,thecontentmovesatapacethatiseasilyseenbythoseviewingthepage.Ifyouwanttospeeduporslowdowntheanimation,simplychangehowoftenthesetInterval()functioncallsdoAnimation()bychangingthesecondparameter.
Whathaveyouseensofar?Well,you’veseentheDOMhierarchyandhowitrepresentstheHTMLdocumentasatree-likestructure.YounavigatedthroughthedifferentpartsofitviaDOMobjects(theNodeobjects)andtheirproperties,andyouchangedthepropertiesofobjects,thusalteringthecontentofthewebpage.ThisleavesjustoneareaoftheDOMtocover:theeventmodel.Youlearnabouteventsinthenextchapter.
SUMMARYThischapterhasfeaturedquiteafewdiversionsanddigressions,butthesewerenecessarytodemonstratethepositionandimportanceofthedocumentobjectmodelinJavaScript.
Thischaptercoveredthefollowingpoints:
Itstartedbyoutliningtwoofthemainstandards—HTMLandECMAScript—andexaminedtherelationshipsbetweenthem.YousawthatacommonaimemergingfromthesestandardswastoprovideguidelinesforcodingHTMLwebpages.Thoseguidelinesinturnbenefitedthedocumentobjectmodel,makingitpossibletoaccessandmanipulateanyitemonthewebpageusingscriptifwebpageswerecodedaccordingtothoseguidelines.
Youexaminedthedocumentobjectmodelandsawthatitofferedabrowser-independentmeansofaccessingtheitemsonawebpage,andthatitresolvedsomeoftheproblemsthatdoggedolderbrowsers.YousawhowtheDOMrepresentstheHTMLdocumentasatreestructureandhowitispossibleforyoutonavigatethroughthetreetodifferentelementsandusethepropertiesandmethodsitexposestoaccessthedifferentpartsofthewebpage.
TheDOMletsyouchangeapageafteritisloadedintothebrowser,andyoucanperformavarietyofuserinterfacetrickstoaddsomeflairtoyourpage.
Youlearnedhowtochangeatag’sstylebyusingthestyleandclassNameproperties.
Youalsolearnedthebasicsofanimationandmadetextbouncebackandforthbetweentwopoints.
EXERCISES1. Here’ssomeHTMLcodethatcreatesatable.Re-createthistableusingonly
JavaScriptandthecoreDOMobjectstogeneratetheHTML.Testyourcodeinallbrowsersavailabletoyoutomakesureitworksinthem.Hint:Commenteachlineasyouwriteittokeeptrackofwhereyouareinthetreestructure,andcreateanewvariableforeveryelementonthepage(forexample,notjustoneforeachoftheTDcellsbutninevariables).
<table>
<tr>
<td>Car</td>
<td>TopSpeed</td>
<td>Price</td>
</tr>
<tr>
<td>Chevrolet</td>
<td>120mph</td>
<td>$10,000</td>
</tr>
<tr>
<td>Pontiac</td>
<td>140mph</td>
<td>$20,000</td>
</tr>
</table>
2. Modifych9_example6.htmlfromthe“AnimatingContent”TryItOutsothattheamountofpixelsmovedineitherdirectioniscontrolledbyaglobalvariable.Callitdirection.RemovetheswitchDirectionvariable,andchangethecodetousethenewdirectionvariabletodeterminewhentheanimationshouldchangedirections.
10EventsWHATYOUWILLLEARNINTHISCHAPTER:
Connectingyourcodetoeventstorespondtouseractions
Writingstandards-compliant,event-drivencode
WritingeventcodeforolderversionsofInternetExplorer
Handlingthedifferencebetweenstandards-compliantandold-IEeventmodels
DragginganddroppingcontentwithHTML5’snativedrag-and-dropcapabilities
Animatingelementsbymanipulatingtheirpositioning
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
There’snodoubtthatJavaScriptisausefultoolinwebprogramming.You’veseenhowtodynamicallycreate,remove,andmanipulateHTMLinthepage,andinthecomingchapters,youlearnhowtoprocessuserinputandsenddatatotheserver.
Althoughthesecapabilitiesareveryimportantintoday’swebprogramming,perhapsthemostimportantconceptyou’lllearnanduseisthatofevents.Intherealworld,aneventis,putsimply,somethingthathappens.Forexample,aringingtelephoneisanevent.Ifyouareexpectingafriendorcolleaguetocall,youusuallywanttodosomething:Answerthecall.
Inprogramming,eventsareverysimilartoatelephonecall.Somethinginthepagewillhappen,andifit’ssomethingyouareexpecting,youcanrespondtoit.Forexample,theuserclickingthepage,pressingakeyonthekeyboard,ormovingthemousepointeroversometextallcauseeventstooccur.Anotherexample,whichisusedquitefrequently,istheloadeventforthepage:Thewindowraises(orfires)anotificationwhenthepageiscompletelyloadedinthebrowser.
Whyshouldyoubeinterestedinevents?
Takeasanexamplethesituationinwhichyouwanttomakeamenupopupwhentheuserclicksanywhereinyourwebpage.Assumingthatyoucanwriteafunctionthatwillmakethepop-upmenuappear,howdoyouknowwhentomakeitappear,orinotherwords,whentocallthefunction?Yousomehowneedtointercepttheeventoftheuserclickinginthedocument,andmakesureyourfunctioniscalledwhenthateventoccurs.
Todothis,youneedtousesomethingcalledaneventhandler,orlistener.Youassociatethiswiththecodethatyouwanttoexecutewhentheeventoccurs.Thisprovidesyouwith
awayofinterceptingeventsandmakingyourcodeexecutewhentheyhaveoccurred.Youwillfindthataddinganeventhandlertoyourcodeisoftenknownas“connectingyourcodetotheevent.”It’sabitlikesettinganalarmclock—yousettheclocktomakearingingnoisewhenacertaineventhappens.Withalarmclocks,theeventiswhenacertaintimeisreached.
TYPESOFEVENTSWebdevelopment,especiallywhenitcomestoJavaScript,isprimarilyevent-driven,meaningthattheflowoftheprogramiscontrolledbyevents.Inotherwords,alargeportionofyourJavaScriptcodeusuallyonlyexecuteswhenaneventoccurs,andyoucanlistenformanyevents.
Takeamomentandthinkabouthowyouinteractwithawebpage.Onacomputerorlaptop,youmoveyourmousearoundthepage,perhapsyouselecttextthatyouwanttocopyandpasteintoyournote-takingprogram,andyoudefinitelyclickthings(likelinks).Ontouch-baseddevices,youtapitemsinthepage.Andonallweb-enableddevices,youfilloutformsbytypingkeysonthekeyboard.Virtuallyeverythingyoudotriggersanevent,andalotofthetime,youwanttowritecodethatreactstosomeofthoseevents.
Followingisalistofthemanytypesofeventsthatyoucanlistenforandreactto:
Mouseevents:Theseoccurwhentheuserdoessomethingwiththemouse,suchasmovingthecursor,clicking,double-clicking,dragging,andsoon.
Keyboardevents:Theseoccurwhenkeysonthekeyboardarepressedordepressed.Thoughcommonlyusedinconjunctionwithforms,keyboardeventsoccureverytimetheuserpressesordepressesakey.
Progressionevents:Thesearemoregenericeventsthatoccuratdifferentstagesofanobject.Forexample,whenthedocumentloads.
Formevents:Theseoccurwhensomethingintheformchanges.
Mutationevents:TheseoccurwhenDOMnodesaremodified.
Touchevents:Theseoccurwhentheusertouchesthesensor.
Errorevents:Theseoccurwhenanerroroccurs.
Themostcommonuser-basedeventsaremouseevents,andrightlyso.Theprimarywayusersinteractwiththeircomputersiswiththemouse,butthat’sstartingtochangeasmoreandmorepeopleowntouch-enableddevices.
Themainfocusofthischapteristoteachyouhowtolistenforevents,anditdoessoprimarilywithmouseevents.Inthenextchapter,youusesomekeyboardeventstointeractwithforms.
CONNECTINGCODETOEVENTSBrowsershavebeenaroundforquitesometime,andasyoucanguess,thewayinwhichwelistenforeventshasevolvedovertheyears.ButevenwiththemanychangestheJavaScriptcommunityhasseenovertheyears,theoldwaysoflisteningforeventsarestillsupportedandusefulincertainsituations.
Chapter5introducedobjectsdefinedbytheirmethodsandproperties.However,objectsalsohaveeventsassociatedwiththem.Thiswasnotmentionedbefore,becausenativeJavaScriptobjectsdonothavetheseevents,buttheobjectsofthebrowserobjectmodel(BOM)anddocumentobjectmodel(DOM)do.
Youcanconnectyourcodetoaneventinthreeways:
AssigningHTMLattributes
Assigninganobject’sspecialproperties
Callinganobject’sspecialmethods
HandlingEventsviaHTMLAttributesInthissectionyoucreateasimpleHTMLpagewithasinglehyperlink,givenbytheelement<a/>.Associatedwiththiselementistheaobject,andoneoftheeventstheaobjecthasistheclickevent.Theclickeventfires,notsurprisingly,whentheuserclicksthehyperlink.Feelfreetofollowalong;openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>ConnectingEventsUsingHTMLAttributes</title>
</head>
<body>
<ahref="somepage.html">ClickMe</a>
</body>
</html>
Asitstands,thispagedoesnothinganormalhyperlinkdoesn’tdo.Youclickit,anditnavigatesthewindowtoanotherpage,calledsomepage.html,whichwouldneedtobecreated.There’sbeennoeventhandleraddedtothelink—yet!
Asmentionedearlier,onewayofconnectingtheeventtoyourcodeistoadditdirectlytotheopeningtagoftheelementobjectwhoseeventyouarecapturing.Inthiscase,it’stheclickeventoftheaobject,asdefinedbythe<a/>element.Onclickingthelink,youwanttocapturetheeventandconnectittoyourcode.Youneedtoaddtheeventhandler,inthiscaseonclick,asanattributetotheopening<a>tag.Yousetthevalueoftheattributetothecodeyouwanttoexecutewhentheeventoccurs.
Rewritetheopening<a>tagtodothisasfollows:
<ahref="somepage.html"onclick="alert('Youclicked?')">ClickMe</a>
Thiscodeaddsonclick="alert('YouClicked?')"tothedefinitionoftheopening<a>tag.Now,whenthelinkisclicked,youseeanalertbox.Afterthis,thehyperlinkdoesitsusualstuffandtakesyoutothepagedefinedinthehrefattribute.
Thisisfineifyouhaveonlyonelineofcodetoconnecttotheeventhandler,butwhatifyouwantanumberoflinestoexecutewhenthelinkisclicked?
Well,allyouneedtodoisdefinethefunctionyouwanttoexecuteandcallitintheonclickcode.Dothatnow:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>ConnectingEventsUsingHTMLAttributes</title>
</head>
<body>
<ahref="somepage.html"onclick="returnlinkClick()">ClickMe</a>
<script>
functionlinkClick(){
alert("YouClicked?");
returntrue;
}
</script>
</body>
</html>
Withinthescriptblock,youhavecreatedastandardfunction.TheonclickattributeisnowconnectedtosomecodethatcallsthefunctionlinkClick().Therefore,whentheuserclicksthehyperlink,thisfunctionwillbeexecuted.
You’llalsoseethatthefunctionreturnsavalue,trueinthiscase.Also,whereyoudefineyouronclickattribute,youreturnthereturnvalueofthefunctionbyusingthereturnstatementbeforethefunctionname.Whydothis?
Thevaluereturnedbyonclick="returnlinkClick()"isusedbyJavaScripttodecidewhetherthenormalactionofthelink—thatis,goingtoanewpage—shouldoccur.Ifyoureturntrue,theactioncontinues,andyougotosomepage.html.Ifyoureturnfalse,thenormalchainofevents(thatis,goingtosomepage.html)doesnothappen.Yousaythattheactionassociatedwiththeeventiscanceled.Trychangingthefunctiontothis:
functionlinkClick(){
alert("Thislinkisgoingnowhere");
returnfalse;
}
Nowyou’llfindthatyoujustgetamessage,andnoattemptismadetogotosomepage.html.
NOTENotallobjectsandtheireventsmakeuseofthereturnvalue,sosometimesit’sredundant.
Someeventsarenotdirectlylinkedwiththeuser’sactionsassuch.Forexample,thewindowobjecthastheloadevent,whichfireswhenapageisloaded,andtheunloadevent,whichfireswhenthepageisunloaded(thatis,whentheusereitherclosesthebrowserormovestoanotherpage).
Eventhandlersforthewindowobjectactuallygoinsidetheopening<body>tag.Forexample,toaddaneventhandlerfortheloadandunloadevents,you’dwritethefollowing:
<bodyonload="myOnLoadfunction()"onunload="myOnUnloadFunction()">
TRYITOUTDisplayingRandomImageswithHTMLAttributeEventHandlersInthisTryItOut,youconnecttoanimage’sclickeventtorandomlychangetheimageloadedinapage.Openyoureditorandtypeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example1</title>
</head>
<body>
<imgsrc="usa.gif"onclick="changeImg(this)"/>
<imgsrc="mexico.gif"onclick="changeImg(this)"/>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(that){
varnewImgNumber=Math.round(Math.random()*3);
while(that.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
that.src=myImages[newImgNumber];
}
</script>
</body>
</html>
Savethepageasch10_example1.html.Youwillneedfourimagefilesfortheexample,whichyoucancreateorretrievefromthecodedownloadavailablewiththisbook.
Loadthepageintoyourbrowser.YoushouldseeapagelikethatshowninFigure10.1.
Figure10.1
Ifyouclickanimage,you’llseeitchangetoadifferentimage,whichisselectedrandomly.
Thefirstlineinthescriptblockatthetopofthepagedefinesavariablewithpage-levelscope.Thisisanarraythatcontainsyourlistofimagesources:
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
NextyouhavethechangeImg()function,whichwillbeconnectedtotheonclickeventhandlerofthe<img/>elementsdefinedinthepage.Youareusingthesamefunctionfortheonclickeventhandlersofbothimages,andindeed,canconnectonefunctiontoasmanyeventhandlersasyoulike.Thisfunctionacceptsoneparametercalledthat.Itiscalledthatbecauseyoupassthethiskeywordtothefunction,whichgivesyouimmediateaccesstotheimgobjectyouclick.Youcanactuallynametheparameterwhateveryouwant,butmostdevelopersusetheword“that”whenitreferencesthis.
Inthefirstlineofthefunction,yousetthenewImgNumbervariabletoarandomintegerbetween0and3:
functionchangeImg(that){
varnewImgNumber=Math.round(Math.random()*3);
TheMath.random()methodprovidesarandomnumberbetween0and1,andyoumultiplythatbythreetogetanumberbetween0and3.Thisnumberisroundedtothenearestwholenumber(0,1,2,or3)bymeansofMath.round().ThisintegerprovidestheindexfortheimagesrcthatyouwillselectfromthemyImagesarray.
Thenextlinesareawhileloop,thepurposeofwhichistoensurethatyoudon’tselectthesameimageasthecurrentone.IfthestringcontainedinmyImages[newImgNumber]isfoundinsidethesrcpropertyofthecurrentimage,youknowit’sthesameandthatyouneedtogetanotherrandomnumber.Youkeeploopinguntilyougetanewimage,atwhichpointmyImages[newImgNumber]willnotbefoundintheexistingsrc,and-1willbereturnedbytheindexOf()method,breakingoutoftheloop:
while(that.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
Next,yousetthesrcpropertyoftheimgobjecttothenewvaluecontainedinyourmyImagesarray:
that.src=myImages[newImgNumber];
}
Youconnecttheonclickeventofthefirst<img/>elementtothechangeImg()function:
<imgsrc="usa.gif"onclick="changeImg(this)"/>
Andnowtothesecond<img/>element:
<imgsrc="mexico.gif"onclick="changeImg(this)"/>
PassingthisinthechangeImg()functiongivesthefunctiondirectaccesstothis<img/>element’scorrespondingobject.WhenyoupassthistoanHTMLelement’sattributeeventhandler,thecorrespondingobjectofthatelementispassedtothefunction.It’sanice,cleanwayofaccessingtheelement’sobjectinyourJavaScriptcode.
Thisexamplehadyoupassthisasanargumenttothefunctionhandlingtheelement’sclickevent.Thisisasimpleandeasywayofaccessingtheelementthatreceivedtheevent,butthere’safarmoreusefulobjectyoucanpass:anEventobjectthatcontainsalltheinformationabouttheevent.
PassingtheEventobjectisverysimpletodo;simplypasseventinsteadofthis.Forexample,inthefollowingcodethe<p/>elementwillraiseadblclickevent:
<pondblclick="handle(event)">Paragraph</p>
<script>
functionhandle(e){
alert(e.type);
}
</script>
Noticethateventispassedtothehandle()functionintheondblclickattribute.Thiseventvariableisspecialinthatitisnotdefinedanywhere;instead,itisanargumentusedonlywitheventhandlersthatareconnectedthroughHTMLattributes.Itpassesareferencetothecurrenteventobjectwhentheeventfires.
Ifyouranthepreviousexample,itwouldjusttellyouwhatkindofeventraisedyourevent-handlingfunction.Thismightseemself-evidentintheprecedingexample,butifyouhadincludedthefollowingextralinesofcode,anyoneofthreeelementscouldhaveraisedthefunction:
<pondblclick="handle(event)">Paragraph</p>
<h1onclick="handle(event)">Heading1</h1>
<spanonmouseover="handle(event)">SpecialText</span>
<script>
functionhandle(e){
alert(e.type);
}
</script>
Thismakesthecodemuchmoreuseful.Ingeneral,youwilluserelativelyfeweventhandlerstodealwithanynumberofevents,andyoucanusetheeventpropertiesasafiltertodeterminewhattypeofeventhappenedandwhatHTMLelementtriggeredit,sothatyoucantreateacheventdifferently.
Inthefollowingexample,youseethatyoucantakedifferentcoursesofactiondependingonwhattypeofeventisreturned:
<pondblclick="handle(event)">Paragraph</p>
<h1onclick="handle(event)">Heading1</h1>
<spanonmouseover="handle(event)">SpecialText</span>
<script>
functionhandle(e){
if(e.type=="mouseover"){
alert("YoumovedovertheSpecialText");
}
}
</script>
Thiscodeusesthetypepropertytodeterminewhattypeofeventoccurred.Ifusersmovetheirmousecursoroverthe<span/>element,analertboxtellsthemso.
YoulearnalotmoreabouttheEventobjectlaterinthechapter,butfornow,justknowthatitexposesapropertycalledtarget.Thisisthetargetoftheevent,theelementobjectthatreceivedtheevent.Withthisinformation,youcanrewritech10_example1.htmltousethemoreversatileEventobject.
TRYITOUTDisplayingRandomImageswithObjectPropertyEventHandlersandtheEventObjectInthisTryItOut,yourewritech10_example1.htmltousetheEventobjectinsteadofthis.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example2</title>
</head>
<body>
<imgsrc="usa.gif"onclick="changeImg(event)"/>
<imgsrc="mexico.gif"onclick="changeImg(event)"/>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=e.target;
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
</script>
</body>
</html>
Savethepageasch10_example2.html.Loadthepageintoyourbrowser,andyouwillseeapagesimilartoch10_example1.html.Clickanimage,andyou’llseeitchangetoarandompicture.
Thecodeforthispageisalmostidenticaltoch10_example1.html.Thisnewversionjusthasafewchanges.
Thefirsttwochangesareintheonclickeventhandlersofthe<img/>elements.InsteadofpassingthistochangeImg(),youpassevent.
ThenextchangeisinthechangeImg()declaration:
functionchangeImg(e){
Theparameternameisnowe,meaningevent.Keepinmindthatitdoesn’tmatterwhatyoucallthisparameter,butthegeneralconventionistousee.
Whenthebrowsercallsthisfunction,itwillpassanEventobjectastheeparameter,andyoucanretrievetheimgelementobjectthatreceivedtheeventbyusinge.target:
varel=e.target;
Youassignthisobjecttoavariablecalledel(shortforelement),andyouuseitinthewhileloop:
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
Youalsouseittoassignitssrcpropertyinthelastlineofthefunction:
el.src=myImages[newImgNumber];
ThechangesmadetochangeImg()areminimal,andthoughitdoesrequirejustalittlebitmorecode,itismuchmoreversatile,asyoulearnlaterinthechapter.
UsingtheHTMLattributeeventhandlersisaneasywaytoconnectyourJavaScriptcodetoanelement’sevents,buttheyhavesomedownsides:
YourHTMLandJavaScriptaremixedtogether.Thismakesitmoredifficulttomaintainandfindandfixbugs.
Youcan’tremoveaneventhandlerwithoutchangingtheHTML.
YoucanonlysetupeventhandlersforelementsthatappearinyourHTMLcode,asopposedtoelementsyoucreatedynamically(like,forexample,whenyoucreateanelementusingdocument.createElement()).
Theseissues,however,aresolvedwithanobject’seventhandlerproperties.
HandlingEventsviaObjectPropertiesWiththismethod,youfirstneedtodefinethefunctionthatwillbeexecutedwhentheeventoccurs.Thenyouneedtosetthatobject’seventhandlerpropertytothefunctionyoudefined.
Thisisillustratedinthefollowingexample.Openyoureditorandtypeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10,Example3</title>
</head>
<body>
<aid="someLink"href="somepage.html">
ClickMe
</a>
<script>
functionlinkClick(){
alert("Thislinkisgoingnowhere");
returnfalse;
}
document.getElementById("someLink").onclick=linkClick;
</script>
</body>
</html>
Savethisasch10_example3.html.
First,youhavethe<a/>element,whoseobject’seventyouareconnectingto.You’llnoticethereisnomentionoftheeventhandlerorthefunctionwithintheattributesofthetag,butdonoticethatitnowhasanidattribute.ThisissothatyoucaneasilyfindtheelementinthedocumentwiththegetElementById()method.
Next,youdefinethefunctionlinkClick(),muchasyoudidpreviously.Asbefore,youcanreturnavalueindicatingwhetheryouwantthenormalactionofthatobjecttohappen.
Theconnectionismadebetweentheobject’seventandthefunctiononthefinallinesofscript,asshowninthefollowingcode:
document.getElementById("someLink").onclick=linkClick;
Asyoulearnedinthepreviouschapter,thegetElementById()methodfindstheelementwiththegivenidandreturnstheaobject.Yousetthisobject’sonclickpropertytoreferenceyourfunction—thismakestheconnectionbetweentheobject’seventhandlerandyourfunction.Notethatnoparenthesesareaddedafterthefunctionname.YouareassigningthelinkClickfunctionobjecttotheelement’sonclickproperty,notexecutinglinkClick()andassigningitsreturnvaluetoonclick.
Takeamomentandlookbackatch10_example2.html.Whenyoulistenedfortheclickeventusingtheonclickattribute,youhadcompletecontroloverhowchangeImg()wascalled;yousimplycalledthefunctionandpassedittheeventobject.
Butthat’snowanissue.Lookagainattheonclickpropertyassignment:
document.getElementById("someLink").onclick=linkClick;
Younolongercontrolhowtheeventhandlerfunctionisexecuted;thebrowserexecutesthefunctionforyou.HowthendoyouattainareferencetotheEvent?Whenaneventtriggersandaneventhandlerexecutes,thebrowserautomaticallypassesanEventobjecttothehandlerfunction.
TRYITOUTDisplayingRandomImageswithObjectPropertyEventHandlersInthisTryItOut,yourewritech10_example2.htmltousetheonclickpropertyof
theimgobjects.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example4</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<imgid="img1"src="mexico.gif"/>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=e.target;
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
document.getElementById("img0").onclick=changeImg;
document.getElementById("img1").onclick=changeImg;
</script>
</body>
</html>
Savethepageasch10_example4.html.Loadthepageintoyourbrowser,andyouwillseeapagesimilartoch10_example2.html.Clickanimage,andyou’llseeitchangetoarandompicture.
Thecodeforthispageisalmostidenticaltoch10_example2.html.Thefirstchangesareinthe<img>tags.Theynolongerhaveonclickattributes,andtheynowhaveidattributes.Thefirstimagehasanidofimg0,andthesecondisimg1.TheseelementshaveanidsothatyoucanreferencetheminyourJavaScriptcode.
TheonlyotherchangesarethefinaltwolinesofJavaScriptcode:
document.getElementById("img0").onclick=changeImg;
document.getElementById("img1").onclick=changeImg;
Youusedocument.getElementById()toretrievethetwoimgobjectsfromtheDOMandassigntheironclickproperties,thussettingupthechangeImg()functionstohandletheclickeventsonbothimgobjects.
Removinganeventhandlerisrathertrivial.Simplyassignnulltotheeventhandlerproperty,likethis:
img1.onclick=null;
Byassigningnull,youhaveoverwrittenthepreviousvaluecontainedbytheproperty,andthatintroducesthemainproblemwiththesetypesofeventhandlers:youcanassignonlyonefunctiontohandleagivenevent.Forexample:
img2.onclick=functionOne;
img2.onclick=functionTwo;
ThefirstlineofthiscodeassignsafunctioncalledfunctionOne()toanelement’sonclickproperty.Thesecondline,however,overwritesthevalueofimg2.onclickbyassigningitanewvalue.So,whentheuserclicksimg2,onlyfunctionTwo()executes.Thatbehaviorisfineifit’swhatyouactuallywant,butmoreoftenthannot,youwantbothfunctionOne()andfunctionTwo()toexecutewhenimg2isclicked.
YoucandothatthankstothestandardDOMeventmodel.
THESTANDARDEVENTMODELUpuntilthispoint,you’vebeenworkingwithnonstandardtechniquesforlisteningforevents.Yes,theyworkineverybrowser,butthatsupportexistsprimarilyforbackwardcompatibility.Theyarenotguaranteedtoworkinfuturebrowserversions.
First,somehistory.Thetwomajorbrowsersinthelate1990swereInternetExplorer4andNetscape4—thefirstbrowserwar.Notsurprisingly,bothbrowservendorsimplementedvastlydifferentDOMsandeventmodels,fragmentingthewebintotwogroups:websitesthatcateredtoNetscapeonly,andwebsitesthatcateredtoIEonly.Veryfewdeveloperschosethefrustratingtaskofcross-browserdevelopment.
Obviously,aneedforastandardgrewfromthisfragmentationandfrustration.SotheW3CintroducedtheDOMstandard,whichgrewintoDOMlevel2,whichincludedastandardeventmodel.
TheDOMstandarddefinesanobjectcalledEventTarget.Itspurposeistodefineastandardwayofaddingandremovinglistenersforaneventonthetarget.EveryelementnodeintheDOMisanEventTarget,andassuch,youcandynamicallyaddandremoveeventlistenersforagivenelement.
ThestandardalsodescribesanEventobjectthatprovidesinformationabouttheelementthathasgeneratedaneventandenablesyoutoretrieveitinscript.Itprovidesasetofguidelinesforastandardwayofdeterminingwhatgeneratedanevent,whattypeofeventitwas,andwhenandwheretheeventoccurred.Ifyouwanttomakeitavailableinscript,itmustbepassedasaparametertothefunctionconnectedtotheeventhandler.
NOTEOlderversionsofInternetExplorer(8andbelow)donotimplementtheDOMeventmodel.Thecodeinthissectiononlyworkswithmodernbrowsers:IE9+,Chrome,Firefox,Opera,andSafari.
ConnectingCodetoEvents—TheStandardWayTheEventTargetobjectdefinestwomethodsforaddingandremovingeventlisteners(rememberthatanEventTargetisanelement).Thefirstmethod,addEventListener(),registersaneventlisteneronthetargetonwhichit’scalled.Youcallitonatarget/elementobject,asyouseeinthefollowingexample.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10,Example5</title>
</head>
<body>
<aid="someLink"href="somepage.html">
ClickMe
</a>
<script>
varlink=document.getElementById("someLink");
link.addEventListener("click",function(e){
alert("Thislinkisgoingnowhere");
e.preventDefault();
});
</script>
</body>
</html>
Savethisasch10_example5.html.Thisisare-creationofch10_example3.html,butitusesthestandardeventmodelapplicationprogramminginterface(API),whichisasetofobjects,properties,andmethods,toregisteraneventlistenerandpreventthedefaultactionofalinkfromoccurring.
ThefirstlineofJavaScriptretrievestheelementthathasanidofsomeLink,andstoresitinthelinkvariable.YouthencalltheaddEventListener()methodandpassittwoarguments.Thefirstisthenameoftheeventwithoutthe"on"prefix.Inthisexample,aneventlistenerisregisteredfortheclickevent.
Thesecondargumentisthefunctionthatexecuteswhentheeventoccurs.Thepreviouscodeusesananonymousfunction,acommonpatternthatyou’llseeveryoften,butit’smoreusefultopassadeclaredfunction,likethis:
functionlinkClick(){
alert("Thislinkisgoingnowhere");
e.preventDefault();
}
link.addEventListener("click",linkClick);
Usingadeclaredfunctionletsyoureuseitformultipleeventlisteners,asyouseeinthenextexercise.Butfirst,noticethatlinkClick()nolongerreturnsfalse;instead,itcallsthepreventDefault()methodontheEventobject.Thisisthestandardwaythatyoupreventthedefaultactionfromoccurring.
TRYITOUTDisplayingRandomImageswithStandardEventHandlersInthisTryItOut,yourewritech10_example4.htmltousethestandardDOMeventmodel.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example6</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<imgid="img1"src="mexico.gif"/>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=e.target;
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
document.getElementById("img0").addEventListener("click",
changeImg);
document.getElementById("img1").addEventListener("click",
changeImg);
</script>
</body>
</html>
Savethepageasch10_example6.html.Loadthepageintoyourbrowser,andyouwillseethefamiliarpagefromthepreviousexamples.Clickanimage,andyou’llseeitchangetoarandompicture.
Theonlychangesfromch10_example4.htmlarethefinaltwolinesofJavaScript:
document.getElementById("img0").addEventListener("click",changeImg);
document.getElementById("img1").addEventListener("click",changeImg);
Insteadofusingeachelementobject’sonclickproperty,youregistertheclickeventhandlerusingaddEventListener().
UsingadeclaredfunctionisalsousefulbecauseitenablesyoutounregisteraneventlistenerwiththeremoveEventListener()method:
elementObj.removeEventListener("click",elementObjClick);
Whenyouremoveaneventlistener,youmustprovidethesameexactinformationthatyoucalledaddEventListener()with;thisincludesnotonlythesamenameoftheevent,butthesamefunctionobjectthatyoupassedtoaddEventListener().
ThebeautyofthestandardDOMeventmodelisthatyoucanregistermultipleeventlistenersforasingleeventonasingleelement.Thisisextremelyusefulwhenyouneedtolistenforthesameeventonanelementwithdifferentandunrelatedfunctions.Todothis,
simplycalladdEventListener()asmanytimesasyouneedto,likethis:
elementObj.addEventListener("click",handlerOne);
elementObj.addEventListener("click",handlerTwo);
elementObj.addEventListener("click",handlerThree);
ThiscoderegistersthreelistenersfortheclickeventontheelementreferencedbyelementObj.Asyoumaysuspect,theselistenersexecuteintheorderinwhichtheywereregistered.So,whenyouclickelementObj,handlerOne()executesfirst,handlerTwo()executessecond,andhandlerThree()executesthird.
TRYITOUTAddingandRemovingMultipleEventListenersInthisTryItOut,youpracticeregisteringmultipleeventlistenersforasingleelement,andyouremovethoselistenerswhenaconditionismet.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example7</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<divid="status"></div>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=e.target;
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
functionupdateStatus(e){
varel=e.target;
varstatus=document.getElementById("status");
status.innerHTML="Theimagechangedto"+el.src;
if(el.src.indexOf("mexico")>-1){
el.removeEventListener("click",changeImg);
el.removeEventListener("click",updateStatus);
}
}
varimgObj=document.getElementById("img0");
imgObj.addEventListener("click",changeImg);
imgObj.addEventListener("click",updateStatus);
</script>
</body>
</html>
Savethepageasch10_example7.html.Loadthepageintoyourbrowser,andyouwillseeapagewithasingleimage.Clicktheimage,anditwillchangetoarandompicture.You’llalsoseethetextofthe<div/>elementchangetocontaintheURLofthenewpicture,asshowninFigure10.2.
Figure10.2
Thiscodeisreminiscentofthepastfewexamples;so,let’sjustfocusonwhat’sdifferent.First,theHTML:
<imgid="img0"src="usa.gif"/>
<divid="status"></div>
Insteadoftwoimageelements,thisHTMLdefinesasingle<img/>elementwithanidofimg0anda<div/>elementwhoseidisstatus.Thecontentsofthe<div/>elementwillchangewhentheuserclickstheimage.
There’sanewfunctioncalledupdateStatus(),anditspurposeistoupdatethetextinside<divid="status"/>.Thefirsttwolinesofthisfunctionacquirereferencesto
theeventtarget(theimage)and<div/>element:
functionupdateStatus(e){
varel=e.target;
varstatus=document.getElementById("status");
Thenextlineofcodechangesthetextofthestatuselement:
status.innerHTML="Theimagechangedto"+el.src;
ElementobjectshaveaninnerHTMLpropertythatletsyousetthecontentsoftheelementtowhatevervalueyouassigntoit.Inthiscode,youchangethe<div/>element’scontentstocontaintheURLofthepicturecurrentlydisplayedinthebrowser.
Toaddsomevariety,thenextfewlinesofcoderemovetheimage’sclickeventlistenersiftheMexicoflagisdisplayedinthebrowser:
if(el.src.indexOf("mexico")>-1){
el.removeEventListener("click",changeImg);
el.removeEventListener("click",updateStatus);
}
}
TheifstatementusestheindexOf()methodontheimage’ssrctodetermineiftheMexicoflagiscurrentlydisplayed.Ifso,youremovetheimage’stwoeventlistenersusingtheremoveEventListener()method.Wehaveyettodiscussthecodeforregisteringtheseclickeventlisteners,butyoupassthesameinformationtoremoveEventListener()thatyoupasstoaddEventListener().Ifyoudon’t,youwon’tremovetheeventlisteners.
Thefinallinesofcodesetuptheeventlisteners:
varimgObj=document.getElementById("img0");
imgObj.addEventListener("click",changeImg);
imgObj.addEventListener("click",updateStatus);
Thefirstlineretrievesthe<imgid="img0"/>element,andyouregistertheclickeventhandlersbycallingaddEventListener()andpassingclickfortheeventandthetwofunctions,changeImg()andupdateStatus(),respectively.
It’simportanttorememberthatwhenyouregistermultipleeventhandlersonasingleelement,thelisteningfunctionsexecuteintheorderinwhichyouregisteredthem.Inthisexample,youregisteredalistenerwithchangeImg()beforealistenerwithupdateStatus().ThisisidealbecauseyouwantthestatustodisplaytheURLoftheimageafteryouchangeit.IfyouhadregisteredupdateStatus()beforechangeImg(),thestatuswouldupdatebeforetheimage,thusdisplayingincorrectinformation.
UsingEventDataThestandardoutlinesseveralpropertiesoftheEventobjectthatofferinformationabout
thatevent:whatelementithappenedat,whattypeofeventtookplace,andwhattimeitoccurred.TheseareallpiecesofdataofferedbytheEventobject.Thefollowingtableliststhepropertiesoutlinedinthespecification.
PROPERTIESOFTHEEVENTOBJECT
DESCRIPTION
bubbles Indicateswhetheraneventcanbubble—passingcontrolfromoneelementtoanotherstartingfromtheeventtargetandbubblingupthehierarchy
cancelable IndicateswhetheraneventcanhaveitsdefaultactioncanceledcurrentTarget Identifiesthecurrenttargetfortheeventastheeventtraversesthe
DOMdefaultPrevented IndicateswhetherornotpreventDefault()hasbeencalledonthe
eventeventPhase Indicateswhichphaseoftheeventflowaneventisintarget Indicateswhichelementcausedtheevent;intheDOMevent
model,textnodesareapossibletargetofaneventtimestamp Indicatesatwhattimetheeventoccurredtype Indicatesthenameoftheevent
Secondly,theDOMeventmodelintroducesaMouseEventobject,whichdealswitheventsgeneratedspecificallybythemouse.Thisisusefulbecauseyoumightneedmorespecificinformationabouttheevent,suchasthepositioninpixelsofthecursor,ortheelementthemousehascomefrom.ThefollowingtablelistssomeoftheMouseEventobject’sproperties:
PROPERTIESOFTHEMOUSEEVENTOBJECT
DESCRIPTION
altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated
button IndicateswhichbuttononthemousewaspressedclientX Indicateswhereinthebrowserwindow,inhorizontalcoordinates,the
mousepointerwaswhentheeventwasgeneratedclientY Indicateswhereinthebrowserwindow,inverticalcoordinates,the
mousepointerwaswhentheeventwasgeneratedctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwas
generatedmetaKey Indicateswhetherthemetakeywaspressedwhentheeventwas
generatedrelatedTarget Usedtoidentifyasecondaryeventtarget.Formouseoverevents,this
propertyreferencestheelementatwhichthemousepointerexited.Formouseoutevents,thispropertyreferencestheelementatwhichthemousepointerentered
screenX IndicatesthehorizontalcoordinatesrelativetotheorigininthescreenscreenY IndicatestheverticalcoordinatesrelativetotheorigininthescreenshiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwas
generated
AlthoughanyeventmightcreateanEventobject,onlyaselectsetofeventscangenerateaMouseEventobject.OntheoccurrenceofaMouseEventevent,you’dbeabletoaccesspropertiesfromtheEventobjectandtheMouseEventobject.Withanon-mouseevent,noneoftheMouseEventobjectpropertiesintheprecedingtablewouldbeavailable.ThefollowingmouseeventscancreateaMouseEventobject:
clickoccurswhenamousebuttonisclicked(pressedandreleased)withthepointeroveranelementortext.
mousedownoccurswhenamousebuttonispressedwiththepointeroveranelementortext.
mouseupoccurswhenamousebuttonisreleasedwiththepointeroveranelementortext.
mouseoveroccurswhenamousebuttonismovedontoanelementortext.
mousemoveoccurswhenamousebuttonismovedanditisalreadyontopofanelementortext.
mouseoutoccurswhenamousebuttonismovedoutandawayfromanelementortext.
UnlikeMouseEvent,thecurrentDOMspecificationdoesnotdefineaKeyboardEventobjectforkeyboard-relatedevents(althoughonewillbedefinedinthenextversion,DOMlevel3).Youcan,however,stillaccessinformationaboutkeyboard-relatedeventswiththepropertieslistedinthefollowingtable.
PROPERTIESOFTHEKEYBOARDEVENTOBJECT
DESCRIPTION
altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated
charCode Usedforthekeypressevent.TheUnicodereferencenumberofthekey
ctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwasgenerated
keyCode Asystem-andbrowser-dependentnumericalcodeidentifyingthepressedkey
metaKey Indicateswhetherthemetakeywaspressedwhentheeventwasgenerated
shiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwasgenerated
TRYITOUTUsingtheDOMEventModelInthisTryItOut,youtakeaquicklookatanexamplethatusessomepropertiesoftheMouseEventobject.
Openatexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example8</title>
<style>
.underline{
color:red;
text-decoration:underline;
}
</style>
</head>
<body>
<p>Thisisparagraph1.</p>
<p>Thisisparagraph2.</p>
<p>Thisisparagraph3.</p>
<script>
functionhandleEvent(e){
vartarget=e.target;
vartype=e.type;
if(target.tagName=="P"){
if(type=="mouseover"){
target.className="underline";
}elseif(type=="mouseout"){
target.className="";
}
}
if(type=="click"){
alert("YouclickedthemousebuttonattheX:"
+e.clientX+"andY:"+e.clientY+"
coordinates");
}
}
document.addEventListener("mouseover",handleEvent);
document.addEventListener("mouseout",handleEvent);
document.addEventListener("click",handleEvent);
</script>
</body>
</html>
Savethisasch10_example8.htmlandrunitinyourbrowser.Whenyoumoveyourmouseoveroneoftheparagraphs,you’llnoticeitstextchangescolortoredanditbecomesunderlined.Clickanywhereinthepage,andyou’llseeanalertboxlikeFigure10.3.
Figure10.3
NowclickOK,movethepointerinthebrowserwindow,andclickagain.Adifferentresultappears.
Thisexampleisconsistentwiththeevent-handlingbehavior:Thebrowserwaitsforanevent,andeverytimethateventoccursitcallsthecorrespondingfunction.Itwillcontinuetowaitfortheeventuntilyouexitthebrowserorthatparticularwebpage.Inthisexample,youassigneventhandlersforthemouseover,mouseout,andclick
eventsonthedocumentobject:
document.addEventListener("mouseover",handleEvent);
document.addEventListener("mouseout",handleEvent);
document.addEventListener("click",handleEvent);
Onefunction,handleEvent(),handlesallthreeoftheseevents.
Wheneveranyoftheseeventsfire,thehandleClick()functionisraisedandanewMouseEventobjectisgenerated.RememberthatMouseEventobjectsgiveyouaccesstoEventobjectpropertiesaswellasMouseEventobjectproperties,andyouusesomeoftheminthisexample.
ThefunctionacceptstheMouseEventobjectandassignsitthereferencee:
functionhandleEvent(e){
vartarget=e.target;
vartype=e.type;
if(target.tagName=="P"){
Insidethefunction,thefirstthingyoudoisinitializethetargetandtypevariableswiththetargetandtypeeventproperties,respectively.Theseareconveniencevariablestomakeaccessingthatinformationeasier.Youthencheckiftheeventtarget(theelementthatcausedtheevent)hasatagNameofP.Ifthetargetisaparagraphelement,thenextbitofinformationyouneedtofindiswhatkindofeventtookplacebyusingthetypevariable:
if(type=="mouseover"){
target.className="underline";
}elseif(type=="mouseout"){
target.className="";
}
}
Iftheeventisamouseover,theparagraph’sCSSclassisassignedtheunderlineclassdefinedinthepage’sstylesheet.Iftheeventtypeismouseout,theelement’sclassNamepropertyiscleared,whichreturnsthetexttoitsoriginalstyle.Thisstyle-changingcoderunsonlyiftheelementthatcausedtheeventisaparagraphelement.
Next,thefunctiondeterminesiftheuserclickedhismousebyagaincheckingthetypevariable:
if(type=="click"){
alert("YouclickedthemousebuttonattheX:"
+e.clientX+"andY:"+e.clientY+"coordinates");
}
Iftheuserdidindeedclicksomewhereinthepage,youusethealert()methodtodisplaythecontentsoftheclientXandclientYpropertiesoftheMouseEventobjectonthescreen.
TheMouseEventobjectsuppliedtothisfunctionisoverwrittenandre-createdeverytimeyougenerateanevent,sothenexttimeyouclickthemouseormovethepointer,
itcreatesanewMouseEventobjectcontainingthecoordinatesforthexandypositionsandtheinformationontheelementthatcausedtheeventtofire.
Let’slookatanotherexample.
TRYITOUTACrudeTabStripInthisTryItOut,youwillwriteafunctional,yetflawed,tabstripusingthemouseover,mouseout,andclickevents.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example9</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<script>
functionhandleEvent(e){
vartarget=e.target;
switch(e.type){
case"mouseover":
if(target.className=="tabStrip-tab"){
target.className="tabStrip-tab-hover";
}
break;
case"mouseout":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab";
}
break;
case"click":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab-click";
varnum=target.getAttribute("data-tab-
number");
showDescription(num);
}
break;
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
descContainer.innerHTML=text;
}
document.addEventListener("mouseover",handleEvent);
document.addEventListener("mouseout",handleEvent);
document.addEventListener("click",handleEvent);
</script>
</body>
</html>
Savethisfileasch10_example9.html.Openitinyourbrowser,andwhenyoumoveyourmousepointeroveratab,itsstylechangestoabluebackgroundwithadarkerblueborder.Whenyouclickatab,itsstylechangesyetagaintomakethetab’sbackgroundcoloralightorangewithadarkerorangebordercolor.Also,whenyouclickatab,textisaddedtothepage.Forexample,clickingtab3resultsinthetext“DescriptionforTab3”beingaddedtothepage.
TakealookattheHTMLinthebody,anditsstyle,first:
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
Thefirst<div/>elementhasaCSSclassoftabStrip.Thethree<div/>elementscontainedwithinitrepresentthreetabs.Eachtab<div/>elementhasanumericvalueassignedtoitsdata-tab-numberattribute,andaCSSclassoftabStrip-tab.
Thetabstrip<div/>elementhasasibling<div/>elementwithanidvalueofdescContainer.Itdoesn’tcontainanychildren,anditdoesn’thaveaCSSclassassociatedwithit.
Inthisexample,thetabstripisvisuallysetapartfromtherestofthepagebygivingitagraybackground:
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
It’sgivenanactualheightof28pixels(height+toppadding+bottompadding).Thisheightandpaddingverticallycentersthetab<div/>elementswithinthetabstrip.
ThetabshaveseveralCSSrulestodefinethewaytheyarerenderedinthebrowserbecausetheyhavethreestates:normal,hover,andclick.Despitethesethreestates,theyarestilltabsandthussharesomevisualcharacteristics.Thefirstruledictatesthesesharedproperties:
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
Theselectortellsthebrowsertoapplythesepropertiestoall<div/>elementsinsidethetabstrip.Theelementsaresettofloatlefttogivethemaninlineappearance(<div/>elementsareblockelements,andappearonanewlinebydefault).
Thenextrule,thetabStrip-tabclass,definesthenormalstate:
.tabStrip-tab{
padding:3px;
}
Allthisruleaddsisapaddingofthreepixelsonallsidesoftheelement.Nextisthehoverstate,asdefinedbythetabStrip-tab-hoverclass:
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
Thisrulereducesthepaddingtotwopixels,addsaone-pixel-wideborder,andchangesthebackgroundcolortoashadeofblue.Borders,likepadding,addtothe
actualdimensionsofanelement;reducingthepaddingwhileaddingaborderkeepstheelementinahoverstate,thesameheightandwidthasitwasinthenormalstate.
ThefinalruledeclaresthetabStrip-tab-clickclass:
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
Thisclassissimilartothehoverclass;theonlydifferenceisthedarkorangebordercolorandlightorangebackgroundcolor.
Nowlet’slookattheJavaScriptcodethatperformsthemagic.ThecodeconsistsofthehandleEvent()function,whichisregisteredasthedocumentobject’smouseover,mouseout,andclickeventlisteners:
document.addEventListener("mouseover",handleEvent);
document.addEventListener("mouseout",handleEvent);
document.addEventListener("click",handleEvent);
Thefunctionbeginsbydeclaringavariablecalledtarget,whichisinitializedwiththeeventobject’stargetproperty:
functionhandleEvent(e){
vartarget=e.target;
NowyouneedtodeterminewhattypeofeventtookplaceandmaketheappropriatechangestotheDOM.Aswitchstatementworkswellhere,andyouusetheeventobject’stypepropertyastheswitchexpression:
switch(e.type){
case"mouseover":
if(target.className=="tabStrip-tab"){
target.className="tabStrip-tab-hover";
}
break;
First,checkforthemouseoverevent.IftheelementthatcausedtheeventhasaclassnameoftabStrip-tab,atabinitsnormalstate,changetheelement’sclassNamepropertytotabStrip-tab-hover.Indoingso,thetabisnowinthehoverstate.
Ifamouseouteventoccurred,youalsoneedtomakechangestotheDOM:
case"mouseout":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab";
}
break;
Thiscodechangesthetab’sclassNamepropertytotabStrip-tab(thenormalstate)onlywhenthetabinwhichthemousepointerexitedisinthehoverstate.
Thelasteventyouneedtolookforistheclickevent,socheckforitnowwiththe
followingcode:
case"click":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab-click";
Thiscodechangesthetabelement’sclassNametotabStrip-tab-click,thusputtingitintotheclickstate.
Next,youneedtoaddthetab’sdescriptiontothepage,andyoustartthisprocessbygettingthetab’snumberfromthe<div/>element’sdata-tab-numberattribute.YouusethegetAttribute()methodtoretrievethisvalue:
varnum=target.getAttribute("data-tab-number");
showDescription(num);
}
break;
}
}
Nowthatyouhavethetab’snumber,youpassittotheshowDescription()function:
functionshowDescription(num){
vardescContainer=document.getElementById("descContainer");
Thetabs’descriptionsareaddedtothe<div/>elementwithanidofdescContainer,soasthiscodeshows,youfirstretrievethatelementusingthegetElementById()method.
Thedescriptionsaredynamicallycreatedbythisfunction,sonowyouneedtobuildthedescriptiontextanddisplaythattextinthedescContainerelement.First,createastringcontainingthedescriptionforthetab.Inthisexample,thedescriptionissimpleandincludesthetab’snumber:
vartext="DescriptionforTab"+num;
ThenaddthetexttothedescriptionelementbyusingitsinnerHTMLproperty:
descContainer.innerHTML=text;
}
Oneproblemthathasplaguedthewebisthelackofcompatibilitybetweenthemajorbrowsers.Today’smodernbrowsersdoaverygoodjobofimplementingthestandardDOM,butolderbrowsers,specificallyIE8andbelow,onlypartiallysupporttheDOMstandard.DespitethelackofsupportfortheDOMstandardintheseoldbrowsers,youcanstillacquirethesameusefulinformationonagiveneventwithold-IE’seventmodel.
EVENTHANDLINGINOLDVERSIONSOFINTERNETEXPLOREROld-IE’seventmodelincorporatestheuseofaglobaleventobject(itisapropertyofthewindowobject),andonesuchobjectexistsforeachopenbrowserwindow.Thebrowserupdatestheeventobjecteverytimetheusercausesaneventtooccur,anditprovidesinformationsimilartothatofthestandardDOMEventobject.
NOTETobeclear,theinformationinthissectionappliestoIE8andbelow.Wewillrefertotheseoldbrowsersas“old-IE.”IE9andlaterimplementthestandardDOMeventmodel.Thankfully,old-IE’susagecontinuestodwindlewitheachpassingyear.
AccessingtheeventObjectBecausetheeventobjectisapropertyofwindow,itisverysimpletoaccess:
<pondblclick="handle()">Paragraph</p>
<script>
functionhandle(){
alert(event.type);
}
</script>
Thiscodeassignsthehandle()functiontohandlethe<p/>element’sdblclickevent.Whenthefunctionexecutes,itgetsthetypeofeventthatcausedthehandle()function’sexecution.Becausetheeventobjectisglobal,thereisnoneedtopasstheobjecttothehandlingfunctionliketheDOMeventmodel.Alsonotethatlikeotherpropertiesofthewindowobject,it’snotrequiredthatyouprecedetheeventobjectwithwindow.
NOTEEventhoughyoudon’thavetopasseventtoaneventhandler,youstillwanttodosoinordertosupportbothold-IEandmodernbrowsers.
ThesameholdstruewhenyouassigneventhandlersthroughJavaScriptusingobjectproperties:
<pid="p">Paragraph</p>
<h1id="h1">Heading1</h1>
<spanid="span">SpecialText</span>
<script>
functionhandle(){
if(event.type=="mouseover"){
alert("YoumovedovertheSpecialText");
}
}
document.getElementById("p").ondblclick=handle;
document.getElementById("h1").onclick=handle;
document.getElementById("span").onmouseover=handle;
</script>
Old-IEdoesnotsupportaddEventListener()andremoveEventListener(),butitdoesimplementtwosimilarmethods:attachEvent()anddetachEvent().RewriteExample5usingold-IE’seventAPI:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10,Example10</title>
</head>
<body>
<aid="someLink"href="somepage.html">
ClickMe
</a>
<script>
varlink=document.getElementById("someLink");
functionlinkClick(e){
alert("Thislinkisgoingnowhere");
e.returnValue=false;
}
link.attachEvent("onclick",linkClick);
</script>
</body>
</html>
Savethisasch10_example10.html.
Let’sfirstlookatthecalltoattachEvent().TheoverallpatternisthesameasaddEventListener()(andthusremoveEventListener());youpasstheeventyouwanttolistenforandthefunctiontoexecutewhentheeventoccurs.Butasyou’llnoticefromthiscode,theeventnamesareprefixedwith“on”.
Thesecondargumentisthefunctionthatexecuteswhentheeventoccurs.Notice,though,thatthelinkClick()functiondefinesaparametercallede.WhenyouregisteraneventhandlerwithattachEvent(),old-IEpassestheeventobjecttothehandlingfunction.
AlsonoticethatlinkClick()doesnotreturnfalseorcallpreventDefault().Instead,old-IE’seventobjecthasapropertycalledreturnValue,andsettingittofalseachievesthesameresult.
UsingEventDataUnsurprisingly,IE’seventobjectprovidessomedifferentpropertiesfromtheDOMstandard’sEventandMouseEventobjects,althoughtheytypicallyprovideyouwithsimilardata.
ThefollowingtablelistssomeofthepropertiesofIE’seventobject.
PROPERTIESOFTHEEVENTOBJECT
DESCRIPTION
altKey IndicateswhethertheAltkeywaspressedwhentheeventwasgenerated
button IndicateswhichbuttononthemousewaspressedcancelBubble Getsorsetswhetherthecurrenteventshouldbubbleupthehierarchy
ofeventhandlersclientX Indicateswhereinthebrowserwindow,inhorizontalcoordinates,the
mousepointerwaswhentheeventwasgeneratedclientY Indicateswhereinthebrowserwindow,inverticalcoordinates,the
mousepointerwaswhentheeventwasgeneratedctrlKey IndicateswhethertheCtrlkeywaspressedwhentheeventwas
generatedfromElement GetstheelementobjectthemousepointerisexitingkeyCode GetstheUnicodekeycodeassociatedwiththekeythatcausedthe
eventreturnValue GetsorsetsthereturnvaluefromtheeventscreenX Indicateswhereinthebrowserwindow,inhorizontalcoordinates
relativetotheorigininthescreencoordinates,themousepointerwaswhentheeventwasgenerated
screenY Indicateswhereinthebrowserwindow,inverticalcoordinatesrelativetotheorigininthescreencoordinates,themousepointerwaswhentheeventwasgenerated
shiftKey IndicateswhethertheShiftkeywaspressedwhentheeventwasgenerated
srcElement GetstheelementobjectthatcausedtheeventtoElement Getstheelementobjectthatthemousepointerisenteringtype Retrievestheevent’sname
Let’srevisitsomepreviousexamplesandmakethemworkexclusivelyinold-IE.
TRYITOUTAddingandRemovingMultipleEventHandlersinOld-IEInthisTryItOut,yourewritech10_example7.htmltouseold-IE’sattachEvent()anddetachEvent()methods.Typeinthefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example11</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<divid="status"></div>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=e.srcElement;
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
functionupdateStatus(e){
varel=e.srcElement;
varstatus=document.getElementById("status");
status.innerHTML="Theimagechangedto"+el.src;
if(el.src.indexOf("mexico")>-1){
el.detachEvent("onclick",changeImg);
el.detachEvent("onclick",updateStatus);
}
}
varimgObj=document.getElementById("img0");
imgObj.attachEvent("onclick",updateStatus);
imgObj.attachEvent("onclick",changeImg);
</script>
</body>
</html>
Savethepageasch10_example11.html.Loadthepageintoyourbrowser,andyouwillseeitbehavelikech10_example7.html.Clickingtheimageresultsinitchangingtoarandompicture,andthetextofthe<div/>elementchangestocontaintheURLofthenewpicture.
Let’sjumprighttothecode,whichismostlythesameasch10_example7.html.Thefirstbigdifferenceishowyouregistertheeventhandlersfortheimageobject.Instead
ofusingaddEventListener(),youuseold-IE’sattachEvent()method:
imgObj.attachEvent("onclick",updateStatus);
imgObj.attachEvent("onclick",changeImg);
Butthere’sanotherbigdifferencehere.UnlikethestandardaddEventListener(),thehandlersregisteredwithattachEvent()executeinreverseorder.So,youregisterthehandlerwiththeupdateStatus()functionbeforeregisteringwithchangeImg().
ThenextchangeisinthefirststatementofthechangeImg()function.Youwanttoretrievetheelementthatreceivedtheevent,andold-IE’seventobjectgivesyouthatinformationwiththesrcElementproperty:
functionchangeImg(e){
varel=e.srcElement;
Therestofthefunctionisleftunchanged.
YouwanttodothesamethingintheupdateStatus()function,soyouchangethefirststatementtouseold-IE’ssrcElementpropertyaswell:
functionupdateStatus(e){
varel=e.srcElement;
AfteryouretrievethestatuselementandsetitsinnerHTML,youthenwanttoremovetheeventhandlersiftheMexicoflagisdisplayed.YoudothiswiththedetachEvent()method:
if(el.src.indexOf("mexico")>-1){
el.detachEvent("onclick",changeImg);
el.detachEvent("onclick",updateStatus);
}
Here,theorderinwhichyoucalldetachEvent()doesn’tmatter.Itwillsimplyremovetheeventhandlerfromtheelement.
Next,yourewriteExample8touseold-IE’seventmodel.
TRYITOUTUsingtheIEEventModelInthisTryItOut,youusetheold-IE’seventmodel.Openyourtexteditorandtypethefollowing.Feelfreetocopyandpastetheelementswithinthebodyandthestylesheetfromch10_example8.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example12</title>
<style>
.underline{
color:red;
text-decoration:underline;
}
</style>
</head>
<body>
<p>Thisisparagraph1.</p>
<p>Thisisparagraph2.</p>
<p>Thisisparagraph3.</p>
<script>
functionhandleEvent(e){
vartarget=e.srcElement;
vartype=e.type;
if(target.tagName=="P"){
if(type=="mouseover"){
target.className="underline";
}elseif(type=="mouseout"){
target.className="";
}
}
if(type=="click"){
alert("YouclickedthemousebuttonattheX:"
+e.clientX+"andY:"+e.clientY+"
coordinates");
}
}
document.attachEvent("onmouseover",handleEvent);
document.attachEvent("onmouseout",handleEvent);
document.attachEvent("onclick",handleEvent);
</script>
</body>
</html>
Savethisasch10_example12.html,andloaditintoold-IE.It’lllookandbehaveexactlylikeExample8;theparagraphtextwillchangetoredandhaveanunderlineasyoumoveyourmousepointerovertheparagraphs.Whenyourmousepointerleavesaparagraph,thetextreturnstotheoriginalstate.Whenyouclickyourmouse,analertboxtellsyouthecoordinatesofwhereyourmousepointerwaswhenyouclicked.
YouassignthehandleEvent()functiontohandlethemouseover,mouseout,andclickeventsonthedocumentobject:
document.attachEvent("onmouseover",handleEvent);
document.attachEvent("onmouseout",handleEvent);
document.attachEvent("onclick",handleEvent);
Whenyoucauseanyoftheseeventstofire,thebrowserupdatestheeventobjectandcallsthehandleEvent()function:
functionhandleEvent(e){
vartarget=e.srcElement;
vartype=e.type;
First,youwanttogetthetargetoftheevent(orinold-IEspeak,thesourceelement),soinitializethetargetvariablewiththeeventobject’ssrcElementpropertyandthetypevariablewiththeeventobject’stypeproperty.
Next,youcheckiftheeventtargethasatagNameofP.Ifso,youdeterminewhatkindofeventtookplacebyusingthetypevariable:
if(target.tagName=="P"){
if(type=="mouseover"){
target.className="underline";
}elseif(type=="mouseout"){
target.className="";
}
}
Formouseoverevents,youchangetheparagraph’sCSSclasstounderline.Iftheeventtypeismouseout,theelement’sclassNamepropertyissettoanemptystring—returningthetexttoitsoriginalstyle.
Beforemovingon,noticethenameoftheseevents:mouseoverandmouseout.LikethestandardDOM,old-IE’stypepropertyreturnsthenameoftheeventwithoutthe"on"prefix.Soeventhoughyouregistertheeventhandlerswithonmouseover,onmouseout,andonclick,thetypepropertywillreturnmouseover,mouseout,andclick,respectively.
Thenextbitofcodedisplaysthemousepointer’slocationifthemousebuttonwasclicked:
if(type=="click"){
alert("YouclickedthemousebuttonattheX:"
+e.clientX+"andY:"+e.clientY+"coordinates");
}
}
IfyoucompareExample8withExample12,youwillnoticethetwoprimarydifferencesarehowtheeventhandlersareregistered,andhowtoretrievetheelementthatcausedtheeventtooccur.MosteverythingelseissharedbetweenthestandardDOMeventmodelandIE’seventmodel.
Nowlet’slookatExample9throughtheprismofold-IE.
TRYITOUTACrudeTabStripforOld-IEInthisTryItOut,youwillrewritech10_example9.htmltouseold-IE’seventmodel.Openyourtexteditorandtypethefollowing,oryoucancopych10_example9.htmlandchangethehighlightedlinesofcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example13</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<script>
functionhandleEvent(e){
vartarget=e.srcElement;
switch(e.type){
case"mouseover":
if(target.className=="tabStrip-tab"){
target.className="tabStrip-tab-hover";
}
break;
case"mouseout":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab";
}
break;
case"click":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab-click";
varnum=target.getAttribute("data-tab-
number");
showDescription(num);
}
break;
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
descContainer.innerHTML=text;
}
document.attachEvent("onmouseover",handleEvent);
document.attachEvent("onmouseout",handleEvent);
document.attachEvent("onclick",handleEvent);
</script>
</body>
</html>
Savethisfileasch10_example13.html.Openitinyourbrowser,andyou’llseeitworkexactlylikech10_example9.html.Whenyoumoveyourmousepointeroveratab,itsstylechangestoabluebackgroundwithadarkerblueborder.Whenyouclickatab,itsstylechangesyetagainandaddsthetab’sdescriptiontothepage.
Fourthingsaredifferentinthisversionofthetabscript.Thefirstthreearehowyouregistertheeventhandlers:
document.attachEvent("onmouseover",handleEvent);
document.attachEvent("onmouseout",handleEvent);
document.attachEvent("onclick",handleEvent);
InsteadofusingaddEventListener(),youuseold-IE’sattachEvent()methodtoregistertheeventhandlers.
ThenextandlastmodificationisthefirststatementofhandleEvent():
functionhandleEvent(e){
vartarget=e.srcElement;
Asinthepreviousexamples,youusetheeventobject’ssrcElementpropertytoretrievetheeventtarget.Therestofthefunctionremainsunchanged.
Inthenextsection,youlearnhowtohandlethefundamentaldifferencesbetweenbotheventmodelsandtowritecross-browserDHTMLcode.
WRITINGCROSS-BROWSERCODEBynowyou’vewrittentwoversionsofmultipleexamples:oneforstandards-compliantbrowsersandoneforold-IE.Intherealworld,creatingseparateversionsofwebsitesisrarelyconsideredbestpractice,andit’smuch,mucheasiertowriteacross-browserversionofthewebpage.Inthissection,youusetheknowledgeyou’vegainedoftheDOM,thestandardDOMeventmodel,andold-IE’seventmodeltowritecross-browsercode.
Thetricktocross-browserJavaScriptistocreateaunifiedAPIthathidesthecomplexityofworkingwithdifferentbrowserimplementations.Forexample,toregisteraneweventlistener,youneedtodothreethings:
CheckifthebrowsersupportsthestandardDOMeventmodel.
Ifso,useaddEventListener()
Ifnot,useattachEvent()
Usingthetechniqueoffeaturedetection,whichyoulearnedaboutinChapter8,youcaneasilydetermineifthebrowsersupportsaddEventListener().Simplychecktoseeifitexists,likethis:
if(typeofaddEventListener!="undefined"){
//useaddEventListener()
}else{
//useattachEvent()
}
Whenwritingcross-browserJavaScript,youalwayswanttocheckforstandardscompliancefirstbecausesomebrowsersmaysupportbothoptions.Forexample,IE9andIE10supportbothaddEventListener()andattachEvent().IfyoucheckforattachEvent()insteadofaddEventListener(),likethis:
//wrong!Donotdo!
if(typeofattachEvent!="undefined"){
//useattachEvent
}else{
//useaddEventListener
}
IE9andIE10willuseattachEvent()insteadofaddEventListener().WeknowthatattachEvent()exhibitsdifferentbehaviorthanaddEventListener(),andassuch,wewanttoavoidthatbehaviorasmuchaspossible.Plus,wealwayswanttousestandards-compliantcodebecauseitisguaranteedtoworkineverystandards-compliantbrowser.
ThepreviousexampleusesthetypeofoperatortodetermineiftheaddEventListener()methodisnotundefined,butyoucansimplifythecodebyusingaddEventListenerasatruthyorfalsyvalue,likethis:
if(addEventListener){
//useaddEventListener()
}else{
//useattachEvent()
}
Whetheryouusethetypeofoperatorortruthy/falsyvalues,eitherapproachwillgiveyouthesameresults.Justkeepinmindthatyouwanttobeconsistentasyouwriteyourcode.Ifyouusetypeof,useitforallofyourfeature-detectioncode.
Sowiththisinmind,youcanwriteafunctionlikethis:
functionaddListener(obj,type,fn){
if(obj.addEventListener){
obj.addEventListener(type,fn)
}else{
obj.attachEvent("on"+type,fn);
}
}
Let’sbreakdownthiscode.Here,youdefineafunctioncalledaddListener().Ithasthreeparameters—theobjecttoregistertheeventlisteneron,theeventtype,andthefunctiontoexecutewhentheeventfires:
functionaddListener(obj,type,fn){
ThefirstthingyoudoinsidethisfunctionistocheckifthegivenobjecthasanaddEventListener()method:
if(obj.addEventListener){
obj.addEventListener(type,fn)
}
IfaddEventListener()exists,youcallitandpassthetypeandfnparameterstoit.ButifaddEventListener()doesn’texist,youwanttocallattachEvent():
else{
obj.attachEvent("on"+type,fn);
}
}
Here,youappendontothevaluecontainedwithinthetypevariable.Thisway,youcanpassthestandardnameoftheevent,suchasclick,totheaddListener()function,andit’llworkwithbothstandards-compliantbrowsersandold-IE.
Tousethisfunction,you’dcallitlikethis:
addListener(elementObj,"click",eventHandler);
AssumingelementObjisanelementobjectandeventHandler()isafunction,you’dsuccessfullyregisteraneventlistener/handlerforstandards-compliantbrowsersandold-IE.
FollowingthepatternusedintheaddListener()function,youcanwriteaneventutilityobjectthatmakesiteasiertowritecross-browser,event-drivencode.Aneventutilityobjectshouldprovidethecapabilitytoaddandremovelisteners,aswellasgettheevent
target.
TRYITOUTACross-BrowserEventUtilityInthisTryItOut,youwillwriteautilitytomakeiteasiertowritecross-browsercode.Openyourtexteditorandtypethefollowing:
varevt={
addListener:function(obj,type,fn){
if(obj.addEventListener){
obj.addEventListener(type,fn);
}else{
obj.attachEvent("on"+type,fn);
}
},
removeListener:function(obj,type,fn){
if(obj.removeEventListener){
obj.removeEventListener(type,fn);
}else{
obj.detachEvent("on"+type,fn);
}
},
getTarget:function(e){
if(e.target){
returne.target;
}
returne.srcElement;
},
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue=false;
}
}
};
Saveitasevent-utility.js.
Usingobjectliteralnotation,youcreateanobjectcalledevt.Itspurposeistomakeiteasiertowritecross-browsercode:
varevt={
ThefirstmethodyouwriteistheaddListener()method,anditisexactlythesameastheaddListener()functionyoupreviouslywrote:
addListener:function(obj,type,fn){
if(obj.addEventListener){
obj.addEventListener(type,fn);
}else{
obj.attachEvent("on"+type,fn);
}
},
IfthebrowsersupportsaddEventListener(),itusesthemethodtoregisteraneventlistener.Otherwise,thebrowsercallsattachEvent().
ThenextmethodisremoveListener().Asitsnameimplies,itremovesalistenerthatwasaddedpreviouslytoanobject:
removeListener:function(obj,type,fn){
if(obj.removeEventListener){
obj.removeEventListener(type,fn);
}else{
obj.detachEvent("on"+type,fn);
}
},
ThecodeisalmostidenticaltoaddListener()exceptforafewkeychanges.First,itchecksifthegivenobjecthasaremoveEventListener()method,andifso,itcallsremoveEventListener().Ifnot,itassumesthebrowserisold-IEandcallsdetachEvent().
Thethirdmethod,getTarget(),isresponsibleforgettingtheeventtargetfromtheeventobject:
getTarget:function(e){
if(e.target){
returne.target;
}
returne.srcElement;
}
};
ItfollowsthesamepatternusedinaddListener()andremoveListener();itusesthetargetpropertyasatruthy/falsyvaluetodetermineifthebrowsersupportsthestandardAPI.Iftargetissupported,itisreturned.Otherwise,thefunctionreturnstheelementobjectcontainedwithinsrcElement.
ThefourthandfinalmethodispreventDefault().Thepurposeofthismethodistopreventthedefaultactionoftheeventthattookplace(ifsuchanactionexists).ItfirstchecksforstandardscompliancebydeterminingifthesuppliedeventobjecthasapreventDefault()method.Ifso,itcallsthemethod;otherwise,itsetstheeventobject’sreturnValuetofalse.
Beforemovingon,it’simportanttorealizethatthiseventutilityobjectisbasedonanassumption:Ifthebrowserdoesn’tsupportthestandardeventmodel,itmustbeold-IE.Althoughthisisasafeassumptiontomake,itisnotalways100percentcorrect.Someoldmobilebrowsersdonotsupporteitherthestandardeventmodelorold-IE’seventmodel.However,asWindows,Android,andiOSmobiledevicescontinuetogainmarketshare,theseold,non-compliantmobilebrowsersarevanishingfromthemarket.Inmostcases,it’ssafetoignorethem.
Nowthatyouhaveautilityformakingiteasiertowritecross-browser,event-drivencode,let’srevisitthepreviousexamplesandputittouse.
StartbymodifyingExample10.Here’stherevisedcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10,Example14</title>
</head>
<body>
<aid="someLink"href="somepage.html">
ClickMe
</a>
<scriptsrc="event-utility.js"></script>
<script>
varlink=document.getElementById("someLink");
functionlinkClick(e){
alert("Thislinkisgoingnowhere");
evt.preventDefault(e);
}
evt.addListener(link,"click",linkClick);
</script>
</body>
</html>
Savethisasch10_example14.html.
Thehighlightedlinesofcodearetheonlychanges.First,youincludeevent-utility.js.Thecodeinthisexampleassumesthefileisinthesamedirectoryasch10_example14.html:
<scriptsrc="event-utility.js"></script>
Youthenregistertheeventlistenerusingevt.addListener():
evt.addListener(link,"click",linkClick);
Youpassittheelementobjectyouwanttoregisterthelisteneron,thenameoftheeventyouwanttolistenfor,andthefunctiontoexecutewhentheeventoccurs.
ThefinalchangeisinsidethelinkClick()function.Youwanttopreventthebrowserfromnavigatingtosomepage.html,soyoucallyoureventutility’spreventDefault()methodandpassittheeventobject.Now,whenyouclickthelink,thebrowserwillstayonthesamepage.
TRYITOUTAddingandRemovingMultipleEventHandlersInthisTryItOut,yourewritech10_example11.htmlanduseyoureventutilityobjecttoaddandremoveeventlisteners/handlers.Youcanwriteitfromscratch,oryoucancopyandpastefromch10_example11.html.Thehighlightedlinesindicatewhatchangedinthisexample.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example15</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<divid="status"></div>
<scriptsrc="event-utility.js"></script>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=evt.getTarget(e);
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
functionupdateStatus(e){
varel=evt.getTarget(e);
varstatus=document.getElementById("status");
status.innerHTML="Theimagechangedto"+el.src;
if(el.src.indexOf("mexico")>-1){
evt.removeListener(el,"click",changeImg);
evt.removeListener(el,"click",updateStatus);
}
}
varimgObj=document.getElementById("img0");
evt.addListener(imgObj,"click",changeImg);
evt.addListener(imgObj,"click",updateStatus);
</script>
</body>
</html>
Savethepageasch10_example15.html.Loadthepageintoyourbrowser,andyouwillseeitbehavelikech10_example11.html.Clickingtheimageresultsinitchangingtoarandompicture,andthetextofthe<div/>elementchangestocontaintheURLofthenewpicture.
You’veseenthiscodeafewtimesnow,sothepertinentchangesarehighlighted.First,youwanttoincludeyourevent-utility.jsfile.
Thenextchangeishowyouregistertheeventlistenersfortheimageobject.Usingyoureventutility’saddListener()method,youpassittheimageobject,eventname,andthefunction:
evt.addListener(imgObj,"click",changeImg);
evt.addListener(imgObj,"click",updateStatus);
InthechangeImg()andupdateStatus()functions,youchangetheirfirstlinestoretrievetheeventtargettouseyournewgetTarget()method:
varel=evt.getTarget(e);
TheninsideupdateStatus(),youmodifythecodeinsidetheifstatementtouseyournewremoveListener()method:
if(el.src.indexOf("mexico")>-1){
evt.removeListener(el,"click",changeImg);
evt.removeListener(el,"click",updateStatus);
}
Thereis,however,anissuewiththisnewversion:Inold-IE,theeventlistenersexecuteinreverseorder.Thisisaproblem,butoneyou’llfixattheveryendofthischapter.
Next,yourewriteExample12touseyournewevtobject.
TRYITOUTUsingtheEventModelsofDifferingBrowsersInthisTryItOut,youwillrewritech10_example12.htmlusingyoureventutility.Openyourtexteditorandtypethefollowing.Feelfreetocopyandpastetheelementswithinthebodyandthestylesheetfromch10_example12.html.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example16</title>
<style>
.underline{
color:red;
text-decoration:underline;
}
</style>
</head>
<body>
<p>Thisisparagraph1.</p>
<p>Thisisparagraph2.</p>
<p>Thisisparagraph3.</p>
<scriptsrc="event-utility.js"></script>
<script>
functionhandleEvent(e){
vartarget=evt.getTarget(e);
vartype=e.type;
if(target.tagName=="P"){
if(type=="mouseover"){
target.className="underline";
}elseif(type=="mouseout"){
target.className="";
}
}
if(type=="click"){
alert("YouclickedthemousebuttonattheX:"
+e.clientX+"andY:"+e.clientY+"
coordinates");
}
}
evt.addListener(document,"mouseover",handleEvent);
evt.addListener(document,"mouseout",handleEvent);
evt.addListener(document,"click",handleEvent);
</script>
</body>
</html>
Savethisasch10_example16.html,andloaditintodifferentbrowsers(preferablyastandards-compliantbrowserandold-IE,ifyouhaveaccesstoone).It’lllookandbehaveexactlylikech10_example12.html;theparagraphtextwillchangetoredandhaveanunderlineasyoumoveyourmousepointerovertheparagraphs.Whenyourmousepointerleavesaparagraph,thetextreturnstotheoriginalstate.Whenyouclickyourmouse,analertboxtellsyouthecoordinatesofwhereyourmousepointerwaswhenyouclicked.
Onceagain,themajorityofcodeisleftuntouchedwithonlyfivelinesofcodehavingchanges.First,youwanttoincludetheevent-utility.jsfileusinga<script/>element:
<scriptsrc="event-utility.js"></script>
Next,youregisterthemouseover,mouseout,andclickeventlistenersusingyourevt.addListener()method:
evt.addListener(document,"mouseover",handleEvent);
evt.addListener(document,"mouseout",handleEvent);
evt.addListener(document,"click",handleEvent);
Andfinally,youchangethefirstlineofthehandleEvent()function:
functionhandleEvent(e){
vartarget=evt.getTarget(e);
Insteadofusinganybrowser-specificcode,youuseevt.getTarget()toretrievetheelementobjectthatreceivedtheevent.
Nowlet’slookatch10_example13.htmlandusetheevtobject.
TRYITOUTACrudeTabStripforAllBrowsersInthisTryItOut,youwillrewritech10_example13.htmlusingyourcross-browsereventutility.Openyourtexteditorandtypethefollowing,oryoucancopych10_example13.htmlandchangethehighlightedlinesofcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example17</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="event-utility.js"></script>
<script>
functionhandleEvent(e){
vartarget=evt.getTarget(e);
switch(e.type){
case"mouseover":
if(target.className=="tabStrip-tab"){
target.className="tabStrip-tab-hover";
}
break;
case"mouseout":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab";
}
break;
case"click":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab-click";
varnum=target.getAttribute("data-tab-
number");
showDescription(num);
}
break;
}
}
functionshowDescription(num){
vardescContainer=
document.getElementById("descContainer");
vartext="DescriptionforTab"+num;
descContainer.innerHTML=text;
}
evt.addListener(document,"mouseover",handleEvent);
evt.addListener(document,"mouseout",handleEvent);
evt.addListener(document,"click",handleEvent);
</script>
</body>
</html>
Savethisfileasch10_example17.html.Openitinmultiplebrowsers,andyou’llseeitworkexactlylikeExample13.
Thecodeismostlyunchanged;thisnewversionchangesonlyfivelinesofcode.Aswiththepasttwoexamples,youneedtoincludethefilecontainingyourevtobject:
<scriptsrc="event-utility.js"></script>
Next,youregistertheeventlistenersonthedocumentobjectfortheclick,mouseover,andmouseouteventsusingtheevtobject’saddListener()method:
evt.addListener(document,"mouseover",handleEvent);
evt.addListener(document,"mouseout",handleEvent);
evt.addListener(document,"click",handleEvent);
Andfinally,youchangethefirstlineofthehandleEvent()function:
functionhandleEvent(e){
vartarget=evt.getTarget(e);
Insteadofdirectlyusingthestandardorold-IE’stargetandsrcElementproperties,youuseevt.getTarget()toretrievetheelementobjectthatreceivedtheevent.
Thankfullywitheachpassingyear,theimportanceofcross-browserJavaScriptdiminishesasold-IEcontinuestolosemarketshare.IE8iscurrentlythemostpopularversionofold-IE,andthenumberofpeopleusingthatbrowserisdwindling.Whetherornotyouneedtosupportold-IEisdeterminedbyyourtargetaudience,andonlyyoucandecideifyouneedtoputforththeeffortofsupportingit.
Thepastfewsectionshavebeenratherrepetitive,butunderstandingeventsandhowtheyworkisabsolutelyvitalinJavaScriptdevelopment.Muchofthecodeyouwritewillbeinreactiontoaneventoccurringwithinthepage.
Additionally,you’llfindthatmoreeventsareaddedtobrowsersastheyimplementnewfeatures—forexample,thenewHTML5DragandDropAPI.
NATIVEDRAGANDDROPDragginganddroppingobjectswithinawebpagehasbeentheHolyGrailofJavaScriptdevelopment,andrightlyso—thesystemwespendthemajorityofourtimewith,ourcomputer’s/device’soperatingsystem,hasalwaysprovidedthatfunctionality.
Unfortunately,truedrag-and-dropsupporthasbeenelusiveinwebdevelopment,althoughsomeJavaScriptlibrariescameclose.Thoughtheyenabledustodraganddropelementswithinthewebpage,theywerelimitedbythecapabilities,orlackofinthiscase,exposedbythebrowser;interactingwithdroppedobjectsfromtheoperatingsystemwasimpossible.
ButHTML5changesthat.Forbrowsersthatsupportit,youcannowincorporatetruedrag-and-dropcapabilitieswithinyourwebpagesthankstoHTML5’sDragandDropAPI.Notonlycanyoumoveelementsaroundthepagebydragginganddroppingthem,buttheAPIenablesyoutodragobjectsfromtheoperatingsystem,likefiles,anddroptheminyourpage.
NOTENativedraganddropisonlysupportedinIE10+,Chrome,Firefox,Opera,andSafari.
MakingContentDraggableHTML5makesiteasytocreatedraggablecontent.Bysimplyaddingthedraggableattributetoanelementandsettingittotrue,youtellthebrowserthattheelementcanbeusedfordraganddrop:
<divdraggable="true">DraggableContent</div>
Inmostbrowsers,images,links,andselectedtextaredraggablebydefault.Figure10.4showssomeselectedtextbeingdraggedinChrome.
Figure10.4
Threeeventsarerelatedtothesourceofthedrag—thatis,theelementthatisbeingdragged.Thefollowingtableliststhem.
DRAGSOURCEEVENTS
DESCRIPTION
dragstart Firesontheelementwhenadragisstarted.Thisdoesnotfirewhendragginganobjectfromthefilesystem
drag Firescontinuouslywhiletheobjectisdraggeddragend Fireswhenthedragoperationiscomplete,regardlessofwhethertheobject
wasdropped.Thisdoesnotfirewhendragginganobjectfromthefilesystem
Toperformadrag-and-dropoperation,theonlyeventyouneedtolistenforisdragstart,butthatdoesn’tmeanthedraganddragendeventsarenotuseful.Youcanusethemtoaddextrafunctionalityand/orvisualcuestoenhancetheuser’sexperience.
CreatingaDropTargetIfyouaredraggingobjects,chancesareverygoodthatyouneedsomeplacetodropthem—adroptarget.Therearen’tspecialattributesorHTMLtosignifyanelementasadroptarget.Instead,youlistenforoneormultipleeventsontheelementservingasthedroptarget.
Oneofthemisthedragenterevent.Thiseventfireswhenthemousecursorentersthetargetwhiledragginganobject.Forexample:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example18</title>
<style>
.drop-zone{
width:300px;
padding:20px;
border:2pxdashed#000;
}
</style>
</head>
<body>
<divid="dropZone"class="drop-zone">DropZone!</div>
<divid="dropStatus"></div>
<script>
functionhandleDragEnter(e){
dropStatus.innerHTML="You'redraggingsomething!";
}
vardropZone=document.getElementById("dropZone");
vardropStatus=document.getElementById("dropStatus");
dropZone.addEventListener("dragenter",handleDragEnter);
</script>
</body>
</html>
Savethisfileasch10_example18.html.Openitandyou’llseesomethinglikeFigure10.5.
Figure10.5
Draganythingtothetarget.Itcanbeselectedtext,afileonyourcomputer,andsoon.Asyourmousepointerentersthetarget,you’llseethetextYou'redraggingsomething!
appearonthepage.Figure10.6showstextbeingdraggedoverthedropzoneinChrome.
Figure10.6
Inthispage,a<div/>elementisusedasthedropzone:
<divid="dropZone"class="drop-zone">DropZone!</div>
IthasanidofdropZoneandhastheCSSclassofdrop-zone.TheCSSisunimportantfromafunctionalstandpoint,butitdoesaddvisualclaritybecauseitdefinestheareainwhichyoucandropsomething.
TheimportantstuffisintheJavaScript.First,youretrievethedroptargetelementbyusingthedocument.getElementById()methodandlistenforitsdragenterevent.Youalsoretrievethe<div/>elementwithanidofdropStatus.You’lluseittodisplaystatusmessagesduringthedragoperation:
vardropZone=document.getElementById("dropZone");
vardropStatus=document.getElementById("dropStatus");
dropZone.addEventListener("dragenter",handleDragEnter);
Thiseventfiresonlywhenyouaredraggingsomethingandthemousecursorentersthetarget.Whenthishappens,thehandleDragEnter()functionexecutes:
functionhandleDragEnter(e){
dropStatus.innerHTML="You'redraggingsomething!";
}
Thissimplefunctionchangesthestatuselement’scontentstostate,You'redraggingsomething!
Thedragentereventisoneoffoureventsyoucanlistenforonthetargetelement.Thefollowingtableliststhem.
DRAGSOURCEEVENTS
DESCRIPTION
dragenter Fireswhenthemouseisfirstmovedoverthetargetelementwhiledragging
dragover Firesonthetargetasthemousemovesoveranelementwhiledragging
dragleave Firesonthetargetwhenthemouseleavesthetargetwhiledragging
drop Firesonthetargetwhenthedrop(theuserreleasesthemousebutton)occurs
Thedragentereventlooksimportant;afterall,itletsyouknowwhenthemousecursorentersthedropzonewhiledragginganobject.Butinactuality,it’soptional.Youcannotcompleteadrag-and-dropoperationwiththedragenterevent.Instead,youhavetolistenforthedropzone’sdragoverevent.
Thisiswherethingsstarttogetweird.Forthedropeventtofire,youhavetopreventthebehaviorofthedragoverevent.So,youbasicallyhavetocallpreventDefault()ontheEventobjecteverytimeyoulistenforthedragoverevent.
TRYITOUTDroppingObjectsonaTargetInthisTryItOut,youwriteasimpleexamplethatletsyoudraganddropanelementontoatarget.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example19</title>
<style>
.box{
width:100px;
height:100px;
}
.red{
background-color:red;
}
.drop-zone{
width:300px;
padding:20px;
border:2pxdashed#000;
}
</style>
</head>
<body>
<divdraggable="true"class="boxred"></div>
<divid="dropZone"class="drop-zone">DropZone!</div>
<divid="dropStatus"></div>
<script>
functiondragDropHandler(e){
e.preventDefault();
if(e.type=="dragover"){
dropStatus.innerHTML="You'redraggingoverthedrop
zone!";
}else{
dropStatus.innerHTML="Youdroppedsomething!";
}
}
vardropZone=document.getElementById("dropZone");
vardropStatus=document.getElementById("dropStatus");
dropZone.addEventListener("dragover",dragDropHandler);
dropZone.addEventListener("drop",dragDropHandler);
</script>
</body>
</html>
Savethisfileasch10_example19.html,andopenit.YourwebpagewilllooklikeFigure10.7.
Figure10.7
Dragtheredboxoverthetargetelement,andyou’llseethetextofthestatuselementchangetoYou'redraggingoverthedropzone!Droptheelementinthedropzone,andthestatustextwillchangetoYoudroppedsomething!
Thereisoneexception,however:Firefoxwillnotletyoudragtheredbox,butitwillletyoudropobjectsfromothersources(suchastext,filesonthefilesystem,andso
on).We’llexplainwhylater.
TheCSSofthisexampledefinesthreeclasses.You’vealreadyseenthedrop-zoneclass,andtheboxandredclassesareextremelysimple:
.box{
width:100px;
height:100px;
}
.red{
background-color:red;
}
Theboxclasssetstheelement’swidthandheightpropertiesto100pixels,andredgivestheelementabackgroundcolorofred.Thesearearbitraryvaluesmeanttoonlygivethedraggableelementsomevisibility.
Next,theHTML.TheonlynewelementinthisHTMLdocumentisadraggable<div/>element:
<divdraggable="true"class="boxred"></div>
Tomakeitdraggable,yousetthedraggableattributetotrue,andyouapplytheboxandredCSSclassestomakeiteasiertodraganddrop.
ButaswithExample18,thegoodstuffisintheJavaScript.First,youregisterlistenersforthedropZone’sdragoveranddropevents:
dropZone.addEventListener("dragover",dragDropHandler);
dropZone.addEventListener("drop",dragDropHandler);
Let’slookatthedragDropHandler()function.TheveryfirstlinecallstheEventobject’spreventDefault()method:
functiondragDropHandler(e){
e.preventDefault();
Thisiscrucialfortworeasons.First,thedragover’sdefaultbehaviormustbepreventedinorderforthedropeventtofire(andthat’skindofimportant).
Second,thebrowserwilldosomethingwhenyoudropanobject.Inotherwords,thedropeventhasadefaultbehavior,buttheexactbehaviordependsonthebrowserandtheobjectthatyoudrop.Someexamplesare:
Forafileorimage,mostbrowserswillattempttoopenit.
DroppingaURLmaycausethebrowsertonavigatetotheURL.
InFirefox,droppinganelementwillcausethebrowsertonavigatetothevalueintheelement’sidattribute.
Therefore,youwanttopreventthedropevent’sdefaultbehaviorinmostcases.
Afterpreventingthedefaultbehavior,thedragDropHandler()functionchangesthecontentofthedropStatuselementbasedonthetypeofevent:
if(e.type=="dragover"){
dropStatus.innerHTML="You'redraggingoverthedropzone!";
}else{
dropStatus.innerHTML="Youdroppedsomething!";
}
}
Forthedragoverevent,itsimplystatesthatyouaredraggingoverthetargetelement;otherwise,thefunctionknowsthatyoudroppedsomethingandtellsyouso.
Frustratingly,nativedraganddropdoesn’tworkexactlythesameinallmodernbrowsers.Theaforementionedpartiallistofthebrowsers’defaultbehaviorforthedropeventisjustonethingJavaScriptdevelopershavetocontendwith.
ButalsorememberthatExample19doesn’tcompletelyworkinFirefox.AlthoughitisfrustratingthatJavaScriptdevelopershavetocopewithinconsistentimplementations,Firefox’sdrag-and-dropimplementation,whetherit’srightorwrong,doesmakesomesenseinthisregard.Aswetrytodragtheredbox,wehaven’ttoldthebrowserwhatwe’retransferring.
TransferringDataWhenyouthinkaboutit,adrag-and-dropoperationisthetransferenceofdata.Forexample,whenyoudragafileonyourfilesystemfromonefoldertoanother,youaretransferringthedata(thefile)betweenthetwofolderlocations.Whendraggingtextfromoneapplicationtoanother,youaretransferringthetextualdatabetweenthetwoapplications.
Draganddropinthebrowserfollowsasimilarconcept.Whenstartingadrag,youneedtotellthebrowserwhatyouplantotransfer,andwhenyoudroptheobject,youneedtospecifyhowthatdatatransfersfromthesourcetothetarget.
Thedrag-and-dropspecificationdefinesaDataTransferobjectthatisusedtoholdthedatathatisbeingdraggedduringadrag-and-dropoperation.YouaccessthisobjectwiththeEventobject’sdataTransferproperty.YousetdatawiththeDataTransferobject’ssetData()methodinthedragstarteventhandler,andyoureadthatdatainthedropeventhandlerwiththegetData()method.
TomakeExample19workinFirefox,youneedtohandlethedragstarteventandusetheDataTransferobject’ssetData()method.Thefollowingaddsthenecessarycode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example20</title>
<style>
.box{
width:100px;
height:100px;
}
.red{
background-color:red;
}
.drop-zone{
width:300px;
padding:20px;
border:2pxdashed#000;
}
</style>
</head>
<body>
<divdraggable="true"class="boxred"></div>
<divid="dropZone"class="drop-zone">DropZone!</div>
<divid="dropStatus"></div>
<script>
functiondragStartHandler(e){
e.dataTransfer.setData("text","DragandDrop!");
}
functiondragDropHandler(e){
e.preventDefault();
if(e.type=="dragover"){
dropStatus.innerHTML="You'redraggingoverthe"+
"dropzone!";
}else{
dropStatus.innerHTML=e.dataTransfer.getData("text");
}
}
vardragBox=document.querySelector("[draggable]");
vardropZone=document.getElementById("dropZone");
vardropStatus=document.getElementById("dropStatus");
dragBox.addEventListener("dragstart",dragStartHandler);
dropZone.addEventListener("dragover",dragDropHandler);
dropZone.addEventListener("drop",dragDropHandler);
</script>
</body>
</html>
Savethisfileasch10_example20.html,andopenitinFirefox.Nowdragtheredboxtothetarget,andyou’llseethatitbehavessimilarlytoch10_example19.htmlinallbrowsers(Firefoxincluded).
Let’sfocusonlyonthenewlinesofcode.First,youstorethedraggableboxinthedragBoxvariablebyusingdocument.querySelector()andpassingtheattributeselectorof“[draggable]”:
vardragBox=document.querySelector("[draggable]");
Next,youregisteraneventlistenerforthedragstarteventonthedragBoxobject:
dragBox.addEventListener("dragstart",dragStartHandler);
ThedragStartHandler()functionexecuteswhenyoustartadragoperationonthedragBoxobject.ThisfunctionmakesuseoftheDataTransferobject’ssetData()methodtoholddataforthedrag-and-dropoperation:
functiondragStartHandler(e){
e.dataTransfer.setData("text","DragandDrop!");
}
ThesetData()functionacceptstwoarguments:thetypeofdatatostoreandtheactualdata.Theonlydatatypessupportedbyallbrowsersare“text”and“url”;therefore,thisfunctionstoresthetextualdataofDragandDrop!
NOTEMostbrowserssupportotherdatatypes,suchasMIMEtypes(forexample,text/plain,text/html,andsoon).IE10andIE11,however,onlysupporttextandurl.
Thelastnew/changedlineisinthedragDropHandler()function.Insteadofdisplayinganarbitrarystringvalueinthestatuselementwhenthedropeventfires,youretrievethedatafromthedataTransferobjectbyusingthegetData()method:
dropStatus.innerHTML=e.dataTransfer.getData("text");
ThegetData()methodacceptsonlyoneargument:thedatatypeyouusedwhencallingsetData().Therefore,thiscoderetrievesthevalueofDragandDrop!andusesitastheinnerHTMLofthestatuselement.
TRYITOUTFullDragandDropInthisTryItOut,youapplyeverythingyou’velearnedaboutnativedraganddropandwriteapagethatletsyoudraganddropelementsbetweentwodroptargets.
Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Example21</title>
<style>
[data-drop-target]{
height:400px;
width:200px;
margin:2px;
background-color:gainsboro;
float:left;
}
.drag-enter{
border:2pxdashed#000;
}
.box{
width:200px;
height:200px;
}
.navy{
background-color:navy;
}
.red{
background-color:red;
}
</style>
</head>
<body>
<divdata-drop-target="true">
<divid="box1"draggable="true"class="boxnavy"></div>
<divid="box2"draggable="true"class="boxred"></div>
</div>
<divdata-drop-target="true"></div>
<script>
functionhandleDragStart(e){
e.dataTransfer.setData("text",this.id);
}
functionhandleDragEnterLeave(e){
if(e.type=="dragenter"){
this.className="drag-enter";
}else{
this.className="";
}
}
functionhandleOverDrop(e){
e.preventDefault();
if(e.type!="drop"){
return;
}
vardraggedId=e.dataTransfer.getData("text");
vardraggedEl=document.getElementById(draggedId);
if(draggedEl.parentNode==this){
return;
}
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
this.className="";
}
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-target]");
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",
handleDragStart);
}
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",
handleDragEnterLeave);
targets[i].addEventListener("dragleave",
handleDragEnterLeave);
}
</script>
</body>
</html>
Savethisfileasch10_example21.htmlandopenitinyourmodernbrowserofchoice.You’llseeapagethatconsistsoftwocolumns.Ontheleft,ablueboxsitsontopofaredone,andontherightisasolidgrayishrectangle,asshowninFigure10.8.
Figure10.8
Thegrayishareasaredroptargets,andtheblueandredboxesaredraggableobjects.Dragtheblueboxtotheemptydroptarget,andyou’llseeadashedborderappeararoundthetarget(Figure10.9).
Figure10.9
Droptheblueboxonthattarget,andyou’llseeitmovefromthelefttargettotheright.Nowdragtheboxesbetweenthetwodroptargetstoseethefulleffect.
Let’sstartwiththeHTML.Adroptargetinthisexampleisanelementidentifiedwiththedata-drop-targetattributesettotrue.Thisexampleconsistsoftwodroptargets,althoughyoucaneasilyaddmore:
<divdata-drop-target="true">
<divid="box1"draggable="true"class="boxnavy"></div>
<divid="box2"draggable="true"class="boxred"></div>
</div>
<divdata-drop-target="true"></div>
Thefirstdroptargetcontainstwodraggable<div/>elements,andtheyeachhaveanidattribute.Otherthantheiridvalues,theonlydifferenceistheirCSS.BothusetheboxCSSclass,butonealsousesthenavyCSSclass,whereastheotherusestheredclass.
SpeakingofCSS,let’slookatthestylesdefinedinthestylesheet.Thefirstrulematchesallelementsthathaveadata-drop-targetattribute:
[data-drop-target]{
height:400px;
width:200px;
margin:2px;
background-color:gainsboro;
float:left;
}
Theheightandwidtharesettoaccommodatetwodraggableboxesatatime.A
marginoftwopixelsgivesjustenoughspacebetweenthedroptargetelementstovisuallyseparatethem.Abackgroundcolormakesthemeasilydistinguishablebetweenthepage’sbackground,andtheyeachfloatleft.
Thenextrulealsoappliestodroptargets:
.drag-enter{
border:2pxdashed#000;
}
Thedrag-enterclassisusedasavisualcue.Asyoudraganobjectoveradroptargetelement,thisdrag-enterclassisappliedtotheelement.Thisisn’tnecessaryforthedrag-and-dropoperationtocomplete,butitdoesenhancetheuser’sexperience.
ThefinalsetofCSSrulesisusedforthedraggableelements:
.box{
width:200px;
height:200px;
}
.navy{
background-color:navy;
}
.red{
background-color:red;
}
Eachdraggableelementusestheboxclasstosetitsheightandwidth.Thenavyandredclassesareusedinconjunctionwiththeboxclasstogivetheelementabackgroundcolorofnavyorred,respectively.
AsfortheJavaScript,youfirstretrievetwogroupsofelements—thosethataredraggableandthosethataredroptargets:
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-target]");
Sousingthedocument.querySelectorAll()method,youretrievebothgroupsofelementswiththeirrespective[draggable]and[data-drop-target]CSSselectorsandassignthemtothedraggableandtargetsvariables.
Next,youwanttoregisterthedragstarteventlistenersonthedraggableelements:
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",handleDragStart);
}
Usingaforloop,youiterateoverthedraggablecollectionandcalltheaddEventListener()methodoneachdraggableobject,passingdragstartastheeventandthehandleDragStart()functionobjectasthehandler.
Youthenwanttouseasimilarprocessonthetargetelements:
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",handleDragEnterLeave);
targets[i].addEventListener("dragleave",handleDragEnterLeave);
}
Byusinganotherforloop,youloopthroughthetargetscollectionandregistereventhandlersforthedragover,drop,dragenter,anddragleaveevents.Twofunctionsareusedtohandlethesefourevents:thehandleOverDrop()functionhandlesthedragoveranddropevents,andhandleDragEnterLeave()handlesdragenteranddragleave.
Thefirstfunction,handleDragStart(),containsjustasinglelineofcode:
functionhandleDragStart(e){
e.dataTransfer.setData("text",this.id);
}
Itspurposeissimple:tostoretheidofthedraggableelement.Noticetheuseofthisinthis.id.Whenyouregisteraneventlistener,thehandlerfunctionexecuteswithinthecontextoftheelementobjecttheeventfiredon.Inthiscase,thedragstarteventfiredononeofthedraggableelements;so,thisreferstothatelement.Inotherwords,thisisthesamease.target.
ThenextfunctionishandleDragEnterLeave(),andasmentionedearlier,itexecuteswhenthedragenteranddragleaveeventsfireonadroptarget:
functionhandleDragEnterLeave(e){
if(e.type=="dragenter"){
this.className="drag-enter";
}else{
this.className="";
}
}
Thefirstlineofthisfunctionchecksthetypeofeventthatoccurred.Iftheeventisdragenter,theCSSclassofthedroptargetelementissettodrag-enter(onceagain,noticethisisusedinsteadofe.target—it’smucheasiertotype).Iftheeventisn’tdragenter,theelement’sCSSclassissettoanemptystring,thusremovingthedrag-enterclass.
Thefinalfunction,handleOverDrop(),performstherealmagicofthedrag-and-dropoperation.Thisfunctionhandlesboththedragoveranddropeventsandshouldthereforepreventthedefaultactionfromoccurring.Thus,thefirstlineofthefunctioncallse.preventDefault():
functionhandleOverDrop(e){
e.preventDefault();
Thisisallthatisneededforthedragoverevent.So,iftheeventisn’tadropevent,thefunctionsimplyexits:
if(e.type!="drop"){
return;
}
Ifitisadropevent,thefunctioncontinuesonandretrievesthedraggableelement’sidfromtheDataTransferobject:
vardraggedId=e.dataTransfer.getData("text");
vardraggedEl=document.getElementById(draggedId);
Andwiththisid,youretrievethedraggableelement’sobjectwithdocument.getElementById()andstoreitinthedraggedElvariable.
Youhavetwooptionswhenitcomestodroppingoneofthedraggableboxes:youcaneitherdropitinthetargetit’scurrentlyin,oryoucandropitinanothertarget.Ifdroppedinitscurrentlocation,there’snothinglefttodoexceptresetthetarget’sCSSclass.Thisiseasyenoughtocheck;simplyusetheelement’sparentNodeproperty:
if(draggedEl.parentNode==this){
this.className="";
return;
}
Ifthedraggedelement’sparentnodeisthetargetdropzone,yousettheclassNamepropertytoanemptystringandexitthefunctionusingthereturnstatement.Otherwise,youwanttomovethedraggedelementnodefromitsoldparent/droptargettoitsnewparent/droptarget:
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
Thisisasimpleprocess,asyoucansee.Toremovethedraggableelementfromitscurrentparent,youretrieveitsparentNodeandcalltheremoveChild()method.TheremoveChild()methoddoesn’tdeletethenode;itsimplyremovesitsothatyoucanappendittoanothernodeintheDOM.
Withthedraggedelementmovedfromonedroptargettoanother,thedrag-and-dropoperationiscomplete,andyousetthedroptargetelement’sCSSclasstoanemptystring:
this.className="";
Thisvisuallyresetsthedroptarget,givingusersavisualcuethatthedrag-and-dropoperationiscomplete.
Awebpageisaninteractiveenvironment.Usersarebusyclicking,typing,dragging,anddoingotherthings.Assuch,eventsareanextremelyimportantmatterforwebdevelopers.Notonlyareeventshowwerespondandinteractwiththeuser,theyalsoenableustoexecutecodewhenspecificthingshappeninthepage.Inlaterchapters,youseeexamplesofsuchanduseeventstorespondtoanobject’saction,ratherthanauser’saction.
SUMMARYYou’vecoveredalotinthischapter,butnowyouhaveasolidbasisonhowtoworkwithandhandleeventsinthebrowsersthatarecurrentlyinuseontheweb.YouevenknowthedifferencebetweenthestandardDOMeventmodelandold-IE’seventmodel,andyouwroteaneventutilitythatmakeswritingcross-browserJavaScriptrelativelysimple.
Thischaptercoveredthefollowingpoints:
YousawthatHTMLelementshaveeventsaswellasmethodsandproperties.YouhandletheseeventsinJavaScriptbyusingeventhandlers,whichyouconnecttocodethatyouwanttohaveexecutedwhentheeventoccurs.Theeventsavailableforusedependontheobjectyouaredealingwith.
Youcanconnectafunctiontoanelement’seventhandlerusingtheelement’s“on”attributes.ButyoualsolearnedthatdoingsomixesyourHTMLandJavaScript,andthisapproachshouldbeavoidedmostofthetime.
Eventscanbehandledbyusinganobject’s"on"properties,whichisabettersolutionthantheHTMLattributes,butstillhasitsownissues.
ThestandardDOMeventmodelissupportedbyallmodernbrowsers,anditprovidesthebestwaytoconnectyourcodetoevents.
YoulearnedaboutthestandardEventobjectandhowitprovidesalotofinformationabouttheeventthatoccurred,includingthetypeofeventandtheelementthatreceivedtheevent.
Youlearnedaboutold-IE’sproprietaryeventmodel,howtoconnecteventswithattachEvent(),andhowtoaccessold-IE’seventobject.
SomedifferencesexistbetweenthestandardDOMeventmodelandtheold-IEeventmodel.Youlearnedthekeydifferencesandwroteasimplecross-browsereventutility.
Someeventshaveadefaultactionthatoccurswhentheeventfires,andyoucanpreventthatactionwiththestandardEventobject’spreventDefault()methodandold-IE’sreturnValueproperty.
Modernbrowserssupportnativedrag-and-dropcapabilities,andyoucanwritecodethattakesadvantageofthisnewfeature.
Insomeinstances,suchasforthedocumentobject,asecondwayofconnectingeventhandlerstocodeisnecessary.Settingtheobject’spropertywiththenameoftheeventhandlertoyourfunctionproducesthesameeffectasifyoudiditusingtheeventhandlerasanattribute.
Insomeinstances,returningvaluesfromeventfunctionsenablesyoutocanceltheactionassociatedwiththeevent.Forexample,tostopaclickedlinkfromnavigatingtoapage,youreturnfalsefromtheeventhandler’scode.
That’sitforthischapter.Inthenextchapter,youmoveontoformscripting,whereyou
EXERCISES1. AddamethodtotheeventutilityobjectcalledisOldIE()thatreturnsaboolean
valueindicatingwhetherornotthebrowserisold-IE.
2. Example15exhibitssomebehaviorinconsistenciesbetweenstandards-compliantbrowsersandold-IE.Rememberthattheeventhandlersexecuteinreverseorderinold-IE.ModifythisexampletousethenewisOldIE()methodsothatyoucanwritespecificcodeforold-IEandstandards-compliantbrowsers(Hint:youwillcalltheaddListener()methodfourtimes).
3. Example17hadyouwriteacross-browsertabscript,butasyouprobablynoticed,itbehavespeculiarly.Thebasicideaisthere,butthetabsremainactiveasyouclickanothertab.Modifythescriptsothatonlyonetabisactiveatatime.
11HTMLForms:InteractingwiththeUserWHATYOUWILLLEARNINTHISCHAPTER:
Scriptingtext,password,textarea,andhiddenformcontrols
Writingcodeforselect,checkbox,andradiobuttonformcontrols
UsingJavaScripttointeractwithnewHTML5formcontrols
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Webpageswouldbeveryboringifyoucouldnotinteractwithorobtaininformationfromtheuser,suchastext,numbers,ordates.Luckily,withJavaScriptthisispossible.Youcanusethisinformationwithinthewebpage,oryoucanpostittothewebserverwhereyoucanmanipulateitandstoreitinadatabaseifyouwish.Thischapterconcentratesonusingtheinformationwithinthewebbrowser,whichiscalledclient-sideprocessing.
You’requiteaccustomedtovarioususerinterfaceelements.Forexample,everyoperatingsystemhasanumberofstandardelements,suchasbuttonsyoucanclick;lists,drop-downlistboxes,andradiobuttonsyoucanselectfrom;andboxesyoucancheck.Theseelementsarethemeansbywhichyounowinterfacewithapplications.Thegoodnewsisthatyoucanincludemanyofthesetypesofelementsinyourwebpage—andevenbetter,it’sveryeasytodoso.Whenyouhavesuchanelement—say,abutton—insideyourpage,youcanthentiecodetoitsevents.Forexample,whenthebuttonisclicked,youcanfireoffaJavaScriptfunctionyoucreated.
AlloftheHTMLelementsusedforinteractionshouldbeplacedinsideanHTMLform.Let’sstartbytakingalookatHTMLformsandhowyouinteractwiththeminJavaScript.
HTMLFORMSFormsprovideyouwithawayofgroupingtogetherHTMLinteractionelementswithacommonpurpose.Forexample,aformmaycontainelementsthatenabletheinputofauser’sdataforregisteringonawebsite.Anotherformmaycontainelementsthatenabletheusertoaskforacarinsurancequote.It’spossibletohaveanumberofseparateformsinasinglepage.Youdon’tneedtoworryaboutpagescontainingmultipleformsuntilyouhavetosubmitinformationtoawebserver—thenyouneedtobeawarethattheinformationfromonlyoneoftheformsonapagecanbesubmittedtotheserveratonetime.
Tocreateaform,usethe<form>and</form>tagstodeclarewhereitstartsandwhereitends.The<form/>elementhasanumberofattributes,suchastheactionattribute,whichdetermineswheretheformissubmitted;themethodattribute,whichdetermineshowtheinformationissubmitted;andthetargetattribute,whichdeterminestheframetowhichtheresponsetotheformisloaded.
Generallyspeaking,forclient-sidescriptingwhereyouhavenointentionofsubmittinginformationtoaserver,theseattributesarenotnecessary.Fornowtheonlyattributeyouneedtosetinthe<form/>elementisthenameattribute,sothatyoucanreferencetheform.
So,tocreateablankform,thetagsrequiredwouldlooksomethinglikethis:
<formname="myForm">
</form>
Youwon’tbesurprisedtohearthatthesetagscreateanHtmlFormElementobject,whichyoucanusetoaccesstheform.Youcanaccessthisobjectintwoways.
First,youcanaccesstheobjectdirectlyusingitsname—inthiscasedocument.myForm.Alternatively,youcanaccesstheobjectthroughthedocumentobject’sformscollectionproperty.RememberthatChapter8includedadiscussionofthedocumentobject’simagescollectionandhowyoucanmanipulateitlikeanyotherarray.Thesameappliestotheformscollection,exceptthatinsteadofeachelementinthecollectionholdinganHtmlImageElementobject,itnowholdsanHtmlFormElement(herebycalledsimplyForm)object.Forexample,ifit’sthefirstforminthepage,youreferenceitusingdocument.forms[0].
NOTEOfcourse,youcanalsoaccessaformusingthedocument.getElementById()anddocument.querySelector()methods.
Manyoftheattributesofthe<form/>elementcanbeaccessedaspropertiesoftheHtmlFormElementobject.Inparticular,thenamepropertymirrorsthenameattributeofthe<form/>element.
TRYITOUTTheformsCollection
InthisTryItOut,you’llusetheformscollectiontoaccesseachofthreeFormobjectsandshowthevalueoftheirnamepropertiesinamessagebox.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example1</title>
</head>
<body>
<formaction=""name="form1">
<p>
Thisisinsideform1.
</p>
</form>
<formaction=""name="form2">
<p>
Thisisinsideform2
</p>
</form>
<formaction=""name="form3">
<p>
Thisisinsideform3
</p>
</form>
<script>
varnumberForms=document.forms.length;
for(varindex=0;index<numberForms;index++){
alert(document.forms[index].name);
}
</script>
</body>
</html>
Savethisasch11_example1.html.Whenyouloaditintoyourbrowser,youshouldseeanalertboxdisplaythenameofthefirstform.ClicktheOKbuttontodisplaythenextform’sname,andthenclickOKathirdtimetodisplaythethirdandfinalform’sname.
Withinthebodyofthepageyoudefinethreeforms.Yougiveeachformanameandaparagraphoftext.
IntheJavaScriptcode,youloopthroughtheformscollection.JustlikeanyotherJavaScriptarray,theformscollectionhasalengthproperty,whichyoucanusetodeterminehowmanytimesyouneedtoloop.Actually,becauseyouknowhowmanyformsyouhave,youcanjustwritethenumberin.However,thisexampleusesthelengthproperty,becausethatmakesiteasiertoaddtothecollectionwithouthavingtochangethecode.Generalizingyourcodelikethisisagoodpracticetogetinto.
ThecodestartsbygettingthenumberofFormobjectswithintheformscollectionandstoringthatnumberinthevariablenumberForms:
varnumberForms=document.forms.length;
Nextyoudefinetheforloop:
for(varformIndex=0;formIndex<numberForms;formIndex++){
alert(document.forms[formIndex].name);
}
Rememberthatbecausetheindexesforarraysstartat0,yourloopneedstogofromanindexof0toanindexofnumberForms–1.Youenablethisbyinitializingtheindexvariableto0,andsettingtheconditionoftheforlooptoindex<numberForms.
Withintheforloop’scode,youpasstheindexoftheformyouwant(thatis,index)todocument.forms[],whichgivesyoutheFormobjectatthatindexintheformscollection.ToaccesstheFormobject’snameproperty,youputadotattheendofthenameoftheproperty,name.
TRADITIONALFORMOBJECTPROPERTIESANDMETHODSTheHTMLformcontrolscommonlyfoundinforms,whichyoulookatinmoredetailshortly,alsohavecorrespondingobjects.OnewaytoaccesstheseisthroughtheelementspropertyoftheFormobject,anothercollection.TheelementscollectioncontainsalltheobjectscorrespondingtotheHTMLinteractionelementswithintheform,withtheexceptionofthelittle-used<inputtype="image"/>element.Asyouseelater,thispropertyisveryusefulforloopingthrougheachoftheelementsinaform.Forexample,youcanloopthrougheachelementtocheckthatitcontainsvaliddatapriortosubmittingaform.
Beingacollection,theelementspropertyoftheFormobjecthasthelengthproperty,whichtellsyouhowmanyelementsareintheform.TheFormobjectalsohasthelengthproperty,whichalsogivesyouthenumberofelementsintheform.Whichoftheseyouuseisuptoyoubecausebothdothesamejob,althoughwritingmyForm.lengthisshorter,andthereforequickertotypeandlesslengthytolookatincode,thanmyForm.elements.length.
Whenyousubmitdatafromaformtoaserver,younormallyusetheSubmitbutton,whichyouwillcometoshortly.However,theFormobjectalsohasthesubmit()method,whichdoesnearlythesamething.
NOTEThesubmit()methodsubmitstheform,butitdoesnotfirethesubmiteventoftheFormobject;thus,submiteventlistenersarenotcalledwhensubmittingtheformwithsubmit().
RecallthatinChapter10youlearnedthatyoucanaffectwhetherthenormalcourseofeventscontinuesoriscanceled.Yousaw,forexample,thatcallingpreventDefault()inahyperlink’sclickeventhandlercausesthelink’snavigationtobecanceled.Well,thesameprincipleappliestotheFormobject’ssubmitevent,whichfireswhentheusersubmitstheform.BycallingpreventDefault(),thesubmissioniscanceled.Thismakesthesubmiteventhandler’scodeagreatplacetodoformvalidation—thatis,tocheckthatwhattheuserhasenteredintotheformisvalid.Forexample,ifyouaskfortheusers’agesandtheyentermindyourownbusiness,youcanspotthatthisistextratherthanavalidnumberandstopthemfromcontinuing.
InadditiontotherebeingaResetbutton,whichisdiscussedlaterinthechapter,theFormobjecthasthereset()method,whichclearstheform,orrestoresdefaultvaluesiftheseexist.
Creatingblankformsisnotexactlyexcitingoruseful,sonowlet’sturnourattentiontotheHTMLelementsthatprovideinteractionfunctionalityinsideforms.
HTMLElementsinForms
Abouttenelementsarecommonlyfoundwithin<form/>elements.ThemostusefulareshowninFigures11.1,11.2,11.3,and11.4,orderedintogeneraltypes.Eachtypenameisgivenand,inparentheses,theHTMLneededtocreateit,thoughnotethisisnotthefullHTMLbutonlyaportion.ThenewHTML5formcontrolsarenotlistedhere;youexaminethemlaterinthechapter.
Figure11.1
Figure11.4
Asyoucansee,mostformelementsarecreatedbymeansofthe<input/>element.Oneofthe<input/>element’sattributesisthetypeattribute.It’sthisattributethatdecideswhichoftheformelementsthiselementwillbe.Examplesofvaluesforthisattributeincludebutton(tocreateabutton)andtext(tocreateatextbox).
Eachformelementinsidethewebpageismadeavailabletoyouas—yes,youguessedit—anobject.Aswithalltheotherobjectsyouhaveseen,eachelement’sobjecthasitsownsetofdistinctiveproperties,methods,andevents.You’llbetakingalookateachformelementinturnandhowtouseitsparticularproperties,methods,andevents,butbeforeyoudothat,let’slookatpropertiesandmethodsthattheobjectsoftheformelementshaveincommon.
CommonPropertiesandMethodsBecausemostformelementsarecreatedbythe<input/>element,itwouldbecorrecttoguessthatallformelementsshareseveralpropertiesandmethodsincommon.
Hereareafew.
ThenamePropertyOnepropertythatalltheobjectsoftheformelementshaveincommonisthenameproperty.Youcanusethevalueofthispropertytoreferencethatparticularelementinyourscript.Also,ifyouaresendingtheinformationintheformtoaserver,theelement’snamepropertyissentalongwithanyvalueoftheformelement,sothattheserverknowswhatthevaluerelatesto.
ThevalueProperty
Mostformelementobjectsalsohavethevalueproperty,whichreturnsthevalueoftheelement.Forexample,foratextbox,thevaluepropertyreturnsthetextthattheuserenteredinthetextbox.Also,settingthevalueofthevaluepropertyenablesyoutoputtextinsidethetextbox.However,theuseofthevaluepropertyisspecifictoeachelement,soyou’lllookatwhatitmeansasyoulookateachindividualelement.
TheformPropertyAllformelementobjectsalsohavetheformproperty,whichreturnstheFormobjectinwhichtheelementiscontained.Thiscanbeusefulincaseswhereyouhaveagenericroutinethatchecksthevalidityofdatainaform.Forexample,whentheuserclicksaSubmitbutton,youcanpasstheFormobjectreferencedbytheformpropertyoftheSubmitbuttontoyourdatachecker,whichcanuseittoloopthrougheachelementontheforminturn,checkingthatthedataintheelementisvalid.Thisishandyifyouhavemorethanoneformdefinedonthepageorwhereyouhaveagenericdatacheckerthatyoucutandpastetodifferentpages—thiswayyoudon’tneedtoknowtheform’snameinadvance.
ThetypePropertySometimesit’susefultoknowwhattypeofelementyou’redealingwith,particularlywhereyou’reloopingthroughtheelementsinaformusingtheelementscollectionproperty.Thisinformationcanberetrievedbymeansofthetypeproperty,whicheachelement’sobjecthas.Thispropertyreturnsthetypeoftheelement(forexample,buttonortext).
Thefocus()andblur()MethodsAllformelementobjectsalsohavethefocus()andblur()methods.Focusisaconceptyoumightnothavecomeacrossyet.Ifanelementisthecenterofthefocus,anykeypressesmadebytheuserarepasseddirectlytothatelement.Forexample,ifatextboxhasfocus,pressingkeyswillentervaluesintothetextbox.Also,ifabuttonhasthefocus,pressingtheEnterkeycausesthebutton’sonclickeventhandlercodetofire,justasifauserhadclickedthebuttonwithhismouse.
TheusercansetwhichelementcurrentlyhasthefocusbyclickingitorbyusingtheTabkeytoselectit.However,youastheprogrammercanalsodecidewhichelementhasthefocusbyusingtheformelement’sobject’sfocus()method.Forexample,ifyouhaveatextboxfortheusertoenterhisageandheentersaninvalidvalue,suchasaletterratherthananumber,youcantellhimthathisinputisinvalidandsendhimbacktothattextboxtocorrecthismistake.
Blur,whichperhapscouldbebettercalled“lostfocus,”istheoppositeoffocus.Ifyouwanttoremoveaformelementfrombeingthefocusoftheuser’sattention,youcanusetheblur()method.Whenusedwithaformelement,theblur()methodusuallyresultsinthefocusshiftingtothepagecontainingtheform.
Inadditiontothefocus()andblur()methods,alltheformelement’sobjectshavetheonfocusandonblureventhandlers.Thesearefired,asyou’dexpect,whenanelementgetsorlosesthefocus,respectively,duetouseractionorthefocus()andblur()methods.Theonblureventhandlercanbeagoodplacetocheckthevalidityofdatainthe
elementthathasjustlostthefocus.Ifthedataisinvalid,youcansetthefocusbacktotheelementandlettheuserknowwhythedataheenterediswrong.
NOTERememberthatthesubmit()methodbehavesdifferentlythanfocus()andblur()inthatitdoesnotfirethesubmitevent.
Onethingtobecarefulofisusingthefocus()andblur()methodsinthefocusorblureventlistenercode.Thereisthedangerofaninfiniteloopoccurring.Forexample,considertwoelements,eachofwhosefocuseventspassesthefocustotheotherelement.Then,ifoneelementgetsthefocus,itsfocuseventwillpassthefocustothesecondelement,whosefocuseventwillpassthefocusbacktothefirstelement,andsoonuntiltheonlywayoutistoclosethebrowserdown.Thisisnotlikelytopleaseyourusers!
Alsobeverywaryofusingthefocus()andblur()methodstoputfocusbackinaproblemfieldifthatfieldorothersdependonsomeoftheuser’sinput.Forexample,sayyouhavetwotextboxes:oneinwhichyouwantuserstoentertheircityandtheotherinwhichyouwantthemtoentertheirstate.Alsosaythattheinputintothestatetextboxischeckedtomakesurethatthespecifiedcityisinthatstate.Ifthestatedoesnotcontainthecity,youputthefocusbackonthestatetextboxsothattheusercanchangethenameofthestate.However,iftheuseractuallyinputthewrongcitynameandtherightstatename,shemaynotbeabletogobacktothecitytextboxtorectifytheproblem.
ButtonElementsWe’restartingourlookatformelementswiththestandardbuttonelementbecauseit’sprobablythemostcommonlyusedandisfairlysimple.TheHTMLelementtocreateabuttonis<input/>.Forexample,tocreateabuttoncalledmyButton,whichhasthewords“ClickMe”onitsface,the<input/>elementwouldneedtobeasfollows:
<inputtype="button"name="myButton"value="ClickMe"/>
Thetypeattributeissettobutton,andthevalueattributeissettothetextyouwanttoappearonthefaceofthebutton.Youcanleavethevalueattributeoff,butyou’llendupwithablankbutton,whichwillleaveyourusersguessingastoitspurpose.
ThiselementcreatesanassociatedHTMLInputElementobject(infact,all<input/>elementscreateHTMLInputElementobjects);inthisexampleitiscalledmyButton.Thisobjecthasallthecommonpropertiesandmethodsdescribedearlier,includingthevalueproperty.ThispropertyenablesyoutochangethetextonthebuttonfaceusingJavaScript,thoughthisisprobablynotsomethingyou’llneedtodoveryoften.Whatthebuttonisreallyallaboutistheclickevent.
Youconnecttothebutton’sclickeventjustasyouwouldwithanyotherelement.Allyouneedtodoisdefineafunctionthatyouwanttoexecutewhenthebuttonisclicked(say,buttonClick())andthenregisteraclickeventlistenerwiththeaddEventListener()method.
TRYITOUTCountingButtonClicksInthefollowingexample,youusethemethodsdescribedpreviouslytorecordhowoftenabuttonhasbeenclicked.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example2</title>
</head>
<body>
<formaction=""name="form1">
<inputtype="button"name="myButton"value="Buttonclicked0
times"/>
</form>
<script>
varmyButton=document.form1.myButton;
varnumberOfClicks=0;
functionmyButtonClick(){
numberOfClicks++;
myButton.value="Buttonclicked"+numberOfClicks+"
times";
}
myButton.addEventListener("click",myButtonClick);
</script>
</body>
</html>
Savethispageasch11_example2.html.Ifyouloadthispageintoyourbrowser,youwillseeabuttonwith“Buttonclicked0times”onit.Ifyourepeatedlypressthisbutton,youwillseethenumberofbuttonclicksrecordedonthetextofthebutton.
YoustartthescriptblockbydefiningtwovariablescalledmyButtonandnumberOfClicks.Theformerholdsareferencetothe<input/>elementobject.Yourecordthenumberoftimesthebuttonhasbeenclickedinthelatterandusethisinformationtoupdatethebutton’stext.
TheotherpieceofcodeinthescriptblockisthedefinitionofthefunctionmyButtonClick().Thisfunctionhandlesthe<input/>element’sclickevent:
myButton.addEventListener("click",myButtonClick);
ThiselementisforaButtonelementcalledmyButtonandiscontainedwithinaformcalledform1:
<formaction=""name="form1">
<inputtype="button"name="myButton"value="Buttonclicked0times"
/>
</form>
Let’slookatthemyButtonClick()functionalittlemoreclosely.First,thefunctionincrementsthevalueofthevariablenumberOfClicksbyone:
functionmyButtonClick(){
numberOfClicks++;
Next,youupdatethetextonthebuttonfaceusingtheButtonobject’svalueproperty:
myButton.value="Buttonclicked"+numberOfClicks+"times";
}
Thefunctioninthisexampleisspecifictothisformandbutton,ratherthanagenericfunctionyou’lluseinothersituations.Therefore,thecodeinthisexampledirectlyreferstoabuttonusingthemyButtonvariable.
TRYITOUTmouseupandmousedownEventsTwolesscommonlyusedeventssupportedbytheButtonobjectarethemousedownandmouseupevents.Youcanseethesetwoeventsinactioninthenextexample.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example3</title>
</head>
<body>
<formaction=""name="form1">
<inputtype="button"name="myButton"value="Mousegoesup"/>
</form>
<script>
varmyButton=document.form1.myButton;
functionmyButtonMouseup(){
myButton.value="MouseGoesUp";
}
functionmyButtonMousedown(){
myButton.value="MouseGoesDown";
}
myButton.addEventListener("mousedown",myButtonMousedown);
myButton.addEventListener("mouseup",myButtonMouseup);
</script>
</body>
</html>
Savethispageasch11_example3.htmlandloaditintoyourbrowser.Ifyouclickthebuttonwithyourleftmousebuttonandkeepithelddown,you’llseethetextonthebuttonchangeto“MouseGoesDown.”Assoonasyoureleasethebutton,thetext
changesto“MouseGoesUp.”
Inthebodyofthepage,youdefineabuttoncalledmyButtonwithinaformcalledform1:
<formaction=""name="form1">
<inputtype="button"name="myButton"value="Mousegoesup"/>
</form>
YourJavaScriptcoderetrievesthisButtonobjectfromthedocumentandstoresitinthemyButtonvariable,andyouregistereventlistenersforthemouseupandmousedownevents.
ThemyButtonMouseup()andmyButtonMousedown()functionshandlethoseevents,respectively.Eachfunctionconsistsofjustasinglelineofcode,inwhichyouusethevaluepropertyoftheButtonobjecttochangethetextthatisdisplayedonthebutton’sface.
Animportantpointtonoteisthateventslikemouseupandmousedownaretriggeredonlywhenthemousepointerisactuallyovertheelementinquestion.Forexample,ifyouclickandholddownthemousebuttonoveryourbutton,thenmovethemouseawayfromthebuttonbeforereleasingthemousebutton,you’llfindthatthemouseupeventdoesnotfireandthetextonthebutton’sfacedoesnotchange.Inthisinstanceitwouldbethedocumentobject’smouseupeventthatwouldfire,ifyou’dconnectedanycodetoit.
Don’tforgetthat,likeallformelementobjects,theButtonobjectalsohasthefocusandblurevents,thoughtheyarerarelyusedinthecontextofbuttons.
TwoadditionalbuttontypesaretheSubmitandResetbuttons.Youdefinethesebuttonsjustasyoudoastandardbutton,exceptthatthetypeattributeofthe<input>tagissettosubmitorresetratherthantobutton.Forexample,theSubmitandResetbuttonsinFigure11.4werecreatedusingthefollowingcode:
<inputtype="submit"value="Submit"name="submit1"/>
<inputtype="reset"value="Reset"name="reset1"/>
Thesebuttonshavespecialpurposes,whicharenotrelatedtoscript.
WhentheSubmitbuttonisclicked,theformdatafromtheformthatthebuttonisinsidegetssenttotheserverautomatically,withouttheneedforanyscript.
WhentheResetbuttonisclicked,alltheelementsinaformareclearedandreturnedtotheirdefaultvalues(thevaluestheyhadwhenthepagewasfirstloaded).
TheSubmitandResetbuttonshavecorrespondingobjectscalledSubmitandReset,whichhaveexactlythesameproperties,methods,andeventsasastandardButtonobject.
TextElementsThestandardtextelementsenableuserstoenterasinglelineoftext.ThisinformationcanthenbeusedinJavaScriptcodeorsubmittedtoaserverforserver-sideprocessing.
TheTextBoxAtextboxiscreatedbymeansofthe<input/>element,muchasthebuttonis,butwiththetypeattributesettotext.Again,youcanchoosenottoincludethevalueattribute,butifyoudo,thisvaluewillappearinsidethetextboxwhenthepageisloaded.
Inthefollowingexamplethe<input/>elementhastwoadditionalattributes,sizeandmaxlength.Thesizeattributedetermineshowmanycharacterswidethetextboxis,andmaxlengthdeterminesthemaximumnumberofcharacterstheusercanenterinthebox.Bothattributesareoptionalandusedefaultsdeterminedbythebrowser.
Forexample,tocreateatextbox10characterswide,withamaximumcharacterlengthof15,andinitiallycontainingthewordsHelloWorld,your<input/>elementwouldbeasfollows:
<inputtype="text"name="myTextBox"size="10"maxlength="15"value="Hello
World"/>
Theobjectthatthiselementcreateshasavalueproperty,whichyoucanuseinyourscriptstosetorreadthetextcontainedinsidethetextbox.Inadditiontothecommonpropertiesandmethodsdiscussedearlier,theobjectrepresentingthetextboxalsohastheselect()method,whichselectsorhighlightsallthetextinsidethetextbox.Thismaybeusediftheuserhasenteredaninvalidvalue,andyoucansetthefocustothetextboxandselectthetextinsideit.Thisthenputstheuser’scursorintherightplacetocorrectthedataandmakesitverycleartotheuserwheretheinvaliddatais.Thevaluepropertyalwaysreturnsastringdatatype,evenifnumbercharactersarebeingentered.Ifyouusethevalueasanumber,JavaScriptnormallydoesaconversionfromastringdatatypetoanumberdatatypeforyou,butthisisnotalwaysthecase.Forexample,JavaScriptwon’tdotheconversioniftheoperationyou’reperformingisvalidforastring.Ifyouhaveaformwithtwotextboxesandyouaddthevaluesreturnedfromthese,JavaScriptconcatenatesratherthanaddsthetwovalues,so1plus1willbe11andnot2.Tofixthis,youneedtoconvertallthevaluesinvolvedtoanumericaldatatype,forexamplebyusingparseInt()orparseFloat()orNumber().However,ifyousubtractthetwovalues,anoperationonlyvalidfornumbers,JavaScriptsays“Aha,thiscanonlybedonewithnumbers,soI’llconvertthevaluestoanumberdatatype.”Therefore,1minus1willbereturnedas0withoutyourhavingtouseparseInt()orparseFloat().Thisisatrickybugtospot,soit’sbesttogetintothehabitofconvertingexplicitlytoavoidproblemslater.
Inadditiontothecommonevents,suchasfocusandblur,thetextboxhasthechange,select,keydown,keypress,andkeyupevents.
Theselecteventfireswhentheuserselectssometextinthetextbox.
Moreusefulisthechangeevent,whichfireswhentheelementlosesfocusif(andonlyif)thevalueinsidethetextboxisdifferentfromthevalueithadwhenitgotthefocus.Thisenablesyoutodothingslikevaliditychecksthatoccuronlyifsomethinghaschanged.
Youcanusethereadonlyattributeofthe<input/>element,orthecorrespondingreadOnlyproperty,topreventthecontentsfrombeingchanged:
<inputtype="text"name="txtReadonly"value="Lookbutdon'tchange"
readonly="readonly">
Thekeypress,keydown,andkeyupeventsfire,astheirnamessuggest,whentheuserpressesakey,whentheuserpressesakeydown,andwhenakeythatispresseddownisletbackup,respectively.
TRYITOUTASimpleFormwithValidationLet’sputalltheinformationontextboxesandbuttonstogetherintoanexample.Inthisexample,youhaveasimpleformconsistingoftwotextboxesandabutton.Thetoptextboxisfortheusers’name,andthesecondisfortheirage.Youdovariousvaliditychecks.Youcheckthevalidityoftheagetextboxwhenitlosesfocus.However,thenameandagetextboxesareonlycheckedtoseeiftheyareemptywhenthebuttonisclicked.ThisexampledoesnotworkproperlyonFirefox;we’lldiscussthisshortly.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example4</title>
</head>
<body>
<formaction=""name="form1">
Pleaseenterthefollowingdetails:
<p>
Name:
<inputtype="text"name="txtName"/>
</p>
<p>
Age:
<inputtype="text"name="txtAge"size="3"maxlength="3"/>
</p>
<p>
<inputtype="button"value="Checkdetails"
name="btnCheckForm">
</p>
</form>
<script>
varmyForm=document.form1;
functionbtnCheckFormClick(e){
vartxtName=myForm.txtName;
vartxtAge=myForm.txtAge;
if(txtAge.value==""||txtName.value==""){
alert("Pleasecompletealloftheform");
if(txtName.value==""){
txtName.focus();
}else{
txtAge.focus();
}
}else{
alert("Thanksforcompletingtheform"+
txtName.value);
}
}
functiontxtAgeBlur(e){
vartarget=e.target;
if(isNaN(target.value)){
alert("Pleaseenteravalidage");
target.focus();
target.select();
}
}
functiontxtNameChange(e){
alert("Hi"+e.target.value);
}
myForm.txtName.addEventListener("change",txtNameChange);
myForm.txtAge.addEventListener("blur",txtAgeBlur);
myForm.btnCheckForm.addEventListener("click",
btnCheckFormClick);
</script>
</body>
</html>
Afteryou’veenteredthetext,savethefileasch11_example4.htmlandloaditintoyourwebbrowser.
InthetextboxshowninFigure11.5,typeyourname.Whenyouleavethetextbox,you’llseeHiyournameappearinanalertbox.
Figure11.5
Enteraninvalidvalueintotheagetextbox,suchasaaaa,andwhenyoutrytoleavethebox,it’lltellyouoftheerrorandsendyoubacktocorrectit.
Finally,clicktheCheckDetailsbuttonandbothtextboxeswillbecheckedtoseethatyouhavecompletedthem.Ifeitherisempty,you’llgetamessagetellingyoutocompletethewholeform,andit’llsendyoubacktotheboxthat’sempty.
Ifeverythingisfilledincorrectly,you’llgetamessagethankingyou,asshowninFigure11.5.
Withinthebodyofthepage,youcreatetheHTMLelementsthatdefineyourform.Insideyourform,whichiscalledform1,youcreatethreeformelementswiththenamestxtName,txtAge,andbtnCheckForm:
<formaction=""name="form1">
Pleaseenterthefollowingdetails:
<p>
Name:
<inputtype="text"name="txtName"/>
</p>
<p>
Age:
<inputtype="text"name="txtAge"size="3"maxlength="3"/>
</p>
<p>
<inputtype="button"value="Checkdetails"
name="btnCheckForm">
</p>
</form>
You’llseethatforthesecondtextbox(thetxtAgetextbox),youhaveincludedthe
sizeandmaxlengthattributesinsidethe<input/>element.Settingthesizeattributeto3givestheuseranideaofhowmuchtextyouareexpecting,andsettingthemaxlengthattributeto3helpsensurethatyoudon’tgetoverlylargenumbersenteredfortheagevalue.
Youregisterlistenersforvariouseventsontheseelements:
varmyForm=document.form1;
myForm.txtName.addEventListener("change",txtNameChange);
myForm.txtAge.addEventListener("blur",txtAgeBlur);
myForm.btnCheckForm.addEventListener("click",btnCheckFormClick);
Thefirsttextbox’schangeeventishandledbythetxtNameChange(),thesecondtextbox’sblureventishandledbytxtAgeBlur(),andthebutton’sclickeventwillcausebtnCheckFormClick()toexecute.Let’slookateachofthesefunctionsinturn,startingwithbtnCheckFormClick().
Thefirstthingyoudoisdefinetwovariables,txtNameandtxtAge,andsetthemtoreference<input/>elementswiththesamenames:
functionbtnCheckFormClick(e){
vartxtName=myForm.txtName;
vartxtAge=myForm.txtAge;
Theseareconveniencevariables,thusreducingthesizeofyourcode(youdon’thavetotypemyForm.txtNameeverytimeyoureferencethetxtNameobject).Itmakesyourcodemorereadableandthereforeeasiertodebug,anditsavestyping.
Aftergettingthereferencetothe<input/>elementobjects,youthenuseitinanifstatementtocheckwhetherthevalueinthetextboxnamedtxtAgeorthetextboxnamedtxtNameactuallycontainsanytext:
if(txtAge.value==""||txtName.value==""){
alert("Pleasecompletealloftheform");
if(txtName.value==""){
txtName.focus();
}else{
txtAge.focus();
}
}
Ifyoudofindanincompleteform,youalerttheuser.Theninaninnerifstatement,youcheckwhichtextboxwasnotfilledin.Yousetthefocustotheoffendingtextbox,sothattheusercanstartfillingitinstraightawaywithouthavingtomovethefocustoitherself.Italsoletstheuserknowwhichtextboxyourprogramrequireshertofillin.Toavoidannoyingyourusers,makesurethattextinthepagetellsthemwhichfieldsarerequired.
Iftheoriginalouterifstatementfindsthattheformiscomplete,itletstheuserknowwithathank-youmessage:
else{
alert("Thanksforcompletingtheform"+txtName.value);
}
}
Inthissortofsituation,it’sprobablymorelikelythatyou’llsubmittheformtotheserverthantolettheuserknowwithathank-youmessage.YoucandothisusingtheFormobject’ssubmit()methodorusinganormalSubmitbutton.
ThenextofthethreefunctionsistxtAgeBlur(),whichhandlestheblureventofthetxtAgetextbox.Thisfunction’spurposeistocheckthatthestringvaluetheuserenteredintotheageboxactuallyconsistsofnumericcharacters:
functiontxtAgeBlur(e){
vartarget=e.target;
Atthestartofthefunction,youretrievethetargetoftheevent(thetxtAgetextbox)andstoreitinthetargetvariable.YoucouldusemyForm.txtAgetoreferencethesametxtAgetextbox,butusingtheEventobject’stargetpropertyisabettersolution.ThetxtAgeBlur()functionworksonlywiththeelementthatreceivedtheblurevent.Assuch,usingtheEventobject’stargetpropertygivesyouageneralizedfunctionthatdoesn’tdependonanyexternalvariables,suchasmyForm.Plus,it’slesstyping.
ThefollowingifstatementcheckstoseewhetherwhathasbeenenteredinthetxtAgetextboxcanbeconvertedtoanumber.YouusetheisNaN()functiontodothisforyou.IfthevalueinthetxtAgetextboxisnotanumber,ittellstheuserandsetsthefocusbacktothetextboxbycallingthefocus()method.Additionally,thistimeyouhighlightthetextbyusingtheselect()method.Thismakesitevenclearertotheuserswhattheyneedtofix.Italsoallowsthemtorectifytheproblemwithoutneedingtodeletetextfirst.
if(isNaN(target.value)){
alert("Pleaseenteravalidage");
target.focus();
target.select();
}
}
Youcouldgofurtherandcheckthatthenumberinsidethetextboxisactuallyavalidage—forexample,191isnotavalidage,noris255likelytobe.Youjustneedtoaddanotherifstatementtocheckforthesepossibilities.
ThisfunctionhandlestheblureventofthetxtAgetextbox,butwhydidn’tyouusethechangeevent,withitsadvantagethatitonlyrechecksthevaluewhenthevaluehasactuallybeenchanged?Thechangeeventwouldnotfireiftheboxwasemptybothbeforefocuswaspassedtoitandafterfocuswaspassedawayfromit.However,leavingthecheckingoftheformcompletionuntiljustbeforetheformissubmittedisprobablybestbecausesomeusersprefertofillininformationoutoforderandcomebacktosomeformelementslater.
ThefinalfunctionisforthetxtNametextbox’schangeevent.Itsusehereisalittleflippantandintendedprimarilyasanexampleofthechangeevent:
functiontxtNameChange(e){
alert("Hi"+e.target.value);
}
Whenthechangeeventfires(whenfocusispassedawayfromthenametextboxanditscontentshavechanged),youtakethevalueoftheeventtarget(again,makinguseofthetargetproperty)andputitintoanalertbox.ItsimplysaysHiyourname.
ProblemswithFirefoxandtheblurEventThepreviousexamplewillfailwithFirefoxifyouenteranameinthenametextboxandthenaninvalidageintotheagebox(forexample,ifyouenterabcandthenclicktheCheckFormbutton).Withotherbrowserstheblureventfiresanddisplaysanalertboxiftheageisinvalid,butthebutton’sclickeventdoesn’tfire.However,inFirefox,botheventsfirewiththeresultthattheinvalidagealertishiddenbythe“formcompletedsuccessfully”alertbox.
Inaddition,ifyouenteraninvalidageandthenswitchtoadifferentprogramaltogether,the“invalidage”alertboxappears,whichisannoyingfortheuser.Itcouldbethattheuserwasopeningupanotherprogramtocheckthedetails.
Althoughthisisafineexample,itisnotgreatfortherealworld.Abetteroptionwouldbetochecktheformwhenit’sfinallysubmittedandnotwhiletheuserisenteringdata.Or,alternatively,youcancheckthedataasitisenteredbutnotuseanalertboxtodisplayerrors.Insteadyoucouldwriteoutawarninginrednexttotheerroneousinputcontrol,informingtheuseroftheinvaliddata,andthenalsogetyourcodetochecktheformwhenit’ssubmitted.
ThePasswordTextBoxTheonlyrealpurposeofthepasswordboxistoenableuserstotypeinapasswordonapageandtohavethepasswordcharactershidden,sothatnoonecanlookovertheuser’sshoulderanddiscoverhisorherpassword.However,thisprotectionisvisualonly.Whensenttotheserver,thetextinthepasswordissentasplaintext—thereisnoencryptionoranyattemptathidingthetext(unlessthepageisservedoverasecureconnectionfromtheserver).
Definingapasswordboxisidenticaltodefiningatextbox,exceptthatthetypeattributeispassword:
<inputname="password1"type="password"/>
Thisformelementcreatesan<input/>elementobjectandhasthesameproperties,methods,andeventsasnormaltextboxes.
TheHiddenTextBoxThehiddentextboxcanholdtextandnumbersjustlikeanormaltextbox,withthedifferencebeingthatit’snotvisibletotheuser.Ahiddenelement?Itmaysoundasusefulasaninvisiblepainting,butinfactitprovestobeveryuseful.
Todefineahiddentextbox,youusethefollowingHTML:
<inputtype="hidden"name="myHiddenElement"/>
Thehiddentextboxcreatesyetanother<input/>elementobject,anditcanbemanipulatedinJavaScriptlikeanyotherobject—although,youcanactuallysetitsvalueonlythroughitsHTMLdefinitionorthroughJavaScript.Aswithanormaltextbox,itsvalueissubmittedtotheserverwhentheusersubmitstheform.
Sowhyarehiddentextboxesuseful?Imagineyouhavealotofinformationthatyouneedtoobtainfromtheuser,buttoavoidhavingapagestuffedfullofelementsandlookinglikethecontrolpanelofthespaceshuttle,youdecidetoobtaintheinformationovermorethanonepage.Theproblemis,howdoyoukeeparecordofwhatwasenteredinpreviouspages?Easy—youusehiddentextboxesandputthevaluesinthere.Then,inthefinalpage,alltheinformationissubmittedtotheserver—it’sjustthatsomeofitishidden.
ThetextareaElementThe<textarea/>elementallowsmulti-lineinputoftext.Otherthanthis,itactsverymuchlikethetextboxelement.
However,unlikethetextbox,the<textarea/>elementhasitsowntag,the<textarea>tag,anditcreatesanHTMLTextAreaElementobject.Italsohastwoadditionalattributes:colsandrows.Thecolsattributedefineshowmanycharacterswidethetextareawillbe,andtherowsattributedefineshowmanycharacterrowstherewillbe.Yousetthetextinsidetheelementbyputtingitbetweenthestartandclosingtags,ratherthanbyusingthevalueattribute.Soifyouwanta<textarea/>element40characterswideby20rowsdeepwithinitialtextHelloWorldonthefirstlineandLine2onthesecondline,youdefineitasfollows:
<textareaname="myTextArea"cols="40"rows="20">HelloWorld
Line2
</textarea>
Anotherattributeofthe<textarea/>elementisthewrapattribute,whichdetermineswhathappenswhentheusertypestotheendofaline.Thedefaultvalueforthisissoft,sotheuserdoesnothavetopressReturnattheendofaline,thoughthiscanvaryfrombrowsertobrowser.Toturnwrappingon,youcanuseoneoftwovalues:softandhard.Asfarasclient-sideprocessinggoes,bothdothesamething:Theyswitchwrappingon.However,whenyoucometoserver-sideprocessing,theydomakeadifferenceintermsofwhichinformationissenttotheserverwhentheformisposted.
Ifyousetthewrapattributeonbysettingittosoft,wrappingwilloccurontheclientside,butthecarriagereturnswon’tbepostedtotheserver,justthetext.Ifthewrapattributeissettohard,anycarriagereturnscausedbywrappingwillbeconvertedtohardreturns—itwillbeasiftheuserhadpressedtheEnterkey,andthesereturnswillbesenttotheserver.Also,youneedtobeawarethatthecarriage-returncharacterisdeterminedbytheoperatingsystemthatthebrowserisrunningon—forexample,inWindowsacarriagereturnis\r\n,onUNIX,UNIX-likesystems,andMacOSX,acarriagereturnis\n.Toturnoffwrappingclient-side,setwraptooff.
NOTEThe\ncharacteristheuniversallinefeedcharacter.Ifyouareformattingrawtextoutputandneedanewline,\nworksineverybrowseroneveryoperatingsystem.
Theobjectcreatedbythe<textarea/>elementhasthesameproperties,methods,andeventsasthetextboxobjectyousawpreviously,exceptthatthetextareadoesn’thavethemaxlengthattribute.Notethatthereisavaluepropertyeventhoughthe<textarea/>elementdoesnothaveavalueattribute.Thevaluepropertysimplyreturnsthetextbetweenthe<textarea>and</textarea>tags.Theeventssupportedbythe<textarea/>elementobjectincludethekeydown,keypress,keyup,andchangeeventhandlers.
TRYITOUTEventWatchingTohelpdemonstratehowthekeydown,keypress,keyup,andchangeeventswork(inparticular,theorderinwhichtheyfire),you’llcreateanexamplethattellsyouwhateventsarefiring:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example5</title>
</head>
<body>
<formaction=""name="form1">
<textarearows="15"cols="40"name="textarea1"></textarea>
<textarearows="15"cols="40"name="textarea2"></textarea>
<br/>
<inputtype="button"value="Cleareventtextarea"
name="button1"/>
</form>
<script>
varmyForm=document.form1;
vartextArea1=myForm.textarea1;
vartextArea2=myForm.textarea2;
varbtnClear=myForm.button1;
functiondisplayEvent(e){
varmessage=textArea2.value;
message=message+e.type+"\n";
textArea2.value=message;
}
functionclearEventLog(e){
textArea2.value="";
}
textArea1.addEventListener("change",displayEvent);
textArea1.addEventListener("keydown",displayEvent);
textArea1.addEventListener("keypress",displayEvent);
textArea1.addEventListener("keyup",displayEvent);
btnClear.addEventListener("click",clearEventLog);
</script>
</body>
</html>
Savethispageasch11_example5.html.Loadthepageintoyourbrowser,andseewhathappenswhenyoutypeanyletterintothefirsttextareabox.Youshouldseetheeventsbeingfiredlistedinthesecondtextareabox(keydown,keypress,andkeyup),asshowninFigure11.6.Whenyouclickoutsidethefirsttextareabox,you’llseethechangeeventfire.
Figure11.6
Experimentwiththeexampletoseewhateventsfireandwhen.
Withinaformcalledform1inthebodyofthepage,youdefinetwotextareasandabutton.Thefirsttextareaistheonewhoseeventsyouaregoingtomonitor:
<formaction=""name="form1">
<textarearows="15"cols="40"name="textarea1"></textarea>
Next,youhaveanemptytextareathesamesizeasthefirst:
<textarearows="15"cols="40"name="textarea2"></textarea>
Finally,youhaveyourbutton:
<inputtype="button"value="Cleareventtextarea"name="button1"/>
</form>
You’llregistereventlistenersforthetextarea1andbutton1elementsinyour
JavaScriptcode.Butfirst,youneedtoretrievethoseelementobjectsfromthedocument.Youdothisverysimplybyusingtheformhierarchy:
varmyForm=document.form1;
vartextArea1=myForm.textarea1;
vartextArea2=myForm.textarea2;
varbtnClear=myForm.button1;
YoustartbycreatingthemyFormvariabletocontainthe<form/>elementobject,andthenyouusethatvariabletoretrievetheotherformelements.Nowthatyouhavetheelementobjects,registeringeventlistenersisaseasyascallingtheaddEventListener()method:
textArea1.addEventListener("change",displayEvent);
textArea1.addEventListener("keydown",displayEvent);
textArea1.addEventListener("keypress",displayEvent);
textArea1.addEventListener("keyup",displayEvent);
btnClear.addEventListener("click",clearEventLog);
Onthefirst<textarea/>element(textArea1),youlistenforthechange,keydown,keypress,andkeyupevents,usingthedisplayEvent()functionasthehandlingfunction.Forthebutton,youlistenfortheclickeventwiththeclearEventLog()function.
Thelatterfunctionisthesimplest,solet’slookatthatfirst:
functionclearEventLog(e){
textArea2.value="";
}
ThepurposeofclearEventLog()istoclearthecontentsofthesecond<textarea/>element,anditachievesthisbysettingthe<textarea/>element’svaluepropertytoanemptystring("").
Nowlet’slookatthedisplayEvent()function.Itaddsthenameoftheeventthatoccurredtothetextalreadycontainedinthesecondtextarea:
functiondisplayEvent(e){
varmessage=textArea2.value;
message=message+e.type+"\n";
Youfirstretrievethe<textarea/>element’svalueandstoreitinthemessagevariable.Youthenappendthenameoftheeventaswellasanewlinetothemessage.Puttingeacheventnameonaseparatelinemakesitmucheasiertoreadandfollow.
Thenfinally,youassignthenewmessagetothetextarea’svalueproperty:
textArea2.value=message;
}
CheckBoxesandRadioButtons
Thediscussionsofcheckboxesandradiobuttonsaretogetherbecausetheirobjectshaveidenticalproperties,methods,andevents.Acheckboxenablestheusertocheckanduncheckit.Itissimilartothepapersurveysyoumaygetwhereyouareaskedto“checktheboxesthatapplytoyou.”Radiobuttonsarebasicallyagroupofcheckboxeswhereonlyonecanbecheckedatatime.Ofcourse,theyalsolookdifferent,andtheirgroupnaturemeansthattheyaretreateddifferently.
Creatingcheckboxesandradiobuttonsrequiresouroldfriendthe<input/>element.Itstypeattributeissetto"checkbox"or"radio"todeterminewhichboxorbuttoniscreated.Tosetacheckboxoraradiobuttontobecheckedwhenthepageisloaded,yousimplyinserttheattributecheckedintothe<input>tagandassignitsvalueaschecked.Thisishandyifyouwanttosetadefaultoptionlike,forexample,those“Checkthisboxifyouwantourjunkmail”formsyouoftenseeontheNet,whichareusuallycheckedbydefault,forcingyoutouncheckthem.Sotocreateacheckboxthatisalreadychecked,your<input>tagwillbethefollowing:
<inputtype="checkbox"name="chkDVD"checked="checked"value="DVD"/>
Tocreateacheckedradiobutton,the<input>tagwouldbeasfollows:
<inputtype="radio"name="radCPUSpeed"checked="checked"value="1GHz"/>
Aspreviouslymentioned,radiobuttonsaregroupelements.Infact,thereislittlepointinputtingjustoneonapage,becausetheuserwon’tbeabletochoosebetweenanyalternativeboxes.
Tocreateagroupofradiobuttons,yousimplygiveeachradiobuttonthesamename.Thiscreatesanarrayofradiobuttonsgoingbythatnamethatyoucanaccess,asyouwouldwithanyarray,usingitsindex.
Forexample,tocreateagroupofthreeradiobuttons,yourHTMLwouldbeasfollows:
<inputtype="radio"name="radCPUSpeed"checked="checked"value="800mhz"/>
<inputtype="radio"name="radCPUSpeed"value="1ghz"/>
<inputtype="radio"name="radCPUSpeed"value="1.5ghz"/>
Youcanputasmanygroupsofradiobuttonsinaformasyouwant,byjustgivingeachgroupitsownuniquename.Notethatyouhaveonlyusedonecheckedattribute,becauseonlyoneoftheradiobuttonsinthegroupcanbechecked.Ifyouhadusedthecheckedattributeinmorethanoneoftheradiobuttons,onlythelastofthesewouldhaveactuallybeenchecked.
Usingthevalueattributeofthecheckboxandradiobuttonelementsisnotthesameaswithpreviouselementsyou’velookedat.Ittellsyounothingabouttheuser’sinteractionwithanelementbecauseit’spredefinedinyourHTMLorbyyourJavaScript.Whetheracheckboxorradiobuttonischeckedornot,itstillreturnsthesamevalue.
EachcheckboxhasanassociatedCheckboxobject,andeachradiobuttoninagrouphasaseparateRadioobject.Asmentionedearlier,withradiobuttonsofthesamenameyoucanaccesseachRadioobjectinagroupbytreatingthegroupofradiobuttonsasanarray,withthenameofthearraybeingthenameoftheradiobuttonsinthegroup.Aswithanyarray,youhavethelengthproperty,whichwilltellyouhowmanyradiobuttonsareinthe
group.
NOTEThereactuallyaren’tobjectscalledCheckboxandRadio.All<input/>elementscreateanobjectoftypeHtmlInputElement.Butforthesakeofclarity,thistextusesCheckboxandRadiotomakeexplanationseasiertofollowandunderstand.
Fordeterminingwhetherauserhasactuallycheckedoruncheckedacheckbox,youneedtousethecheckedpropertyoftheCheckboxobject.Thispropertyreturnstrueifthecheckboxiscurrentlycheckedandfalseifnot.
Radiobuttonsareslightlydifferent.Becauseradiobuttonswiththesamenamearegroupedtogether,youneedtotesteachRadioobjectinthegroupinturntoseeifithasbeenchecked.Onlyoneoftheradiobuttonsinagroupcanbechecked,soifyoucheckanotheroneinthegroup,thepreviouslycheckedonewillbecomeunchecked,andthenewonewillbecheckedinitsplace.
BothCheckboxandRadiohavetheclick,focus,andblurevents,andtheseoperateidenticallytotheotherelements,althoughtheycanalsobeusedtocancelthedefaultaction,suchasclickingthecheckboxorradiobutton.
Scriptingcheckboxandradiobuttonsusuallyautomaticallyaddsextrastufftoyourcode—namelyloopsbecauseyouareworkingwithmultiple,near-identicalelements.Thenextexampledemonstratesthis.
TRYITOUTCheckBoxesandRadioButtonsLet’slookatanexamplethatmakesuseofalltheproperties,methods,andeventswehavejustdiscussed.Theexampleisasimpleformthatenablesausertobuildacomputersystem.Perhapsitcouldbeusedinane-commercesituation,tosellcomputerswiththeexactspecificationsdeterminedbythecustomer.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example6</title>
</head>
<body>
<formaction=""name="form1">
<p>
Tickallofthecomponentsyouwantincludedonyour
computer
</p>
<p>
<labelfor="chkDVD">DVD-ROM</label>
<inputtype="checkbox"id="chkDVD"name="chkDVD"
value="DVD-ROM"/>
</p>
<p>
<labelfor="chkBluRay">Blu-ray</label>
<inputtype="checkbox"id="chkBluRay"name="chkBluRay"
value="Blu-ray"/>
</p>
<p>
Selecttheprocessorspeedyourequire
</p>
<p>
<inputtype="radio"name="radCpuSpeed"checked="checked"
value="3.2ghz"/>
<label>3.2GHz</label>
<inputtype="radio"name="radCpuSpeed"value="3.7ghz"/>
<label>3.7GHz</label>
<inputtype="radio"name="radCpuSpeed"value="4.0ghz"/>
<label>4.0GHz</label>
</p>
<inputtype="button"value="Checkform"name="btnCheck"/>
</form>
<script>
varmyForm=document.form1;
functiongetSelectedSpeedValue(){
varradios=myForm.radCpuSpeed;
for(varindex=0;index<radios.length;index++){
if(radios[index].checked){
returnradios[index].value;
}
}
return"";
}
functionfindIndexOfSpeed(radio){
varradios=myForm.radCpuSpeed;
for(varindex=0;index<radios.length;index++){
if(radios[index]==radio){
returnindex;
}
}
return-1;
}
functionradCpuSpeedClick(e){
varradIndex=findIndexOfSpeed(e.target);
if(radIndex==1){
e.preventDefault();
alert("Sorrythatprocessorspeediscurrently
unavailable");
//tofixanissuewithIE
myForm.radCpuSpeed[0].checked=true;
}
}
functionbtnCheckClick(){
varnumberOfControls=myForm.length;
varcompSpec="Yourchosenprocessorspeedis";
compSpec=compSpec+getSelectedSpeedValue();
compSpec=compSpec+"\nWiththefollowingadditional
components:\n";
for(varindex=0;index<numberOfControls;index++){
varelement=myForm[index];
if(element.type=="checkbox"){
if(element.checked){
compSpec=compSpec+element.value+"\n";
}
}
}
alert(compSpec);
}
for(varindex=0;index<myForm.radCpuSpeed.length;index++)
{
myForm.radCpuSpeed[index].addEventListener("click",
radCpuSpeedClick);
}
myForm.btnCheck.addEventListener("click",btnCheckClick);
</script>
</body>
</html>
Savethepageasch11_example6.htmlandloaditintoyourwebbrowser.YoushouldseeaformliketheoneshowninFigure11.7.
Figure11.7
Checksomeofthecheckboxes,changetheprocessorspeed,andclicktheCheckFormbutton.Amessageboxappearsandliststhecomponentsandprocessorspeedyouselected.Forexample,ifyouselectaDVD-ROManda4.0GHzprocessorspeed,youwillseesomethinglikewhatisshowninFigure11.8.
Figure11.8
Notethatthe3.7GHzprocessorisoutofstock,soifyouchoosethat,amessagebox
tellsyouit’soutofstock,andthe3.2GHzprocessorspeedradiobuttonwon’tbeselected.Theprevioussettingwillberestoredwhentheuserdismissesthemessagebox.
Let’sfirstlookatthebodyofthepage,whereyoudefinethecheckboxesandradiobuttonsandastandardbuttoninsideaformcalledform1.Youstartwiththecheckboxes:
<p>
Tickallofthecomponentsyouwantincludedonyourcomputer
</p>
<p>
<labelfor="chkDVD">DVD-ROM</label>
<inputtype="checkbox"id="chkDVD"name="chkDVD"value="DVD-ROM"/>
</p>
<p>
<labelfor="chkBluRay">Blu-ray</label>
<inputtype="checkbox"id="chkBluRay"name="chkBluRay"value="Blu-
ray"/>
</p>
Eachcheckboxhasalabelandiscontainedwithina<p/>elementforformattingpurposes.
NextcometheradiobuttonsforselectingtherequiredCPUspeed.Again,eachhasalabel,butunlikethecheckboxes,theseradiobuttonsarecontainedwithinasingle<p/>element:
<p>
Selecttheprocessorspeedyourequire
</p>
<p>
<inputtype="radio"name="radCpuSpeed"checked="checked"
value="3.2ghz"/>
<label>3.2GHz</label>
<inputtype="radio"name="radCpuSpeed"value="3.7ghz"/>
<label>3.7GHz</label>
<inputtype="radio"name="radCpuSpeed"value="4.0ghz"/>
<label>4.0GHz</label>
</p>
TheradiobuttongroupnameisradCpuSpeed.Here,thefirstoneissettobecheckedbydefaultbytheinclusionofthecheckedattributeinsidethe<input/>element’sdefinition.It’sagoodideatoensurethatyouhaveoneradiobuttoncheckedbydefault,becauseifyoudonotandtheuserdoesn’tselectabutton,theformwillbesubmittedwithnovalueforthatradiogroup.
Next,thestandardbuttonthatcompletesyourform:
<inputtype="button"value="Checkform"name="btnCheck"/>
Beforeproceedingfurther,anote:TomaketheJavaScriptcodeeasier,youcoulduse
theonclickattributesoneachoftheradiobuttonsaswellasthestandardbutton.ButasmentionedinChapter10,youwanttoavoidthoseattributesasmuchaspossiblebecauseitcouplesyourHTMLandJavaScripttogether.
Twofunctionsareusedtohandletheclickeventsforthestandardbuttonandtheradiobuttons:btnCheckClick()andradCpuSpeedClick(),respectively.Andbeforewelookatthesefunctions,youfirstneedtoregistertheclickeventlistenersontheirrespectiveelements.Asinpreviousexamples,firstcreateavariablecalledmyFormtoreferencetheforminthedocument:
varmyForm=document.form1;
Now,registertheclickeventlisteneronyourradiobuttons.Unfortunately,there’snomagicalcommandthatsays“usethisfunctiontohandlealltheradiobuttons’clickevents.”So,you’llhavetocalladdEventListener()oneveryRadioobject.Thisisn’tasdifficultasitsounds;aforloopwillhelpyou:
for(varindex=0;index<myForm.radCpuSpeed.length;index++){
myForm.radCpuSpeed[index].addEventListener("click",
radCpuSpeedClick);
}
Thisforloopisfairlystraightforwardexceptforonething:myForm.radCpuSpeed.WhatyouaredoinghereisusingthecollectionfortheradCpuSpeedradiogroup.Eachelementinthecollectionactuallycontainsanobject,namelyeachofyourthreeRadioobjects.Therefore,you’reloopingovertheRadioobjectsintheradCpuSpeedradiogroup,retrievingtheRadioobjectatthegivenindex,andcallingitsaddEventListener()method.
Next,registertheeventlistenerfortheform’sstandardbutton:
myForm.btnCheck.addEventListener("click",btnCheckClick);
Nowlet’slookattheradCpuSpeedClick()function,thefunctionthatexecuteswhentheradiobuttonsareclicked.ThefirstthingthisfunctionneedstodoistofindtheindexoftheeventtargetintheradCpuSpeedradiogroup:
functionradCpuSpeedClick(e){
varradIndex=findIndexOfSpeed(e.target);
YoudothisbycallingthefindIndexOfSpeed()helperfunction.We’lllookatthisfunctionlater,butfornow,justknowthatitfindstheindexofthesuppliedRadioobjectinthemyForm.radCpuSpeedcollection.
Thedefaultactionofclickingaradiobuttonistochecktheradiobutton.Ifyoupreventthedefaultactionfromoccurring,theradiobuttonwillnotbechecked.Asanexampleofthisinaction,youhaveanifstatementonthenextline.Iftheradiobutton’sindexvalueis1(thatis,iftheusercheckedtheboxfora3.7GHzprocessor),youtelltheuserthatit’soutofstockandcanceltheclickingactionbycallingtheEventobject’spreventDefault()method:
if(radIndex==1){
e.preventDefault();
alert("Sorrythatprocessorspeediscurrentlyunavailable");
Aspreviouslymentioned,cancelingtheclickingactionresultsintheradiobuttonnotbeingchecked.Insuchasituation,allbrowsers(exceptforIE)recheckthepreviouslycheckedradiobutton.IE,however,removesallchecksfromtheradiogroup.Torectifythis,youresettheradiogroup:
//tofixanissuewithIE
myForm.radCpuSpeed[0].checked=true;
}
}
YouonceagainusethemyForm.radCpuSpeedcollection,retrievetheRadioobjectatindex0,andsetitscheckedpropertytotrue.Let’stakeamomentandlookatthefindIndexOfSpeed()helpermethod.ItacceptsaRadioobjectasanargument,anditsearchesthemyForm.radCpuSpeedcollectionforthegivenRadioobject.
Thefirstlineofthefunctioncreatesavariablecalledradios,anditcontainsareferencetothemyForm.radCpuSpeedcollection.Thisistomaketypingandreadingabiteasier:
functionfindIndexOfSpeed(radio){
varradios=myForm.radCpuSpeed;
Next,youwanttoloopthroughtheradioscollectionanddetermineifeachRadioobjectinthecollectionisthesameRadioobjectintheradiovariable:
for(varindex=0;index<radios.length;index++){
if(radios[index]==radio){
returnindex;
}
}
return-1;
}
Ifyoufindamatch,youreturnthevalueoftheindexvariable.Iftheloopexitswithoutfindingamatch,youreturn-1.ThisbehaviorisconsistentwiththeStringobject’sindexOf()method.Consistencyisaverygoodthing!
Thenextfunction,btnCheckClick(),executeswhenthestandardbutton’sclickeventfires.Inareale-commercesituation,thisbuttonwouldbetheplacewhereyou’dcheckyourformandthensubmitittotheserverforprocessing.Hereyouusetheformtoshowamessageboxconfirmingwhichboxesyouhavechecked(asifyoudidn’talreadyknow)!
Atthetopyoudeclaretwolocalvariablestouseinthefunction.ThevariablenumberOfControlsissettotheform’slengthproperty,whichisthenumberofelementsontheform.ThevariablecompSpecisusedtobuildthestringthatyou’lldisplayinamessagebox:
functionbtnCheckClick(){
varnumberOfControls=myForm.length;
varcompSpec="Yourchosenprocessorspeedis";
Inthefollowingline,youaddthevalueoftheradiobuttontheuserhasselectedtoyourmessagestring:
compSpec=compSpec+findSelectedSpeedValue();
compSpec=compSpec+"\nWiththefollowingadditional
components:\n";
YouuseyetanotherhelperfunctioncalledgetSelectedSpeedValue().Asitsnameimplies,itgetsthevalueoftheselectedRadioobject.You’lllookatitscodelater.
Next,youloopthroughtheform’selements:
for(varindex=0;index<numberOfControls;index++){
varelement=myForm[index];
if(element.type=="checkbox"){
if(element.checked){
compSpec=compSpec+element.value+"\n";
}
}
}
alert(compSpec);
}
It’sherethatyouloopthrougheachelementontheformusingmyForm[controlIndex],whichreturnsareferencetotheelementobjectstoredatthecontrolIndexindexposition.
You’llseethatinthisexampletheelementvariableissettoreferencetheobjectstoredinthemyFormcollectionattheindexpositionstoredinvariablecontrolIndex.Again,thisisforconvenientshorthandpurposes;nowtousethatparticularobject’spropertiesormethods,youjusttypeelement,aperiod,andthenthemethodorpropertyname,makingyourcodeeasiertoreadanddebug,whichalsosavesontyping.
Youonlywanttoseewhichcheckboxeshavebeenchecked,soyouusethetypeproperty,whicheveryHTMLformelementobjecthas,toseewhatelementtypeyouaredealingwith.Ifthetypeischeckbox,yougoaheadandseeifit’sacheckedcheckbox.Ifso,youappenditsvaluetothemessagestringincompSpec.Ifitisnotacheckbox,itcanbesafelyignored.
Finally,youusethealert()methodtodisplaythecontentsofyourmessagestring.
ThelastfunctionisgetSelectedSpeedValue().Itdoesn’tacceptanyarguments,althoughyoucouldgeneralizethisfunctiontoacceptacollectionofRadioobjects.Doingsowouldallowyoutoreusethefunctioninmultipleprojects.
Buttogetbacktotheactualcode,thefirststatementofthefunctioncreatesaradiosvariablethatcontainsareferencetothemyForm.radCpuSpeedcollection:
functiongetSelectedSpeedValue(){
varradios=myForm.radCpuSpeed;
Next,youwanttofindtheselectedRadioobjectandretrieveitsvalue.Youcandothiswithyetanotherforloop:
for(varindex=0;index<radios.length;index++){
if(radios[index].checked){
returnradios[index].value;
}
}
return"";
}
Thelogicisstraightforward:LoopthroughtheradioscollectionandcheckeachRadioobject’scheckedproperty.Ifit’strue,returnthevalueofthatRadioobject,butiftheloopexitswithoutfindingacheckedRadioobject,youreturnanemptystring.
SelectionBoxesAlthoughtheylookquitedifferent,thedrop-downlistandthelistboxesareactuallybothelementscreatedwiththe<select>tag,andstrictlyspeakingtheyarebothselectelements.Theselectelementhasoneormoreoptionsinalistthatyoucanselectfrom;eachoftheseoptionsisdefinedbymeansofoneormore<option/>elementsinsidetheopeningandclosing<select>tags.
Thesizeattributeofthe<select/>elementisusedtospecifyhowmanyoftheoptionsarevisibletotheuser.
Forexample,tocreatealistboxfiverowsdeepandpopulateitwithsevenoptions,yourHTMLwouldlooklikethis:
<selectname="theDay"size="5">
<optionvalue="0"selected="selected">Monday</option>
<optionvalue="1">Tuesday</option>
<optionvalue="2">Wednesday</option>
<optionvalue="3">Thursday</option>
<optionvalue="4">Friday</option>
<optionvalue="5">Saturday</option>
<optionvalue="6">Sunday</option>
</select>
Noticethatthe<option/>elementforMondayalsocontainstheattributeselected;thiswillmakethisoptionselectedbydefaultwhenthepageisloaded.Thevaluesoftheoptionshavebeendefinedasnumbers,buttextwouldbeequallyvalid.
Ifyouwantthistobeadrop-downlist,youjustneedtochangethesizeattributeinthe<select/>elementto1,andpresto,it’sadrop-downlist.
Ifyouwanttolettheuserchoosemorethanoneitemfromalistatonce,yousimplyneedtoaddthemultipleattributetothe<select/>definition.
The<select/>elementcreatesanHTMLSelectElementobject(herebyknownasSelect).
Thisobjecthasanoptionscollectionproperty,whichismadeupofHtmlOptionElement(herebyknownasOption)objects,oneforeach<option/>elementinsidethe<select/>elementassociatedwiththeSelectobject.Forinstance,intheprecedingexample,ifthe<select/>elementwascontainedinaformcalledtheFormwiththefollowing:
document.theForm.theDay.options[0]
youwouldaccesstheoptioncreatedforMonday.
Howcanyoutellwhichoptionhasbeenselectedbytheuser?Easy:youusetheSelectobject’sselectedIndexproperty.Youcanusetheindexvaluereturnedbythispropertytoaccesstheselectedoptionusingtheoptionscollection.
TheOptionobjectalsohasindex,text,andvalueproperties.Theindexpropertyreturnstheindexpositionofthatoptionintheoptionscollection.Thetextpropertyiswhat’sdisplayedinthelist,andthevaluepropertyisthevaluedefinedfortheoption,whichwouldbepostedtotheserveriftheformweresubmitted.
Ifyouwanttofindouthowmanyoptionsareinaselectelement,youcanusethelengthpropertyofeithertheSelectobjectitselforofitsoptionscollectionproperty.
Let’sseehowyoucouldloopthroughtheoptionsfortheprecedingselectbox:
vartheDayElement=document.theForm.theDay;
document.write("Thereare"+theDayElement.length+"options<br/>");
for(varindex=0;index<theDayElement.length;index++){
document.write("Optiontextis"+
theDayElement.options[index].text);
document.write("anditsvalueis");
document.write(theDayElement.options[index].value);
document.write("<br/>");
}
First,yousetthevariabletheDayElementtoreferencetheSelectobject.Thenyouwritethenumberofoptionstothepage,inthiscase7.
Nextyouuseaforlooptoloopthroughtheoptionscollection,displayingthetextofeachoption,suchasMonday,Tuesday,andsoon,anditsvalue,suchas0,1,andsoon.Ifyoucreateapagebasedonthiscode,itmustbeplacedafterthe<select/>element’sdefinition.
It’salsopossibletoaddoptionstoaselectelementafterthepagehasfinishedloading.Youlookathowtodothisnext.
AddingandRemovingOptionsToaddanewoptiontoaselectelement,yousimplycreateanewOptionobjectusingthenewoperatorandtheninsertitintotheoptionscollectionoftheSelectobjectatanemptyindexposition.
WhenyoucreateanewOptionobject,youhavetwoparameterstopass.Thefirstisthetextyouwanttoappearinthelist,andthesecondisthevaluetobeassignedtotheoption:
varmyNewOption=newOption("TheText","TheValue");
YouthensimplyassignthisOptionobjecttoanemptyarrayelement.Forexample:
theDayElement.options[0]=myNewOption;
Ifyouwanttoremoveanoption,yousimplysetthatpartoftheoptionscollectiontonull.Forexample,toremovetheelementyoujustinserted,youneedthefollowing:
theDayElement.options[0]=null;
WhenyouremoveanOptionobjectfromtheoptionscollection,thecollectionisreorderedsothatthearrayindexvalueofeachoftheoptionsabovetheremovedonehasitsindexvaluedecrementedbyone.
Whenyouinsertanewoptionatacertainindexposition,beawarethatitwilloverwriteanyOptionobjectthatisalreadythere.
TRYITOUTAddingandRemovingListOptionsInthisTryItOut,youusethelist-of-daysexampleyousawpreviouslytodemonstrateaddingandremovinglistoptions.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example7</title>
</head>
<body>
<formaction=""name="theForm">
<selectname="theDay"size="5">
<optionvalue="0"selected="selected">Monday</option>
<optionvalue="1">Tuesday</option>
<optionvalue="2">Wednesday</option>
<optionvalue="3">Thursday</option>
<optionvalue="4">Friday</option>
<optionvalue="5">Saturday</option>
<optionvalue="6">Sunday</option>
</select>
<br/>
<inputtype="button"value="RemoveWednesday"
name="btnRemoveWed"/>
<inputtype="button"value="AddWednesday"name="btnAddWed"/>
<br/>
</form>
<script>
vartheForm=document.theForm;
functionbtnRemoveWedClick(){
varoptions=theForm.theDay.options;
if(options[2].text=="Wednesday"){
options[2]=null;
}else{
alert("ThereisnoWednesdayhere!");
}
}
functionbtnAddWedClick(){
varoptions=theForm.theDay.options;
if(options[2].text!="Wednesday"){
varlastOption=newOption();
options[options.length]=lastOption;
for(varindex=options.length-1;index>2;
index––){
varcurrentOption=options[index];
varpreviousOption=options[index-1];
currentOption.text=previousOption.text;
currentOption.value=previousOption.value;
}
varoption=newOption("Wednesday",2);
options[2]=option;
}else{
alert("DoyouwanttohaveTWOWednesdays?");
}
}
theForm.btnRemoveWed.addEventListener("click",
btnRemoveWedClick);
theForm.btnAddWed.addEventListener("click",btnAddWedClick);
</script>
</body>
</html>
Savethisasch11_example7.html.Ifyoutypethepageinandloaditintoyourbrowser,youshouldseetheformshowninFigure11.9.ClicktheRemoveWednesdaybutton,andyou’llseeWednesdaydisappearfromthelist.AdditbackbyclickingtheAddWednesdaybutton.IfyoutrytoaddasecondWednesdayorremoveanonexistentWednesday,you’llgetapolitewarningtellingyouthatyoucan’tdothat.
Figure11.9
Withinthebodyofthepage,youdefineaformwiththenametheForm.Thiscontainsthe<select/>element,whichincludesday-of-the-weekoptionsthatyouhaveseenpreviously.Theformalsocontainstwobuttons,asshownhere:
<inputtype="button"value="RemoveWednesday"name="btnRemoveWed"/>
<inputtype="button"value="AddWednesday"name="btnAddWed"/>
YouwanttoexecuteJavaScriptcodewhenthesebuttonsareclicked;therefore,youwanttoregisterclickeventlistenersforeachofthebuttons.Tomakethisabiteasier,youfirstcreateavariablecalledtheForm,whichcontainsthe<form/>elementobject:
vartheForm=document.theForm;
Youusethisvariabletoaccesstheindividualbuttonsandregistertheirclickeventlisteners:
theForm.btnRemoveWed.addEventListener("click",btnRemoveWedClick);
theForm.btnAddWed.addEventListener("click",btnAddWedClick);
The“remove”buttonexecutesthebtnRemoveWedClick()function,andthe“add”buttonexecutesbtnAddWedClick().Youtakealookateachofthesefunctionsinturn.
Thefirstfunction,btnRemoveWedClick(),removestheWednesdayoption:
functionbtnRemoveWedClick(){
varoptions=theForm.theDay.options;
if(options[2].text=="Wednesday"){
options[2]=null;
}else{
alert("ThereisnoWednesdayhere!");
}
}
ThefirstthingyoudointhefunctioniscreateavariablethatcontainsthecollectionofOptionelements.Thisletsyourepeatedlyreferencetheoptioncollectionwithouttypingdocument.theForm.theDay.options,oranyvariationthereof.
Next,asanitycheck:YoumusttrytoremovetheWednesdayoptiononlyifit’sthereinthefirstplace!Youmakesureofthisbyseeingifthethirdoptioninthecollection(withindex2becausearraysstartatindex0)hasthetext"Wednesday".Ifitdoes,youcanremovetheWednesdayoptionbysettingthatparticularoptiontonull.IfthethirdoptioninthearrayisnotWednesday,youalerttheusertothefactthatthereisnoWednesdaytoremove.Althoughthiscodeusesthetextpropertyintheifstatement’scondition,youcouldjustaseasilyhaveusedthevalueproperty;itmakesnodifference.
NextyoucometothebtnAddWedClick()function,which,asthenamesuggests,addstheWednesdayoption.Thisisslightlymorecomplexthanthecoderequiredtoremoveanoption.First,youcreateanothervariable,calledoptions,tocontainthecollectionofOptionobjects.Then,youuseanifstatementtocheckthatthereisnotalreadyaWednesdayoption:
functionbtnAddWedClick(){
varoptions=theForm.theDay.options;
if(options[2].text!="Wednesday"){
varlastOption=newOption();
options[options.length]=lastOption;
for(varindex=options.length-1;index>2;index––){
varcurrentOption=options[index];
varpreviousOption=options[index-1];
currentOption.text=previousOption.text;
currentOption.value=previousOption.value;
}
IfthereisnoWednesdayoption,youthenneedtomakespaceforthenewWednesdayoptiontobeinserted.
Atthispoint,youhavesixoptions(thelastelementisasindex5),sonextyoucreateanewoptionwiththevariablenamelastOptionandassignittotheelementattheendofthecollection.Thisnewelementisassignedatindexposition6byusingthelengthpropertyoftheoptionscollection,whichpreviouslyhadnocontents.YounextassignthetextandvaluepropertiesofeachoftheOptionobjectsfromThursdaytoSundaytotheOptionatanindexvaluehigherbyoneintheoptionsarray,leavingaspaceintheoptionsarrayatposition2toputWednesdayin.Thisisthetaskfortheforloopwithintheifstatement.
Next,youcreateanewOptionobjectbypassingthetext"Wednesday"andthevalue
2totheOptionconstructor.TheOptionobjectistheninsertedintotheoptionscollectionatposition2,andpresto,itappearsinyourselectbox.
varoption=newOption("Wednesday",2);
options[2]=option;
}
YouendthefunctionbyalertingtheusertothefactthatthereisalreadyaWednesdayoptioninthelist,iftheconditionintheifstatementisfalse:
else{
alert("DoyouwanttohaveTWOWednesdays?");
}
}
Thisexampleworksineverybrowser;however,allmodernbrowsersprovideadditionalmethodstomakeaddingandremovingoptionseasier.
AddingNewOptionswithStandardMethodsInparticular,theSelectobjectyouareinterestedinhasadditionaladd()andremove()methods,whichaddandremoveoptions.Thesemakelifealittlesimpler.
Beforeyouaddanoption,youneedtocreateit.Youdothisjustasbefore,usingthenewoperator.
TheSelectobject’sadd()methodenablesyoutoinsertanOptionobjectthatyouhavecreatedandacceptstwoparameters.ThefirstparameteristheOptionobjectyouwanttoadd.ThesecondparameteristheOptionobjectyouwanttoplacethenewOptionobjectbefore.However,inIE7(orIE8non-standardsmode),thesecondparameteristheindexpositionatwhichyouwanttoaddtheoption.Inallbrowsers,youcanpassnullasthesecondparameter,andtheaddedOptionobjectwillbeaddedattheendoftheoptionscollection.
Theadd()methodwon’toverwriteanyOptionobjectalreadyatthatposition,butinsteadwillsimplymovetheOptionobjectsupinthecollectiontomakespace.ThisisbasicallythesameaswhatyouhadtocodeintothebtnAddWedClick()functionusingyourforloop.
Usingtheadd()method,youcanrewritethebtnAddWedClick()functioninch11_example7.htmltolooklikethis:
functionbtnAddWedClick(){
vardays=theForm.theDay;
varoptions=days.options;
if(options[2].text!="Wednesday"){
varoption=newOption("Wednesday",2);
varthursdayOption=options[2];
try{
days.add(option,thursdayOption);
}
catch(error){
days.add(option,2);
}
}else{
alert("DoyouwanttohaveTWOWednesdays?");
}
}
InIE7(orIE8innon-standardsmode),thebrowserwillthrowanerrorifyoupassanOptionobjectasthesecondparameter.Souseatry…catchstatementtocatchtheerrorandpassanumbertothesecondargument,asthiscodeshows.
TheSelectobject’sremove()methodacceptsjustoneparameter,namelytheindexoftheoptionyouwantremoved.Whenanoptionisremoved,theoptionsathigherindexpositionsaremoveddowninthecollectiontofillthegap.
Usingtheremove()method,youcanrewritethebtnRemoveWedClick()functioninch11_example7.htmltolooklikethis:
functionbtnRemoveWedClick(){
vardays=theForm.theDay;
if(days.options[2].text=="Wednesday"){
days.remove(2);
}else{
alert("ThereisnoWednesdayhere!");
}
}
Modifythepreviousexampleandsaveitasch11_example8.htmlbeforeloadingitintoyourbrowser.You’llseethatitworksjustasthepreviousversiondid.
SelectElementEventsSelectelementshavethreeevents:blur,focus,andchange.You’veseenalltheseeventsbefore.Yousawthechangeeventwiththetextboxelement,whereitfiredwhenfocuswasmovedawayfromthetextboxandthevalueinthetextboxhadchanged.Hereitfireswhentheuserchangeswhichoptioninthelistisselected.
TRYITOUTWorldTimeConverterLet’stakealookatanexamplethatusesthechangeevent.TheWorldTimeConverterletsyoucalculatethetimeindifferentcountries:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example9</title>
</head>
<body>
<div>LocalTimeis<spanid="spanLocalTime"></span></div>
<divid="divCityTime"></div>
<formname="form1">
<selectsize="5"name="lstCity">
<optionvalue="60"selected>Berlin
<optionvalue="330">Bombay
<optionvalue="0">London
<optionvalue="180">Moscow
<optionvalue="-300">NewYork
<optionvalue="60">Paris
<optionvalue="-480">SanFrancisco
<optionvalue="600">Sydney
</select>
<p>
<inputtype="checkbox"id="chkDst"name="chkDst"/>
<labelfor="chkDst">AdjustcitytimeforDaylight
Savings</label>
</p>
</form>
<script>
varmyForm=document.form1;
functionupdateTimeZone(){
varlstCity=myForm.lstCity;
varselectedOption=
lstCity.options[lstCity.selectedIndex];
varoffset=selectedOption.value;
varselectedCity=selectedOption.text;
vardstAdjust=0;
if(myForm.chkDst.checked){
dstAdjust=60;
}
updateOutput(selectedCity,offset,dstAdjust);
}
functionupdateOutput(selectedCity,offset,dstAdjust){
varnow=newDate();
document.getElementById("spanLocalTime")
.innerHTML=now.toLocaleString();
now.setMinutes(now.getMinutes()+now.getTimezoneOffset()+
parseInt(offset,10)+dstAdjust);
varresultsText=selectedCity+"timeis"+
now.toLocaleString();
document.getElementById("divCityTime").innerHTML=
resultsText;
}
myForm.lstCity.addEventListener("change",updateTimeZone);
myForm.chkDst.addEventListener("click",updateTimeZone);
updateTimeZone();
</script>
</body>
</html>
Savethisasch11_example9.html.Openthepageinyourbrowser.
TheformlayoutlookssomethingliketheoneshowninFigure11.10.Whenevertheuserclicksacityinthelist,herlocaltimeandtheequivalenttimeintheselectedcityareshown.IntheexampleshowninFigure11.10,thelocalregionissettoCentralStandardTimeintheU.S.,andtheselectedcityisBerlin,withthedaylightsavingsboxchecked.
Figure11.10
It’sworthpointingoutthatthisisjustanexampleandnotatotallyfoolproofone,becauseoftheproblemspresentedbydaylightsavings.Somelocationsdon’thaveit,othersdoatfixedtimesofyear,andyetothersdobutatvaryingtimesoftheyear.Thismakesitdifficulttopredictaccuratelywhenacountrywillhaveitsdaylightsavingsperiod.Youhavetriedtosolvethisproblembyaddingacheckboxfortheusertoclickifthecityshechoosesfromthelistisusingdaylightsavingshours(whichyouassumewillputthetimeinthecityforwardbyonehour).
Inaddition,don’tforgetthatsomeusersmaynotevenhavetheirregionalsettingssetcorrectly—there’snoeasywayaroundthisproblem.
Inthebodyofthispageisapairof<div/>elementsusedforoutput:
<div>LocalTimeis<spanid="spanLocalTime"></span></div>
<divid="divCityTime"></div>
There’salsoaforminwhichyou’vedefinedalistboxusinga<select>element:
<selectsize="5"name="lstCity">
<optionvalue="60"selected>Berlin
<optionvalue="330">Bombay
<optionvalue="0">London
<optionvalue="180">Moscow
<optionvalue="-300">NewYork
<optionvalue="60">Paris
<optionvalue="-480">SanFrancisco
<optionvalue="600">Sydney
</select>
Eachoftheoptionsdisplaysthecity’snameinthelistboxandhasitsvaluesettothedifferenceinminutesbetweenthatcity’stimezone(inwinter)andUTC.SoLondon,whichusesUTC,hasavalueof0.Paris,whichisanhouraheadofUTC,hasavalueof60(thatis,60minutes).NewYork,whichisfivehoursbehindUTC,hasavalueof-300.
There’salsoacheckboxwithanassociatedlabel:
<p>
<inputtype="checkbox"id="chkDst"name="chkDst"/>
<labelfor="chkDst">AdjustcitytimeforDaylightSavings</label>
</p>
Checkingthischeckboxwilladdanhourtoacity’scalculatedtime.
You’llregisterthechangeeventlistenerofthe<select/>elementandtheclickeventlistenerofthecheckboxtocalltheupdateTimeZone()function.Aswithpreviousversions,youcreateaglobalvariabletoprovideeasieraccesstothe<form/>elementobject:
varmyForm=document.form1;
Thenyouregistertheeventlisteners:
myForm.lstCity.addEventListener("change",updateTimeZone);
myForm.chkDst.addEventListener("click",updateTimeZone);
ThefunctionupdateTimeZone()doesn’treallyupdateanything,butitdoesgatherinformationandkickofftheupdateprocess:
functionupdateTimeZone(){
varlstCity=myForm.lstCity;
Thefirstfourstatementsofthisfunctioncreatefourvariables.Thefirst,lstCity,containsareferencetothe<select/>elementobject.Youcreatethisvariableforconveniencepurposes—namelyforthecreationofthesecondvariable:selectedOption:
varselectedOption=lstCity.options[lstCity.selectedIndex];
ThisselectedOptionvariableisretrievedbyusingthelstCityobject’soptionspropertyinconjunctionwithitsselectedIndexproperty,andnowthatyouhavetheselectedOption,youcaneasilygettheinformationattachedtotheoption:
varoffset=selectedOption.value;
varselectedCity=selectedOption.text;
Next,youwanttodetermineiftheusercheckedthedaylightsavingscheckbox:
vardstAdjust=0;
if(myForm.chkDst.checked){
dstAdjust=60;
}
YouinitializethedstAdjustvariablewith0.Ifthecheckboxischecked,youmodifydstAdjusttocontainthevalueof60.Thevalueof60isfor60minutes.Asyouhaveprobablyguessed,yourtimeconversioncalculationwillbewithminutevalues.
InthefinalpartofupdateTimeZone(),youcalltheupdateTime()function,passingthevaluescontainedwithintheselectedCity,offset,anddstAdjustvariables:
updateTime(selectedCity,offset,dstAdjust);
}
InthefunctionupdateTime(),youwritethecurrentlocaltimeandtheequivalenttimeintheselectedcitytotheoutputelements.
YoustartatthetopofthefunctionbycreatinganewDateobject,whichisstoredinthevariablenow.TheDateobjectwillbeinitializedtothecurrentlocaltime:
functionupdateOutput(selectedCity,offset,dstAdjust){
varnow=newDate();
Next,yououtputthelocaltimetothe<span/>elementwithanidofspanLocalTime:
document.getElementById("spanLocalTime").innerHTML=
now.toLocaleString();
YouusetheDateobject’stoLocaleString()methodtoformatthedateandtimeinyourregion’sformat.
YousawinChapter7thatifyousetthevalueofaDateobject’sindividualparts(suchashours,minutes,andseconds)toavaluebeyondtheirnormalrange,JavaScriptassumesyouwanttoadjustthedate,hours,orminutestotakethisintoaccount.Forexample,ifyousetthehoursto36,JavaScriptsimplychangesthehoursto12andaddsonedaytothedatestoredinsidetheDateobject.Youusethistoyourbenefitinthefollowingline:
now.setMinutes(now.getMinutes()+now.getTimezoneOffset()+
parseInt(offset,10)+dstAdjust);
Let’sbreakdownthislinetoseehowitworks.Supposethatyou’reinNewYork,withthelocalsummertimeof5:11,andyouwanttoknowwhattimeitisinBerlin.
Howdoesyourlineofcodecalculatethis?
First,yougettheminutesofthecurrentlocaltime;it’s5:11,sonow.getMinutes()returns11.
Thenyougetthedifference,inminutes,betweentheuser’slocaltimeandUTCusingnow.getTimezoneOffset().IfyouareinNewYork,whichisdifferentfromUTCby4hoursduringthesummer,thisis240minutes.
ThenyougettheintegervalueofthetimedifferencebetweenthestandardwintertimeintheselectedcityandUTCtime,whichisstoredinoffset.You’veusedparseInt()herebecauseit’soneofthefewsituationswhereJavaScriptgetsconfusedandassumesyouwanttojointwostringstogetherratherthantreatthevaluesasnumbersandaddthemtogether.RememberthatyougotoffsetfromanHTMLelement’svalue,andthatanHTMLelement’svaluesarestrings,evenwhentheyholdcharactersthataredigits.BecauseyouwantthetimeinBerlin,whichis60minutesdifferentfromUTCtime,thisvaluewillbe60.
Finally,youaddthevalueofdstAdjust.Becauseit’ssummerwhereyouareandBerlinusesdaylightsavingshours,thisvalueis60.
Soyouhavethefollowing:
11+240+60+60=371
Therefore,now.setMinutes()issettingtheminutesto371.Clearly,there’snosuchthingas371minutespastthehour,soinsteadJavaScriptassumesyoumean6hoursand11minutesafter5:00,thatbeing11:11—thetimeinBerlinthatyouwanted.
Finally,theupdateTime()functioncreatestheresultsTextvariableandthenwritestheresultstothedivCityTime:
varresultsText=selectedCity+"timeis"+
now.toLocaleString();
document.getElementById("divCityTime").innerHTML=resultsText;
}
HTML5FORMOBJECTPROPERTIESANDMETHODSHTML4wasfinalizedin1997,anditwasn’tuntil2012thatthewebcommunitysawapushforHTML5.Needlesstosay,HTMLhadn’tseenasignificantupdateuntiltheintroductionofHTML5.Soforfifteenyears,webdevelopershaveworkedwithformcontrolsthatgrosslydon’tmeetdevelopers’andusers’needs.Thankfully,thatchangeswithHTML5.
Onethingyou’vedonethroughoutthischapterisrespondtovariousformcontrols’change,click,focus,blur,andkeypressevents(amongothers).Alloftheseeventscanbeusedinconjunctionwithoneanothersothatyoucanrespondtoanyuserinput,butthatrequiresalotofextracode.
AbettersolutionwouldbetousetheinputeventintroducedinHTML5.Thisneweventfireswhenthevalueofanelementchanges.Thatmeansyoucanlistenfortheinputeventona<form/>objectandprocessitsdataasanyfieldisupdated.
Thetargetoftheinputeventistheelementthatchanged.Youusetheinputeventlaterinthischapter.
NewInputTypesHTML5introducesaslewofnewtypesfor<input/>elements,andthefollowingtableliststhem,theirdescriptions,andadescriptionoftheiroutput(thecontrol’svalueifknown).Inallcases,thevalueisastringobject.
TYPE DESCRIPTION VALUEcolor Acontrolforspecifyingacolor.Thevalue
isthecolorinhexadecimalformat.Ahexadecimalvalueofthenumber(#ff00ff).
date Usedforenteringthedate(year,month,andday).
Thedateinyyyy-mm-ddformat(2014-07-14).
datetime AllowsforenteringthedateandtimebasedonUTC.
Notyetsupported.
email Afieldforeditingane-mailaddress.Thevalueisautomaticallyvalidated.
Thetextinputintothefield(evenifinvalide-mail).
month Acontrolforenteringmonthandyear;notimezone.
Thedateinyyyy-mmformat(2014-07).
number Createsacontrolfornumericinput,butdoesnotprohibitalpha-characterinput.
Thenumericdatainputintothefield,oranemptystringifnotanumber.
range Createsanativesliderforimprecisenumericinput.
Thevalueoftheslider.
search Asingle-linetextentrycontrol. Thetextinputintothefield.Linebreaksareremoved.
tel Createsacontrolfortelephoneentry. Thetextinputintothefield.Linebreaksareremoved.
time Allowstimeinputwithnotimezone. Thetimein24-hourformat(15:37for03:37PM).
url AcontrolforeditingabsoluteURLs. Thetextinputintothefield.Linebreaksandleading/trailingwhitespaceareremoved.
week Createsacontrolforenteringadateconsistingofaweek-yearnumberandaweeknumberwithnotimezone.
Theyearandweeknumber(2014-W29).
Unfortunately,someofthenewinputtypesarenotsupportedbyanybrowser,andsomeareonlysupportedbyafew.Manyofthesupportedinputtypesexhibitinconsistentbehaviorbetweenbrowsers.Inshort,ifyouplanonusinganyofthesenewinputtypes,besuretotestyourpageinallmodernbrowsers.
HTML5alsobringsseveralnewattributesto<input/>elements,allofwhichareaccessibleaspropertiesoftheelementobject.Thefollowingtablelistsjustsomeoftheseattributes.
TYPE DESCRIPTIONautocomplete Specifiesthatthevalueofthecontrolcanbeautomaticallycompletedby
thebrowser.autofocus Determinesifthecontrolshouldhavefocuswhenthepageloads.form TheIDoftheassociatedform.Ifspecified,thecontrolcanbeplaced
anywhereinthedocument.Ifnotspecified,thecontrolcanonlyresidewithintheform.
maxLength Specifiesthemaximumnumberofcharacterstheusercanenterfortext,email,search,password,tel,andurltypes.
pattern Aregularexpressionthatthecontrol’svalueischeckedagainst.placeholder Displaysahinttotheuserofwhatcanbeenteredinthefield.required Specifiesthattheusermustfillinavalueforthefieldbeforesubmitting
theform.
Inadditiontotheseproperties,HTML5specifiesthreeuniqueproperties/attributesfortherangetype:
min:Theminimumvalueoftheslider
max:Themaximumvalueoftheslider
step:Theincrementbetweenvalues
TRYITOUTNewInputTypesLet’slookatanexampleofthenumberandrangeinputtypes,aswellastheinputevent.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example10</title>
</head>
<body>
<formname="form1">
<p>
<labelfor="minValue">Min:</label>
<inputtype="number"id="minValue"name="minValue"/>
</p>
<p>
<labelfor="maxValue">Max:</label>
<inputtype="number"id="maxValue"name="maxValue"/>
</p>
<p>
<labelfor="stepValue">Step:</label>
<inputtype="number"id="stepValue"name="stepValue"/>
</p>
<p>
<inputtype="range"id="slider"name="slider"/>
</p>
</form>
<divid="output"></div>
<script>
varmyForm=document.form1;
varoutput=document.getElementById("output");
functionformInputChange(){
varslider=myForm.slider;
slider.min=parseFloat(myForm.minValue.value);
slider.max=parseFloat(myForm.maxValue.value);
slider.step=parseFloat(myForm.stepValue.value);
output.innerHTML=slider.value;
}
myForm.addEventListener("input",formInputChange);
</script>
</body>
</html>
Savethisasch11_example10.html.
Whenyouopenthispageinamodernbrowser,youwillseethreetextboxesandoneslider.Thethreetextboxesenableyoutoedittheminimum,maximum,andstepoftheslider.Providinganyinputtoanyoftheformfieldsupdatesthemin,max,andsteppropertiesoftheslider,aswellasdisplaysthevalueofthesliderina<div/>element.
Thereisoneexception:InIE,changingthevalueofthesliderdoesnotcausetheinputeventtofire.
Let’sfirstlookattheform’sHTML:
<formname="form1">
<p>
<labelfor="minValue">Min:</label>
<inputtype="number"id="minValue"name="minValue"/>
</p>
<p>
<labelfor="maxValue">Max:</label>
<inputtype="number"id="maxValue"name="maxValue"/>
</p>
<p>
<labelfor="stepValue">Step:</label>
<inputtype="number"id="stepValue"name="stepValue"/>
</p>
Youstartwiththree<input/>elementsoftypenumber.Theirpurposeistoallowyoutospecifytheminimum,maximum,andstepvaluesofthefourth<input/>element:
<p>
<inputtype="range"id="slider"name="slider"/>
</p>
</form>
Thisisarange<input/>element,andtherearenoattributesotherthantype,id,andname.
Outsideoftheformisa<div/>elementwithanidofoutput:
<divid="output"></div>
Asyouinputdataintheform,thecontentsofthis<div/>elementchangewiththevalueoftherange<input/>element.
NowfortheJavaScript.ThefirsttwolinesofJavaScriptcodereachintotheDOMandgrabreferencestotwoelements:
varmyForm=document.form1;
varoutput=document.getElementById("output");
Thefirstisareferencetothe<form/>element,andthesecondisthe<divid="output"/>element.
Tomakethisexamplework,youlistenforthemyFormobject’sinputevent.So,nextyoucallmyForm.addEventListener()toregisterthelistener:
myForm.addEventListener("input",formInputChange);
TheformInputChange()functionexecuteswhentheinputeventfires,andinitsfirstlineofcode,youcreateavariablecalledslidertocontaintherange<input/>element:
functionformInputChange(){
varslider=myForm.slider;
Thisisforconveniencepurposesbecauseeverystatementinthisfunctionwillreferencethesliderelementinsomeway.
Next,youwanttomodifytheslider’smin,max,andsteppropertieswiththedataenteredintotheform:
slider.min=parseFloat(myForm.minValue.value);
slider.max=parseFloat(myForm.maxValue.value);
slider.step=parseFloat(myForm.stepValue.value);
Rememberthatan<input/>element’svalueisstringdata—evenifthatstringcontainsanumber.Therefore,youneedtoconvertthestringintoanumericvalue.TheparseFloat()functionshouldbeusedherebecausefloating-pointnumbersarevalidvaluesforarange’smin,max,andstepproperties.
Finally,youdisplayslider’svalue.
output.innerHTML=slider.value;
}
NewElementsHTML5alsointroducesthreenewformcontrols:
<output/>isusedtodisplaytheresultofacalculation.
<meter/>isagraphicaldisplayofavalue.
<progress/>representsthecompletionprogressofatask.
The<output/>elementismoreofatraditionalformcontrolinthatithastobeassociatedwithaform;itcanresidewithinaformoryoucanprovideaform’sidasthevalueofitsformattribute.
The<meter/>and<progress/>elements,however,havenosuchrequirement.Theycanappearanywherewithinthedocumentwithoutanyformassociation.
The<output/>ElementThe<output/>elementrepresentstheresultofaparticularcalculationoruseraction.Nographicsorstylingareassociatedwiththeelement;itsimplydisplaystext(althoughyoucanapplystylingwithCSS).
Attheheartofthe<output/>elementisitsvalueproperty.Likeatypicalformcontrol,thevaluepropertyletsyougetandsetthevalueofthecontrol,andsettingthevaluevisuallyupdatesthecontroltodisplaywhatevervalueyouassignedtotheproperty.Butunliketypicalformcontrols,the<output/>elementdoesnothaveavalueattribute.Thevalueoftheelementisinsteadrepresentedbyatextnodebetweentheopeningandclosing<ouput>tags.Forexample:
<outputname="result"id="result"for="field1field2">10</output>
IE11andbelowdonotofficiallysupportthe<output/>element,andsettingthevaluepropertywillresultinanerror.Youmightworkaroundthisissuebystillusingthe<output/>elementandsettingsits“value”withinnerHTML.However,thisworkaroundisnotstandardandisnotrecommended.
Finally,the<output/>elementshouldbeassociatedwithfieldsinvolvedintheresultofcalculationsthatthe<output/>displays.Youdothiswiththefamiliarforattribute.InthepreviousHTML,the<output/>elementisassociatedwithfield1andfield2.
TRYITOUTsingthe<output/>ElementInthisexercise,youmodifyExample10andusethe<output/>elementtodisplaytherange’svalue.FeelfreetocopyandpasteExample10andmodifythehighlightedlinesofcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example11</title>
</head>
<body>
<formid="form1"name="form1">
<p>
<labelfor="minValue">Min:</label>
<inputtype="number"id="minValue"name="minValue"/>
</p>
<p>
<labelfor="maxValue">Max:</label>
<inputtype="number"id="maxValue"name="maxValue"/>
</p>
<p>
<labelfor="stepValue">Step:</label>
<inputtype="number"id="stepValue"name="stepValue"/>
</p>
<p>
<inputtype="range"id="slider"name="slider"/>
</p>
</form>
<outputid="result"name="result"form="form1"for="slider">
</output>
<script>
varmyForm=document.form1;
varoutput=myForm.result;
functionformInputChange(){
varslider=myForm.slider;
slider.min=parseFloat(myForm.minValue.value);
slider.max=parseFloat(myForm.maxValue.value);
slider.step=parseFloat(myForm.stepValue.value);
result.value=slider.value;
}
myForm.addEventListener("input",formInputChange);
</script>
</body>
</html>
Savethisasch11_example11.html.
Becauseyou’reusingstandard<output/>code,youwillneedtoopenthispageinChrome,Firefox,orOpera.
Let’sfocusonlyonthelinesthatchanged.First,youaddanidattributetothe<form/>element:
<formid="form1"name="form1">
Thisadditionisonlynecessarybecauseyoudefinethe<output/>elementoutsideoftheform:
<outputid="result"name="result"form="form1"for="slider"></output>
Youdefinethe<output/>elementbysettingitsidandnameattributestoresult,the
formattributetoform1,andtheforattributetoslider.Thelatterisn’tabsolutelynecessaryforthisexampletowork,buttheforattributeexistssothatyoucanwritesemanticmarkup.Bysettingfortoslider,you(andreadersofyourcode)knowthatthe<output/>elementdisplaysthevaluerelatedtotherangefield.
ThenextchangeisthesecondlineofJavaScriptcode.Insteadofretrievinga<div/>element,yougrabareferencetoyournew<output/>element:
varoutput=myForm.result;
Noticethecode:myForm.result.Eventhoughthe<output/>elementisnotinsidetheform,itisstillassociatedwiththeformbecauseoftheforattribute.Therefore,youcanwalktheFormobjecthierarchytoreferencethe<output/>element.
ThefinalchangeisthelaststatementoftheformInputChange()function:
result.value=slider.value;
Yousetthe<output/>element’svaluepropertytothevalueofslider;thus,updatingtheinformationdisplayedinthepage.
The<meter/>and<progress/>ElementsAsmentionedearlier,the<meter/>and<progress/>formcontrolsareratheruniqueinthattheycanbeusedanywherewithinapage.Itmightseemstrangetocallthem“formcontrols”whentheydon’thavetobeusedwithinaform—theydon’tevenacceptuserinput!Nevertheless,they’recategorizedassuch.
Atfirstglance,theseelementslooksimilar,butthey,infact,servetwodifferentpurposesandhaveadifferentsetofattributesandproperties.
The<meter/>elementisusedtographicallydisplayanindividualvaluewithinaparticularrange.Forexample,theRPMsofavehicle’sengine,theheatofaCPU,ordiskusageindicatorsareperfectexamplesofwhatthe<meter/>elementisusedfor.
The<meter/>elementconsistsofanopeningandclosingtag,andyoucanspecifythelow,optimum,andhighsectionsofthemeter.Theseareranges,mostlyforsemanticpurposes,thataffectthemeter’scolor.Youcanalsosettheminandmaxofpossiblevalues,aswellasthevalueofthemeter:
<metermin="0"max="150"low="40"optimum="75"
high="100"value="80">80UnitsofSomething</meter>
Thesesixattributesmaptopropertiesofthesamenames.Ifabrowserdoesn’tsupportthe<meter/>element,thetextbetweentheopeningandclosingtagisdisplayedinthebrowser.
NOTEIE9,IE10,andIE11donotsupportthe<meter/>element.
The<progress/>elementrepresentsthecompletionprogressofatask,andaswiththeprecedingnewelements,itconsistsofanopeningandclosingtag:
<progressmax="100"value="40">40%donewithwhatyou'redoing</progress>
Italsohasamaxattributethatmapstotheelementobject’smaxproperty,andthecontrol’svalueiscontainedwithinthevalueattribute/property.Like<meter/>,thetextbetweentheopeningandclosingtagsisdisplayedifthebrowserdoesn’tsupportthe<progress/>element.
TRYITOUTThe<meter/>and<progress/>ElementsLet’susethe<meter/>and<progress/>elementsinanexample.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Example12</title>
</head>
<body>
<h2>HighwaySpeedTracker</h2>
<formid="form1"name="form1">
<p>
<labelfor="driverName">DriverName:</label>
<inputtype="text"id="driverName"name="driverName"/>
</p>
<p>
<labelfor="speed">Speed(Miles/Hour):</label>
<inputtype="number"id="speed"name="speed"/>
<meterid="speedMeter"value="0"low="55"optimum="75"
high="90"max="120"></meter>
</p>
<p>
<labelfor="vehicle">VehicleType:</label>
<inputtype="text"id="vehicle"name="vehicle"/>
</p>
</form>
<p>
FormCompletionProgress:
<progressid="completionProgress"max="3"value="0"></progress>
</p>
<script>
varmyForm=document.form1;
varcompletionProgress=
document.getElementById("completionProgress");
varspeedMeter=document.getElementById("speedMeter");
functioncountFieldData(){
varcount=0;
for(varindex=0;index<myForm.length;index++){
varelement=myForm[index];
if(element.value){
count++;
}
}
returncount;
}
functionformInputChange(){
completionProgress.value=countFieldData();
speedMeter.value=myForm.speed.value;
}
myForm.addEventListener("input",formInputChange);
</script>
</body>
</html>
Savethisasch11_example12.html.Openthepageinyourbrowser(includingIE—thisexamplemostlyworksinIE9,IE10,andIE11),andyou’llseeaformwiththreefields:adriver’sname,thedriver’sspeed,andthetypeofvehiclethedriverdrove.Asyoufillouttheform,you’llnoticeafewthingsgoingon.
First,theprogressbarbelowtheformchangesinvalue.Thisindicatesyourprogressinfillingouttheform.Whenallfieldshaveavalue,you’redone!Second,you’llnoticethemeternexttotheSpeedfieldupdatestovisuallyrepresentthedatafromthatfield.
Nowlet’slookattheHTML.Inthebodyofthepage,youdefineaformwiththree<input/>elements.Thefirstisanormaltextboxforthedriver’sname:
<formid="form1"name="form1">
<p>
<labelfor="driverName">DriverName:</label>
<inputtype="text"id="driverName"name="driverName"/>
</p>
Thenextfieldisanumberfieldforinputtingthedriver’sspeed:
<p>
<labelfor="speed">Speed(Miles/Hour):</label>
<inputtype="number"id="speed"name="speed"/>
<meterid="speedMeter"value="0"low="55"optimum="75"
high="90"max="120"></meter>
</p>
Here,youalsodefinea<meter/>elementwithanidofspeedMeter.Thismeterissupposedtovisuallyrepresenthighwayspeedinmilesperhour.Insuchcases,55MPHisslow,75MPHisoptimum/standard,and90MPHishigh.Themaximumvaluethismetercandisplayis120.
Thelastfieldisanothertextboxforthedriver’svehicle:
<p>
<labelfor="vehicle">VehicleType:</label>
<inputtype="text"id="vehicle"name="vehicle"/>
</p>
Thenaftertheform,youdefinea<progress/>element:
<p>
FormCompletionProgress:
<progressid="completionProgress"max="3"value="0"></progress>
</p>
Thisistotracktheuser’sprogressinfillingouttheform.IthasanidofcompletionProgressandhasamaximumvalueof3becauseitcontainsthreefields.
Ofcourse,theHTMLbyitselfisn’tveryinteresting;so,let’slookattheJavaScript.Youfirstretrievethreeelementsfromthedocument:the<form/>,<progress/>,and<meter/>elements.
varmyForm=document.form1;
varcompletionProgress=document.getElementById("completionProgress");
varspeedMeter=document.getElementById("speedMeter");
Toretrievethe<progress/>and<meter/>elements,youusedocument.getElementById()becausealthoughthesetwoelementsareconsideredformcontrols,youcannotaccessthemthroughtheformhierarchy(whichadmittedlycanbealittleconfusing).
Onceagain,theform’sinputeventprovidesthemagicforthisexample;so,youregisteritslistener:
myForm.addEventListener("input",formInputChange);
TheformInputChange()functionisrathersimple;itupdatesthevaluesofboththe<progress/>and<meter/>elements:
functionformInputChange(){
completionProgress.value=countFieldData();
speedMeter.value=myForm.speed.value;
}
ThevalueforspeedMetercomesfromthespeedfieldintheform,butalittlemoreworkisneededtosetthevalueforcompletionProgress.
YoucreateahelperfunctioncalledcountFieldData().Itsjobisstraightforward:Examinetheelementswithintheformanddetermineiftheyhaveavalue.It’snotafoolproofsolutionfordeterminingiftheuserhascompletedtheform,butitworksforthisexample.
First,youdefineacountervariabletocounthowmanyfieldshaveavalue.Youcallthisvariablecount:
functioncountFieldData(){
varcount=0;
Nowyouneedtocheckthevaluepropertyofeveryelementintheform.Youcouldwritecodeexplicitlyforthisform,oryoucantakeamoregenericapproachandloopthroughtheform’selements.Let’sdothelatter:
for(varindex=0;index<myForm.length;index++){
varelement=myForm[index];
if(element.value){
count++;
}
}
Usingaforloop,youiterateoverthemyFormobject/collectiontoretrieveeachformcontrolandcheckifithasavalue.Iftheelementhasavalue,youincrementthecountvariable.
Aftertheloopexits,youreturnthevalueofthecountvariable:
returncount;
}
SUMMARYInthischapter,youlookedathowtoaddauserinterfaceontoyourJavaScriptsothatyoucaninteractwithyourusersandacquireinformationfromthem.Thischaptercoveredthefollowing:
TheHTMLformiswhereyouplaceelementsmakinguptheinterfaceinapage.
EachHTMLformgroupstogetherasetofHTMLelements.Whenaformissubmittedtoaserverforprocessing,allthedatainthatformissenttotheserver.Youcanhavemultipleformsonapage,butonlytheinformationinoneformcanbesenttotheserver.
Aformiscreatedwiththeopeningtag<form>andendswiththeclosetag</form>.Alltheelementsyouwantincludedinthatformareplacedinbetweentheopenandclose<form>tags.The<form/>elementhasvariousattributes—forclient-sidescripting,thenameattributeistheimportantone.YoucanaccessformswitheithertheirnameattributeortheirIDattribute.
Each<form>elementcreatesaFormobject,whichiscontainedwithinthedocumentobject.ToaccessaformnamedmyForm,youwritedocument.myForm.Thedocumentobjectalsohasaformsproperty,whichisacollectioncontainingeveryforminsidethedocument.Thefirstforminthepageisdocument.forms[0],thesecondisdocument.forms[1],andsoon.Thelengthpropertyoftheformsproperty(document.forms.length)tellsyouhowmanyformsareonthepage.
Havingdiscussedforms,wethenwentontolookatthedifferenttypesofHTMLelementsthatcanbeplacedinsideforms,howtocreatethem,andhowtheyareusedinJavaScript.
Theobjectsassociatedwiththeformelementshaveanumberofproperties,methods,andeventsthatarecommontothemall.Theyallhavethenameproperty,whichyoucanusetoreferencetheminyourJavaScript.Theyalsoallhavetheformproperty,whichprovidesareferencetotheFormobjectinwhichthatelementiscontained.Thetypepropertyreturnsatextstringtellingyouwhattypeofelementthisis;typesincludetext,button,andradio.
Youalsosawthatthemethodsfocus()andblur(),andtheeventsfocusandblur,areavailabletoeveryformelementobject.Suchanelementissaidtoreceivethefocuswhenitbecomestheactiveelementintheform,eitherbecausetheuserhasselectedthatelementorbecauseyouusedthefocus()method.Howeveranelementgotthefocus,itsfocuseventwillfire.Whenanotherelementissetasthecurrentlyactiveelement,thepreviouselementissaidtoloseitsfocus,ortoblur.Again,lossoffocuscanbetheresultoftheuserselectinganotherelementortheuseoftheblur()method;eitherway,whenithappenstheblureventfires.Yousawthatthefiringoffocusandblurcan,ifusedcarefully,beagoodplacetocheckthingslikethevalidityofdataenteredbyauserintoanelement.
Allelementsreturnavalue,whichisthestringdataassignedtothatelement.The
meaningofthevaluedependsontheelement;foratextbox,itisthevalueinsidethetextbox,andforabutton,it’sthetextdisplayedonitsface.
Havingdiscussedthecommonfeaturesofelements,wethenlookedateachofthemorecommonlyusedelementsinturn,startingwiththebuttonelement.
Thebuttonelement’spurposeinlifeistobeclickedbytheuser,wherethatclickingfiressomescriptyouhavewritten.Youcancapturetheclickingbyconnectingtothebutton’sclickevent.Abuttoniscreatedbymeansofthe<input/>elementwiththetypeattributesettobutton.Thevalueattributedetermineswhattextappearsonthebutton’sface.Twovariationsonabuttonarethesubmitandresetbuttons.Inadditiontoactingasbuttons,theyalsoprovideaspecialservicenotlinkedtocode.Thesubmitbuttonautomaticallysubmitstheformtotheserver;theresetbuttonclearstheformbacktoitsdefaultstatewhenloadedinthepage.
Thetextelementallowstheusertoenterasinglelineofplaintext.Atextboxiscreatedbymeansofthe<input/>elementwiththetypeattributesettotext.Youcansethowmanycharacterstheusercanenterandhowwidethetextboxiswiththemaxlengthandsizeattributes,respectively,ofthe<input/>element.ThetextboxhasanassociatedobjectcalledText,whichhastheadditionaleventsselectandchange.Theselecteventfireswhentheuserselectstextinthebox,andthemoreusefulchangeeventfireswhentheelementlosesfocusanditscontentshavechangedsincetheelementgainedthefocus.Thefiringofthechangeeventisagoodplacetodovalidationofwhattheuserhasjustentered.Ifsheenteredillegalvalues,suchasletterswhenyouwantednumbers,youcanletherknowandsendherbacktocorrecthermistake.Avariationonthetextboxisthepasswordbox,whichisalmostidenticaltothetextboxexceptthatthevaluestypedintoitarehiddenandshownasasterisks.Additionally,thetextboxalsohasthekeydown,keypress,andkeyupevents.
Thenextelementyoulookedatwasthetextarea,whichissimilartothetextboxexceptthatitallowsmultiplelinesoftexttobeentered.Thiselementiscreatedwiththeopentag<textarea>andclosedwiththe</textarea>tag,thewidthandheightincharactersofthetextboxbeingdeterminedbythecolsandrowsattributes,respectively.Thewrapattributedetermineswhetherthetextareawrapstextthatreachestheendofalineandwhetherthatwrappingissentwhenthecontentsarepostedtotheserver.Ifthisattributeisleftout,orsettooff,nowrappingoccurs;ifsettosoft,itcauseswrappingclient-side,butisnotsenttotheserverwhentheformissent;ifsettohard,itcauseswrappingclient-sideandissenttotheserver.TheassociatedTextareaobjecthasvirtuallythesameproperties,methods,andeventsasaTextobject.
Youthenlookedatthecheckboxandradiobuttonelementstogether.Essentiallytheyarethesametypeofelement,exceptthattheradiobuttonisagroupedelement,meaningthatonlyoneinagroupcanbecheckedatonce.Checkinganotheronecausesthepreviouslycheckedbuttontobeunchecked.Bothelementsarecreatedwiththe<input/>element,thetypeattributebeingcheckboxorradio.Ifcheckedisputinsidethe<input>tag,thatelementwillbecheckedwhenthepageisloaded.Creatingradiobuttonswiththesamenamecreatesaradiobuttongroup.Thenameof
aradiobuttonactuallyreferstoanarray,andeachelementwithinthatarrayisaradiobuttondefinedontheformtobewithinthatgroup.TheseelementshaveassociatedobjectscalledCheckboxandRadio.Usingthecheckedpropertyoftheseobjects,youcanfindoutwhetheracheckboxorradiobuttoniscurrentlychecked.Bothobjectsalsohavetheclickeventinadditiontothecommoneventsfocusandblur.
Nextinyourlookatelementswerethedrop-downlistandlistboxes.Both,infact,arethesameselectelement,withthesizeattributedeterminingwhetherit’sadrop-downorlistbox.The<select>tagcreatestheseelements,thesizeattributedetermininghowmanylistitemsarevisibleatonce.Ifasizeof1isgiven,adrop-downboxratherthanalistboxiscreated.Eachiteminaselectelementisdefinedbythe<option/>element,oraddedtolaterbymeansoftheSelectobject’soptionscollectionproperty,whichisanarray-likestructurecontainingeachOptionobjectforthatelement.However,addingoptionsafterthepageisloadeddiffersslightlybetweenstandards-compliantbrowsersandold-IE.TheSelectobject’sselectedIndexpropertytellsyouwhichoptionisselected;youcanthenusethatvaluetoaccesstheappropriateoptionintheoptionscollectionandusetheOptionobject’svalueproperty.TheOptionobjectalsohasthetextandindexproperties,textbeingthedisplayedtextinthelistandindexbeingitspositionintheSelectobject’soptionscollectionproperty.Youcanloopthroughtheoptionscollection,findingoutitslengthfromtheSelectobject’slengthproperty.TheSelectobjecthasthechangeevent,whichfireswhentheuserselectsanotheritemfromthelist.
YouthenlookedatHTML5’snewelementsandinputtypes,aswellastheinputevent.YoulearnedhowtowriteJavaScriptcodetomanipulatethe<output/>,<meter/>,and<progress/>elementsandmodifytheiroutputwhenusersinputdatainaform.
Inthenextchapter,youlookatJavaScriptObjectNotation(JSON),adataformatthatletsyoustoreJavaScriptobjectsandarraysasstringdata.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. UsingthecodefromthetemperatureconverterexampleyousawinChapter2,createauserinterfaceforitandconnectittotheexistingcodesothattheusercanenteravalueindegreesFahrenheitandconvertittocentigrade.
2. Createauserinterfacethatallowsuserstopickthecomputersystemoftheirdreams,similarinprincipletothee-commercesitessellingcomputersovertheInternet.Forexample,theycouldbegivenachoiceofprocessortype,speed,memory,andharddrivesize,andtheoptiontoaddadditionalcomponentslikeaDVD-ROMdrive,asoundcard,andsoon.Astheuserschangetheirselections,thepriceofthesystemshouldupdateautomaticallyandnotifythemofthecostofthesystemastheyspecifiedit,eitherbyusinganalertboxorbyupdatingthecontentsofatextbox.
12JSONWHATYOUWILLLEARNINTHISCHAPTER:
DiscoveringthelimitationsofusingXMLwithJavaScript
RecognizingthedifferencesbetweenJavaScriptandJSON
Serializingobjectsusingthebuilt-inJSONobject
ParsingJSONbackintoactualobjectsandvaluesyoucanuseinyourpages
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Ifyouaren’talready,startthinkingofawebpageasaprogram.Itdoes,afterall,haveallthetrappingsofatraditionalprogram.Ithasauserinterface,anditcanprocessdatawithJavaScript.Butasyouwellknow,traditionalprogramscandomore;theycanstoredataaswellastransmitdatatoothercomputersandsystems.Inthecomingchapters,youlearnthatyoucandothesamethingsinawebpage—allthankstoJavaScript.
Butasyousoonlearn,youcan’tjuststoreobjectsandarraysastheyare;instead,youneedtoserializethem.Serializationistheprocessoftranslatinganobjectintoastringrepresentationofthatobject.Onceanobjectisserialized,thestringrepresentationofthatobjectcanthenbestoredinamorepermanentstoragefacilityortransmittedtoanothercomputer.
Serializationtranslatesonlythestructureandpertinentinformationofanobject—thatis,onlythepropertiesarepresentinaserializedobject.ButonceyouneedtoworkwiththeobjectwithinJavaScript,youcandeserializeit,convertingitbackintoanativeJavaScriptobject.
TheserializationformatthatwebdevelopersoverwhelminglyembraceiscalledJavaScriptObjectNotation,orJSON(pronouncedlikethename:Jason).ItisasubsetoftheJavaScriptlanguage;assuch,it’seasytoread,it’sconcise,andmostimportantly,it’seasytoserializetoanddeserializefrom.
Butthewebhasn’talwaysusedJSONforserializingJavaScriptobjects.SobeforewelookattheJSONformat,let’slookatwhatwebdevelopersusedtouse.
XMLTherewasatimewhenthewebdevelopmentcommunityembracedXMLforjustabouteverything.Webservicesusedittocommunicatewithoneanotherandothercomputers,andJavaScriptdevelopersusedittocommunicatewiththewebapplication’sserver.
XMLisahuman-readablelanguagethankstoitsdeclarativesyntax.It’snotnecessaryforhumanstoreadXMLdata,butbeingabletoreadanddeciphertheXMLcanbeuseful.ConsiderthefollowingXMLdocumentasanexample:
<person>
<firstName>John</firstName>
<lastName>Doe</lastName>
<age>30</age>
</person>
Despitebeingasimpledocument,youknowthatthisXMLrepresentsanindividualpersonnamedJohnDoewhois30yearsold.YoucouldcatchandfixerrorsthatmayoccurinyourapplicationasitgeneratestheprecedingXML-formatteddata.
XMLisalsomachine-readable,anditwasaknowncommoditywhendevelopersstartedusingit.Everymodernprogramminglanguagehadthetoolsandcapabilitiesforreading,parsing,andcreatingXML-formatteddata,andsousingXMLtocommunicatebetweencomputersystemsandapplicationsseemedlikeagoodidea.
ButXMLhasitsdrawbacks.Forone,XML’sdeclarativesyntaxaddsalotofextracrufttothedata.LookagainattheXMLdescribingapersonnamedJohnDoe:
<person>
<firstName>John</firstName>
<lastName>Doe</lastName>
<age>30</age>
</person>
ThissimpleXMLis101bytes.That’snotlargebytoday’sstandards,butrememberthatthisisjustanexample.ThisisinformationthatacomputerwouldsendovertheInternettoanothercomputer.
First,theopeningandclosing<person>tagssurroundtheactualdata.Ofcourse,theouter<person/>elementexistsfororganizationalpurposes,butitis17bytes—16percentoftheentirepayload.Otherformatswillstillhavesomewaytoorganizethedocument’srealinformation(thefirstandlastname),buttheywouldbesmallerinsize.
Next,openingandclosingtagssurroundboththefirstandlastname.Naturally,thereneedstobesomewaytoorganizethatdata,butyet,thisXMLuses55bytestodenotethefirstname,lastname,andtheage.
AnotherofXML’sissuesisthecodenecessaryforreading,parsing,andgeneratingXMLdata.Yes,mostmodernprogramminglanguagescanhandleXML,butitrequiresalotofcode—codethatusuallyhastoberewrittenforspecificXMLformats.Forexample,thefollowingcodeisonewayyoucouldreadthepreviousXMLandparseitintoanobject
calledperson:
varpersonElement=document.querySelector("person");
varfirstName=personElement.querySelector("firstName").innerHTML;
varlastName=personElement.querySelector("lastName").innerHTML;
varage=personElement.querySelector("age").innerHTML;
varperson={
firstName:firstName,
lastName:lastName,
age:age
};
ThiscodedemonstratesastraightforwardapproachtoparsingtheJohnDoeXML.Itfirstretrievesthe<person/>elementusingdocument.querySelector().Itthenretrievesthe<firstName/>,<lastName/>,and<age/>elementsandstorestheirrespectivecontentsinthefirstName,lastName,andagevariables.Finally,itcreatesthepersonobjectandassignstheappropriatedatatoitsproperties.Thiscodeisn’tcomplex,butasyoumightsuspect,itwouldn’tworkforXML-formatteddatawithdifferentelementnamesandstructures.Naturally,documentswithmorecomplexstructuresrequiremuchmorecode.
ButparsingXMLintoaJavaScriptobjectisonlyhalfofthestory.BeforeyoucansenddatafromJavaScripttotheserver,youhavetoserializetheJavaScriptobject.SerializingaJavaScriptobjecttoXML-formatteddataisnotatrivialtask.Likeparsing,thesamecodeusuallydoesn’tworkfordifferentdatastructures.Plus,developersmustensuretheirgeneratedXMLdataiswell-formed.
Around2007and2008,thewebcommunitythankfullyadoptedadifferentdataformatforstoringandtransmittingJavaScriptdata.
JSONIn2006,DouglasCrockfordwrotetheJavaScriptObjectNotationspecification.JSONisasubsetoftheJavaScriptlanguage,anditusesseveralofJavaScript’ssyntacticalpatternsfororganizingandstructuringdata.Assuch,itisdoesaverygoodjobofrepresentingobjectsandtheirdata(it’ssogoodthatotherlanguagesuseJSON,too).It’sextremelyeasytoparseJSONintoJavaScriptobjectsandtoserializeobjectsintoJSON.Intoday’smodernbrowsers,itonlytakesonelineofcode!
Asyousoonsee,JSONlooksalotlikeJavaScript’sobjectandarrayliterals.It’seasytoconfuseJSONandJavaScriptasbeingthesamething,butit’simportanttounderstandthedifferencebetweenthetwo.JavaScriptisaprogramminglanguage;JSONisadataformat.
JSONletsyourepresentthreetypesofdata:simplevalues,objects,andarrays.
SimpleValuesYoucanrepresentsimplevalueslikestrings,numbers,booleans,andnull.Forexample,thefollowinglineisvalidJSON:
"JavaScript"
ThisJSONrepresentsthestringvalueof"JavaScript",anditlooksexactlylikeanormalJavaScriptstring.Butthere’sabigdifferencebetweenstringsinJavaScriptandJSON;JSONstringsmustusedoublequotes.Thus,thefollowingisinvalidJSON:
'JavaScript'
Numericdataisrepresentedbywhatappearstobenumberliterals,likethis:
10
ThisisvalidJSONrepresentingthenumber10.Similarly,booleanvaluesandnulllooklikeJavaScriptliterals,too:
true
null
ObjectsObjectsinJSONarerepresentedwithwhatlookslikeJavaScript’sobjectliteralnotation.Forexample,thefollowingisaJavaScriptobjectthatrepresentsthesamepersonfromearlier:
varperson={
firstName:"John",
lastName:"Doe",
age:30
};
TheJSONrepresentationofthisobjectlookssimilar.HereisthesameobjectrepresentedinJSON:
{
"firstName":"John",
"lastName":"Doe",
"age":30
}
AfewnoticeabledifferencesexistbetweentheJavaScriptandJSONrepresentationsofthisobject.First,JSONdoesn’thavethepersonvariablename.RememberthatJSONisadataformat,notalanguage.Ithasnovariables,functions,ormethods.Itsimplydefinesthestructureanddataofanobject.
Theseconddifferenceistheobject’spropertynames.Noticethattheyaresurroundedbydoublequotes.InJSON,anobject’spropertynamesarestrings,andthevaluesofthosepropertiesfollowtherulesspecifiedintheprevioussection.Doublequotessurroundthestringvaluesof"John"and"Doe",andthenumber30appearsasaliteralvalue.
Thefinaldifferenceisthelackofatrailingsemicolonaftertheclosingcurlybrace.Thisisn’taJavaScriptstatement,andthus,thesemicolonisnotneeded.
ThesizeofthisJSONdatastructureis69bytes.That’s68percentofthe101bytesoftheequivalentXML.
LikeJavaScriptobjects,JSONobjectscanbesimpleorcomplex.ThedatastructurerepresentingJohnDoeisrathersimple,butyoucaneasilyaddcomplexitybyincorporatinghisaddress:
{
"firstName":"John",
"lastName":"Doe",
"age":30,
"address":{
"numberAndStreet":"123Someplace",
"city":"Somewhere",
"state":"Elsewhere"
}
}
Thisaddsanaddresspropertytothemainobject,anditsvalueisanotherobjectthatcontainsJohn’smailingaddress.
ArraysLikeobjects,arraysinJSONaresimilartoJavaScript’sarrayliteralnotation.ThefollowinglineofcodeisanarrayliteralinJavaScript:
varvalues=["John",30,false,null];
ThesamearraylookslikethisinJSON:
["John",30,false,null]
Again,noticetheJSONarraydoesnothavethevaluesvariable,nordoesithavethetrailingsemicolon.Andlikeobjects,arraysarenotlimitedtojustsimplevalues;theycancontaincomplexobjects,too:
[
{
"firstName":"John",
"lastName":"Doe",
"age":30,
"address":{
"numberAndStreet":"123Someplace",
"city":"Somewhere",
"state":"Elsewhere"
}
},
{
"firstName":"Jane",
"lastName":"Doe",
"age":28,
"address":{
"numberAndStreet":"246Someplace",
"city":"Somewhere",
"state":"Elsewhere"
}
}
]
ThisJSONarraycontainsmultipleobjectsthatrepresentpeopleandtheiraddresses.ThefirstisourfamiliarJohnDoe,andthesecondishislittlesister,Jane,wholivesdownthestreet.JSONdatastructurescanbeassimpleorcomplexasyouneedthemtobe.
SerializingIntoJSONIt’sextremelyeasytoserializeJavaScriptobjectsintoJSON.JavaScripthasanaptlynamedJSONobjectthatyouusetoparseJSONdataandserializeJavaScriptobjects.AllmajorbrowserssupportthisJSONobject.Olderbrowsers,suchasIE7andbelow,canuseCrockford’sJSONimplementation(https://github.com/douglascrockford/JSON-js)toachievethesameresults.
ToserializeaJavaScriptobjectintoJSON,youusetheJSONobject’sstringify()method.Itacceptsanyvalue,object,orarrayandserializesitintoJSON.Forexample:
varperson={
firstName:"John",
lastName:"Doe",
age:30
};
varjson=JSON.stringify(person);
ThiscodeserializesthepersonobjectwithJSON.stringify()andstoresitinthejsonvariable.TheresultingJSON-formatteddatalookslikethis:
{"firstName":"John","lastName":"Doe","age":30}
Allunnecessarywhitespaceisremoved,givingyouanoptimizedpayloadthatyoucanthensendtothewebserverorstoreelsewhere.
ParsingJSONParsingJSONintoJavaScriptobjectsisequallysimple.TheJSONobjecthasaparse()methodthatparsestheJSONandreturnstheresultingobject.Usingthejsonvariablefromthepreviouscode:
varjohnDoe=JSON.parse(json);
ThiscodeparsestheJSONtextcontainedinjsonandstorestheresultingobjectinthejohnDoevariable.Andhere’sthewonderfulthing—youcanimmediatelyusejohnDoeandaccessitsproperties,suchas:
varfullName=johnDoe.firstName+""+johnDoe.lastName;
It’sreallynowonderwhydevelopersembracedJSON.It’seasytoworkwith!
JSONisusefulwhenyouneedtostoreanobject,buttheAPIyou’reworkingwithonlyletsyoustoretext.InChapter10,youlearnedthatthenativedraganddropAPIhasadataTransferobjectthatyoucanusetoworkwithdataduringthedrag-and-dropoperation.Butasyoulearned,itdoesn’tletyoustoreobjects,butyoucanstoretext.JSONistext,soyoucanserializeaJavaScriptobjectatthebeginningofthedragoperationandparsetheJSONwhenthedropeventfires.
TRYITOUTUsingJSONinDragandDropThisexampleusesch10_example21.htmlasabasis.Feelfreetocopyandpastethecodefromthatexampleandmakethehighlightedmodifications.Otherwise,openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter12:Example1</title>
<style>
[data-drop-target]{
height:400px;
width:200px;
margin:2px;
background-color:gainsboro;
float:left;
}
.drag-enter{
border:2pxdashed#000;
}
.box{
width:200px;
height:200px;
}
.navy{
background-color:navy;
}
.red{
background-color:red;
}
</style>
</head>
<body>
<divdata-drop-target="true">
<divid="box1"draggable="true"class="boxnavy"></div>
<divid="box2"draggable="true"class="boxred"></div>
</div>
<divdata-drop-target="true"></div>
<script>
functionhandleDragStart(e){
vardata={
elementId:this.id,
message:"Youmovedanelement!"
};
e.dataTransfer.setData("text",JSON.stringify(data));
}
functionhandleDragEnterLeave(e){
if(e.type=="dragenter"){
this.className="drag-enter";
}else{
this.className="";
}
}
functionhandleOverDrop(e){
e.preventDefault();
if(e.type!="drop"){
return;
}
varjson=e.dataTransfer.getData("text");
vardata=JSON.parse(json);
vardraggedEl=document.getElementById(data.elementId);
if(draggedEl.parentNode==this){
this.className="";
return;
}
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
this.className="";
alert(data.message);
}
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-target]");
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",
handleDragStart);
}
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",
handleDragEnterLeave);
targets[i].addEventListener("dragleave",
handleDragEnterLeave);
}
</script>
</body>
</html>
Savethisfileasch12_example1.html.
Youneedjustafewchangestomakethisexampledifferentfromch10_example21.html.ThefirstisinthehandleDragStart()function:
functionhandleDragStart(e){
vardata={
elementId:this.id,
message:"Youmovedanelement!"
};
Thenewcodecreatesanobjectcalleddata.IthasanelementIdpropertytocontaintheelement’sidvalue,andamessagepropertythatcontainsarbitrarytext.Youwanttousethisobjectasthedraganddrop’stransferdata;so,youhavetoserializeit:
e.dataTransfer.setData("text",JSON.stringify(data));
}
YoucalltheJSON.stringify()methodtodojustthat,andtheresultingJSONtextissetasthetransfer’sdata.
TheremainingchangesappearinthehandleOverDrop()function.Itsfirstfewlinesarethesame:
functionhandleOverDrop(e){
e.preventDefault();
if(e.type!="drop"){
return;
}
Butthenexttwolinesarenew:
varjson=e.dataTransfer.getData("text");
vardata=JSON.parse(json);
YouretrievethetransferreddatawiththegetData()methodandstoreitinthejsonvariable.YouthenparsetheJSONintoaJavaScriptobjectthatyoustoreinthedatavariable.Youneedtoretrievethedraggedelementobjectfromthedocument.So,youusedata.elementIdandpassittodocument.getElementById():
vardraggedEl=document.getElementById(data.elementId);
if(draggedEl.parentNode==this){
this.className="";
return;
}
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
this.className="";
Afteryouremovethedraggedelementfromitsparentandappendittothedroptarget,youreachintoyourdataobjectandalertitsmessagetotheuser:
alert(data.message);
}
ThistechniqueofusingJSONtostoreobjectdataisusefulinavarietyofscenarios.Inthenextchapter,youusethesametechniquetostoreobjectdatadirectlyinthebrowser.
SUMMARYInthischapter,youlookedatJSON,atextformatforstoringandtransmittingobjects,arrays,andsimplevalues.Let’slookatsomeofthethingsdiscussedinthischapter:
Serializationistheprocessoftranslatingobjectsandvaluesintoastringrepresentationofthoseobjectsandvalues.
ThewebusedtouseXMLforstoringandtransmittingJavaScriptdata,butJSONisnowtheformatofchoice.
JSONisnotJavaScript,butasubsetofJavaScript.Itssyntaxlookssimilar,butkeydifferencesexistbetweenthetwo.Forone,JSONdoesnothavevariablesorfunctions.Itissimplyadataformat.
JSONstringsmustbesurroundedbydoublequotes.Singlequotesresultinanerror.
Numbers,booleans,andnullappearasliteralvaluesinJSON.
JSONobjectslookverymuchlikeJavaScriptobjectliteralsexcepttheirpropertiesarestringsandtherearenotrailingsemicolons.
JSONarraysarealmostidenticaltoJavaScriptarrayliterals,buttheydonothaveatrailingsemicolon.
YouserializeJavaScriptobjects,arrays,andvaluesusingtheJSONobject’sstringify()method.
YouparseJSONtextintoaJavaScriptobjectorvalueusingJSON.parse().
Inthenextchapter,youlookathowtostoredatainandforthebrowserusinglocalstorageandcookies.
EXERCISESYoucanfindasuggestedsolutiontothisquestioninAppendixA.
1. ThecodeforalertingasinglemessageinExample1isn’tveryexciting.Modifythecodetodisplayarandommessagefromasetofthreepossiblemessages.
13DataStorageWHATYOUWILLLEARNINTHISCHAPTER:
Storingdataontheuser’scomputerispossiblewithcookiesandwebstorage
Creatingcookiesisrelativelystraightforward,butreadingthemiscomplex
Usingwebstorageiseasy
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Ourgoalaswebsiteprogrammersshouldbetomakethewebsiteexperienceaseasyandpleasantfortheuseraspossible.Clearly,well-designedpageswitheasilynavigablelayoutsarecentraltothis,butthey’renotthewholestory.Youcangoonestepfurtherbylearningaboutyourusersandusinginformationgainedaboutthemtopersonalizethewebsite.
Forexample,imagineauser,whosenameyouaskedonthefirstvisit,returnstoyourwebsite.Youcouldwelcomeherbacktothewebsitebygreetingherbyname.Anothergoodexampleisgivenbyawebsite,suchasAmazon’s,thatincorporatestheone-clickpurchasingsystem.Byalreadyknowingtheuser’spurchasingdetails,suchascredit-cardnumberanddeliveryaddress,youcanallowtheusertogofromviewingabooktobuyingitinjustoneclick,makingthelikelihoodoftheuserpurchasingitthatmuchgreater.Also,basedoninformation,suchasthepreviouspurchasesandbrowsingpatternsoftheuser,it’spossibletomakebooksuggestions.
Suchpersonalizationrequiresthatinformationaboutusersbestoredsomewhereinbetweentheirvisitstothewebsite.Accessingtheuser’slocalfilesystemfromawebapplicationisprettymuchofflimitsbecauseofsecurityrestrictionsincludedinbrowsers.However,you,asawebsitedeveloper,canstoresmallamountsofinformationinaspecialplaceontheuser’slocaldisk,usingwhatiscalledacookie,andinthebrowserusingHTML5’sWebStorage.
BAKINGYOURFIRSTCOOKIEThekeytocookiesisthedocumentobject’scookieproperty.Usingthisproperty,youcancreateandretrievecookiedatafromwithinyourJavaScriptcode.
Youcansetacookiebysettingdocument.cookietoacookiestring.You’llbelookingindetailathowthiscookiestringismadeuplaterinthechapter,butlet’sfirstcreateasimpleexampleofacookieandseewheretheinformationisstoredontheuser’scomputer.
AFresh-BakedCookieThefollowingcodesetsacookiewiththeUserNamesetasPaulandanexpirationdateof28December,2020:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Fresh-BakedCookie</title>
<script>
document.cookie=
"UserName=Paul;expires=Tue,28Dec202000:00:00;";
</script>
</head>
<body>
<p>Thispagejustcreatedacookie</p>
</body>
</html>
Savethepageasfreshbakedcookie.html.You’llseehowthecodeworksasyoulearnthepartsofacookiestring,butfirstlet’sseewhathappenswhenacookieiscreated.
Howyouviewcookieswithoutusingcodevarieswiththebrowseryouareusing.
ViewingCookiesinInternetExplorerInthissection,youseehowtolookatthecookiesthatarealreadystoredbyInternetExplorer(IE)onyourcomputer.Youthenloadthecookie-creatingpageyoujustcreatedwiththeprecedingcodetoseewhateffectthishas.Followthesesteps:
1. First,youneedtoopenIE.TheexamplesinthischapteruseIE11,soifyou’reusinganearlierversionofIEyoumayfindthescreenshotsandmenusinslightlydifferentplaces.
2. Beforeyouviewthecookies,firstclearthetemporaryInternetfilefolderforthebrowser,becausethiswillmakeiteasiertoviewthecookiesthatyourbrowserhasstored.ClicktheGeariconandchoosetheInternetOptionsmenuitem,whichisshowninFigure13.1.
Figure13.3
5. Makesuretoselectthetickboxesnextto“TemporaryInternetfilesandwebsitefiles”and“Cookiesandwebsitedata”andthenclicktheDeletebutton.Younowhaveanicecleancache,whichmakesiteasytoseewhenyoucreateacookie.
6. YoucannowclosethedialogboxandreturntothemainInternetOptionsdialogbox.
Let’shavealookatthecookiesyouhavecurrentlyresidingonyourmachine.
7. FromtheInternetOptionsdialogbox,clicktheSettingsbuttonnexttotheDeletebuttongroupedunderBrowsingHistory.YoushouldseethedialogboxshowninFigure13.4.
Figure13.4
8. NowclicktheViewFilesbutton,andalistofallthetemporarypagesandcookiefilesonyourcomputerisdisplayed.IfyoufollowedthepreviousinstructionsanddeletedalltemporaryInternetfiles,thereshouldbenothinglisted,asshowninFigure13.5.
Figure13.5
Theactualcookies,theirnames,andtheirvaluesmaylookslightlydifferentdependingonyourcomputer’soperatingsystem.
Youcanexaminethecontentsofthecookiesbydouble-clickingthem.Notethatyoumaygetawarningaboutthepotentialsecurityriskofopeningatextfile,althoughyouarefairlysafewithcookiesbecausetheyaresimplytextfiles.InFigure13.6youcanseethecontentsofthecookiefilenamedgooglesetbythesearchengineGoogle.
Figure13.6
Asyoucansee,acookieisjustaplainoldtextfile.Eachwebsite,ordomainname,hasitsowntextfilewhereallthecookiesforthatwebsitearestored.Inthiscase,there’sjustonecookiecurrentlystoredforgoogle.com.Domainslikeamazon.comwillalmostcertainlyhavemanycookiesset.
InFigure13.6,youcanseethecookie’sdetails.Here,thenameofthecookieisPREF;itsvalueisaseriesofcharacters,whichalthoughindecipherabletoyoumakesensetotheGooglewebsite.Itwassetbythedomaingoogle.com,anditrelatestotherootdirectory/.Thecontentsprobablylooklikeamessofcharacters,butdon’tworry.Whenyoulearnhowtoprogramcookies,you’llseethatyoudon’tneedtoworryaboutsettingthedetailsinthisformat.
Afteryouhavefinished,closethecookieandclickOKonthedialogboxestoreturntothebrowser.
Nowlet’sloadthefreshbakedcookie.htmlpageintoyourIEbrowser.Thiswillsetacookie.Let’sseehowithaschangedthings:
1. ReturntotheInternetOptionsdialogbox(bychoosingTools ➪ InternetOptions).2. ClicktheSettingsbutton.
3. ClickViewFiles.YourcomputernowshowssomethingliketheinformationinFigure13.7.
Figure13.7
IfyouloadedtheHTMLfilefromyourcomputer,youcreatedacookiefromawebpagestoredonthelocalharddriveratherthanaserver.Thus,itsdomainnamehasbeensettothenameofthedirectoryinwhichthewebpageisstored.Obviously,thisisalittleartificial.Inreality,peoplewillbeloadingyourwebpagesfromyourwebsiteontheInternetandnotoffyourlocalharddrive.TheInternetaddressisbasedonthedirectorythefreshbakedcookie.htmlfilewasin.YoucanalsoseethatitexpiresonDecember31,2020,asyouspecifiedwhenyoucreatedthecookie.Double-clickthecookietoviewitscontents,whichlooklikethoseinFigure13.8.
Figure13.8
Youcanseethenameyougavetothecookieattheleft,UserName,itsvalue,Paul,andalsothedirectoryit’sapplicableto.Theexpirationdateisthereaswell;it’sjustnotinaneasilyrecognizableform.Notethatyoumaysometimesneedtoclosethebrowserandreopenitbeforeyouseethecookiefile.
ViewingCookiesinFirefoxThereisnosharingofcookiesbetweenbrowsers,sothecookiesstoredwhenyouvisitedwebsitesusingIEwon’tbeavailabletoFirefoxandviceversa.TheexamplesinthissectionuseFirefox31.
FirefoxkeepsitscookiesinatotallydifferentplacefromIE,andthecontentsareviewedbyadifferentmeans.ToviewcookiesinFirefox:
1. Clickthe“Hamburger”iconandchooseOptionsasshowninFigure13.9.
Figure13.9
2. SelectthePrivacyoption.
3. Clickthe“removeindividualcookies”linkandyoushouldseethedialogboxshowninFigure13.10.
Figure13.10
4. ClickClosetogetbacktothebrowser,andloadfreshbakedcookie.html.
5. RepeattheprocessyoufollowedpreviouslytogettotheCookieManager,andyoushouldfindthattheUserNamecookiehasbeenaddedtothebox.IfloadedfromyourPCandnottheInternet,thecookiewillhaveablankwebaddress.TheexpandedcookiedetailsareshowninFigure13.11.
Figure13.11
NotethatbuttonsareprovidedatthebottomoftheCookieManagertoremovetheselectedcookieorallofthecookiesthatarestored.
ViewingCookiesinChromeWhenitcomestocookies,ChromeissomewhatsimilartoFirefoxinthatyouviewandmanagethemthroughthebrowser:
1. Clickthe“Hamburger”iconandchooseSettingsasshowninFigure13.12.
Figure13.12
2. Inthe“Searchsettings”box,typecookies.You’llseeChromechangetheSettingspagetolooksomethinglikeFigure13.13.Clickthe“Contentsettings”button.
Figure13.13
3. Inthe“Contentsettings”window,clickthe“Allcookiesandsitedata…”button.Anewwindowpopsupthatletsyoumanageyourcookies(Figure13.14).
Figure13.14
4. Loadfreshbakedcookie.htmlinanewtaborwindow.
5. GobacktotheSettingspageandclicktheRefreshicon.You’llnowseeanentryforthenewcookieasshowninFigure13.15.
Figure13.15
Nowthatyou’veseenhowtoviewcookiesmanually,let’slookathowyoucreatethemandreadthemusingcode.Youstartbylookingateachofthepartsthatmakeupacookiestring.
TheCookieStringWhenyouarecreatingacookie,youcansetsixparts:name,value,expires,path,domain,andsecure,althoughthelatterfouroftheseareoptional.You’llnowlookateachoftheseinturn.
nameandvalueThefirstpartofthecookiestringconsistsofthenameandvalueofthecookie.Thenameisusedsothatyoucanreferencethecookielater,andthevalueistheinformationpartofthecookie.
Thisname/valuepartofthecookiestringiscompulsory;itsortofdefeatsthepointofthecookieifyoudon’tstoreanameorvalue,becausestoringinformationiswhatcookiesareallabout.Youshouldmakesurethatthispartcomesfirstinthecookiestring.
Thevalueforthecookieisaprimitivestring,althoughthestringcanholdnumber
charactersifitisnumericaldatathatyouwanttostore.Ifyouarestoringtext,certaincharacters,suchassemicolons,cannotbeusedinsidethevalue,unlessyouuseaspecialencoding,whichyou’llseelater.Inthecaseofsemicolons,thisisbecausetheyareusedtoseparatethedifferentpartsofthecookiewithinthecookiestring.
Inthefollowinglineofcode,yousetacookiewiththenameUserNameandthevaluePaul:
document.cookie="UserName=Paul;";
Thiscookiehasaverylimitedlifespan,whichisthelengthoftimetheinformationwillcontinuetoexist.Ifyoudon’tsetanexpirationdate,acookiewillexpirewhentheuserclosesthebrowser.Thenexttimetheuseropensthebrowserthecookiewillbegone.Thisisfineifyoujustwanttostoreinformationforthelifeofausersession,whichisasinglevisitbytheusertoyourwebsite.However,ifyouwanttoensurethatyourcookieisavailableforlonger,youmustsetitsexpirationdate,whichyoulookatnext.
expiresIfyouwantacookietoexistforlongerthanjustasingleusersession,youneedtosetanexpirationdateusingthesecondpartofthecookiestring,expires,asfollows:
document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00GMT;";
ThecookiesetbythepreviouslineofcodewillremainavailableforfutureuserightupuntilDecember28,2020.
NOTETheformatoftheexpirationdateisveryimportant.ItshouldbethesameformatthecookieisgivenbythetoUTCString()method.
Inpractice,you’llprobablyusetheDateobjecttogetthecurrentdate,andthensetacookietoexpirethreeorsixmonthsafterthisdate.Otherwise,you’regoingtoneedtorewriteyourpagesonDecember28,2020.
Forexample,youcouldwritethefollowing:
varexpire=newDate();
expire.setMonth(expire.getMonth()+6);
document.cookie="UserName=Paul;expires="+expire.toUTCString()+";";
ThiswillcreateanewcookiecalledUserNamewiththevalueofPaul,whichwillexpiresixmonthsfromthecurrentdate.Notethatotherfactorscancauseacookietoexpirebeforeitsexpirationdate,suchastheuserdeletingthecookieortheuppercookielimitbeingreached.
pathYou’llfindthat99percentofthetimeyouwillonlyneedtosetthename,value,andexpirespartsofacookie.However,attimestheotherthreeparts,suchasthepathpartthatyouarelookingatinthissection,needtobeset.Thefinaltwoparts,domainandsecure,areforadvancedusebeyondthescopeofabeginners’book,butyou’lllookat
thembrieflyjustforcompleteness.
You’reprobablyusedtotheideaoftherebeingdirectoriesonyourharddrive.Ratherthanstoringeverythingonyourcomputerinoneplaceontheharddrive,youdivideitintothesedirectories.Forexample,youmightkeepyourword-processingfilesinMyDocuments,yourimagefilesinMyImages,andsoon.Youprobablyalsosubdivideyourdirectories,sounderMyImagesyoumighthavesubdirectoriescalledMyFamilyandMyHoliday.
Well,webserversusethesameprinciple.Ratherthanputtingthewholewebsiteintoonewebdirectory,it’scommonandindeedsensibletodivideitintovariousdifferentdirectories.Forexample,ifyouvisittheWroxwebsiteatwww.wrox.comandthenclickoneofthebookcategories,you’llfindthatthepathtothepagenavigatedtoisnowwww.wrox.com/Books/.
Thisisallveryinteresting,butwhyisitrelevanttocookies?
Theproblemisthatcookiesarespecificnotonlytoaparticularwebdomain,suchaswww.wrox.com,butalsotoaparticularpathonthatdomain.Forexample,ifapageinwww.wrox.com/Books/setsacookie,onlypagesinthatdirectoryoritssubdirectorieswillbeabletoreadandchangethecookie.Ifapageinwww.wrox.com/academic/triedtoreadthecookie,itwouldfail.Whyarecookiesrestrictedlikethis?
Takethecommonexampleoffreewebspace.Alotofcompaniesonthewebenableyoutosignupforfreewebspace.Usuallyeveryonewhosignsupforthiswebspacehasasiteatthesamedomain.Forexample,Bob’swebsitemightbeatwww.freespace.com/members/bob/.Belindamighthavehersatwww.freespace.com/members/belinda.Ifcookiescouldberetrievedandchangedregardlessofthepath,thenanycookiessetonBob’swebsitecouldbeviewedbyBelindaandviceversa.Thisisclearlysomethingneitherofthemwouldbehappyabout.Notonlyisthereasecurityproblem,butif,unknowntoeachother,theybothhaveacookienamedMyHotCookie,therewouldbeproblemswitheachofthemsettingandretrievingthesamecookie.Whenyouthinkhowmanyusersafreewebspaceprovideroftenhas,youcanseethatthereispotentialforchaos.
Okay,sonowyouknowthatcookiesarespecifictoacertainpath,butwhatifyouwanttoviewyourcookiesfromtwodifferentpathsonyourserver?Say,forexample,youhaveanonlinestoreatwww.mywebsite.com/mystore/butyousubdividethestoreintosubdirectories,suchas/Booksand/Games.Nowlet’simaginethatyourcheckoutisinthedirectorywww.mywebsite.com/mystore/Checkout.Anycookiessetinthe/Booksand/Gamesdirectorieswon’tbevisibletoeachotherorpagesinthe/Checkoutdirectory.Togetaroundthisyoucaneithersetcookiesonlyinthe/mystoredirectory(becausethesecanbereadbythatdirectoryandanyofitssubdirectories),oryoucanusethepathpartofthecookiestringtospecifythatthepathofthecookieis/mystoreevenifit’sbeingsetinthe/Gamesor/Booksor/Checkoutsubdirectories.
Forexample,youcoulddothislikeso:
document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00"+
";path=/mystore;";
Now,evenifthecookieissetbyapageinthedirectory/Books,itwillstillbeaccessibletofilesinthe/mystoredirectoryanditssubdirectories,suchas/Checkoutand/Games.
Ifyouwanttospecifythatthecookieisavailabletoallsubdirectoriesofthedomainitissetin,youcanspecifyapathoftherootdirectoryusingthe/character:
document.cookie="UserName=Paul;expires=Tue,28Dec2020
00:00:00;path=/;";
Now,thecookiewillbeavailabletoalldirectoriesonthedomainitissetfrom.Ifthewebsiteisjustoneofmanyatthatdomain,it’sbestnottodothisbecauseeveryoneelsewillalsohaveaccesstoyourcookieinformation.
It’simportanttonotethatalthoughWindowscomputersdon’thavecase-sensitivedirectorynames,manyotheroperatingsystemsdo.Forexample,ifyourwebsiteisonaUnix-orLinux-basedserver,thepathpropertywillbecase-sensitive.
domainThefourthpartofthecookiestringisthedomain.Anexampleofadomainiswrox.comorbeginningjs.com.Likethepathpartofthecookiestring,thedomainpartisoptionalandit’sunlikelythatyou’llfindyourselfusingitveryoften.
Bydefault,cookiesareavailableonlytopagesinthedomaininwhichtheywereset.Forexample,ifyouhaveyourfirstwebsiterunningonaserverwiththedomainmypersonalwebsite.mydomain.comandyouhaveasecondwebsiterunningundermybusinesswebsite.mydomain.com,acookiesetinonewebsitewillnotbeavailabletopagesaccessedundertheotherdomainname,andviceversa.Mostofthetime,thisisexactlywhatyouwant,butifitisnot,youcanusethedomainpartofthecookiestringtospecifythatacookieisavailabletoallsubdomainsofthespecifieddomain.Forexample,thefollowingsetsacookiethatcanbesharedacrossbothsubdomains:
document.cookie="UserName=Paul;expires=Tue,28Dec202000:00:00;path=/"
+
";domain=mydomain.com;";
Notethatthedomainmustbethesame.Youcan’tsharewww.someoneelsesdomain.comwithwww.mydomain.com.
secureThefinalpartofthecookiestringisthesecurepart.Thisissimplyabooleanvalue;ifit’ssettotruethecookiewillbesentonlytoawebserverthattriestoretrieveitusingasecurechannel.Thedefaultvalue,whichisfalse,meansthecookiewillalwaysbesent,regardlessofthesecurity.ThisisonlyapplicablewhereyouhavesetupaserverwithSSL(SecureSocketsLayer).
CREATINGACOOKIETomakelifeeasierforyourself,you’llwriteafunctionthatenablesyoutocreateanewcookieandsetcertainofitsattributeswithmoreease.Thisisthefirstofanumberofusefulfunctionsyou’llcreateandaddtoaseparate.jsfilesoyoucaneasilyreusethecodeinyourfutureprojects.You’lllookatthecodefirstandcreateanexampleusingitshortly.Firstcreateafilecalledcookiefunctions.jsandaddthefollowingtoit:
functionsetCookie(name,value,path,expires){
value=escape(value);
if(!expires){
varnow=newDate();
now.setMonth(now.getMonth()+6);
expires=now.toUTCString();
}
if(path){
path=";Path="+path;
}
document.cookie=name+"="+value+";expires="+expires+path;
}
Thesecureanddomainpartsofthecookiestringareunlikelytobeneeded,soyouallowjustthename,value,expires,andpathpartsofacookietobesetbythefunction.Ifyoudon’twanttosetapathorexpirationdate,youcanomitthemorpassemptystringsforthoseparameters.Ifnopathisspecified,thecurrentdirectoryanditssubdirectorieswillbethepath.Ifnoexpirationdateisset,youjustassumeadatesixmonthsfromnow.
Thefirstlineofthefunctionintroducestheescape()function,whichyou’venotseenbefore:
value=escape(value);
Whenwetalkedaboutsettingthevalueofacookie,wementionedthatcertaincharacterscannotbeuseddirectly,suchasasemicolon.(Thisalsoappliestothenameofthecookie.)Togetaroundthisproblem,youcanusethebuilt-inescape()andunescape()functions.Theescape()functionconvertscharactersthatarenottextornumbersintothehexadecimalequivalentoftheircharacterintheLatin-1characterset,precededbya%character.
Forexample,aspacehasthehexadecimalvalue20,andthesemicolonthevalue3B.SothefollowingcodeproducestheoutputshowninFigure13.16:
Figure13.16
alert(escape("2001aspaceodyssey;"));
Youcanseethateachspacehasbeenconvertedto%20,the%indicatingthatitrepresentsanescapeorspecialcharacterratherthananactualcharacter,andthat20istheASCIIvalueoftheactualcharacter.Thesemicolonhasbeenconvertedto%3B,asyou’dexpect.
Asyouseelater,whenretrievingcookievaluesyoucanusetheunescape()functiontoconvertfromtheencodedversiontoplaintext.
Backtoyourfunction;nextyouhaveanifstatement:
if(!expires){
varnow=newDate();
now.setMonth(now.getMonth()+6);
expires=now.toUTCString();
}
Thisdealswiththesituationinwhichtheexpiresparameterdoesnotcontainausablevalue(eitherbyomittingitorpassinganemptystring"").Becausemostofthetimeyouwantacookietolastlongerthanthesessionit’screatedin,yousetadefaultvalueforexpiresthatissixmonthsafterthecurrentdate.
Next,ifavaluehasbeenpassedtothefunctionforthepathparameter,youneedtoaddthatvaluewhenyoucreatethecookie.Yousimplyput"path="infrontofanyvaluethathasbeenpassedinthepathparameter:
if(path){
path=";Path="+path;
}
Finally,onthelastlineyouactuallycreatethecookie,puttingtogetherthename,cvalue,expires,andpathpartsofthestring:
document.cookie=name+"="+value+";expires="+expires+path;
You’llbeusingthesetCookie()functionwheneveryouwanttocreateanewcookiebecauseitmakessettingacookieeasierthanhavingtorememberallthepartsyouwanttoset.Moreimportant,itcanbeusedtosettheexpirationdatetoadatesixmonthsaheadofthecurrentdate.
Forexample,tousethefunctionandsetacookiewithdefaultvaluesforexpiresandpath,youjusttypethefollowing:
setCookie("cookieName","cookieValue");
TRYITOUTUsingsetCookie()YounowputallthistogetherinasimpleexampleinwhichyouuseyoursetCookie()functiontosetthreecookiesnamedName,Age,andFirstVisit.Youthendisplaywhatisinthedocument.cookiepropertytoseehowithasbeenaffected.
Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Example1</title>
</head>
<body>
<scriptsrc="cookiefunctions.js"></script>
<script>
setCookie("Name","Bob");
setCookie("Age","101");
setCookie("FirstVisit","10May2007");
alert(document.cookie);
</script>
</body>
</html>
Savetheexampleasch13_example1.htmlandloaditintoawebbrowser.
You’llseethealertboxshowninFigure13.17.Notethatallthreecookiesaredisplayedasname/valuepairsseparatedfromtheothersbysemicolons,andalsothattheexpirationdateisnotdisplayed.Ifyouhadsetthepathparameter,thisalsowouldnothavebeendisplayed.TheUserNamecookiefromapreviousexampleisalsodisplayed.
Figure13.17
YoualreadyknowhowthesetCookie()functionworks,solet’slookatthethreelinesthatusethefunctiontocreatethreenewcookies:
setCookie("Name","Bob");
setCookie("Age","101");
setCookie("FirstVisit","10May2007");
Itisallfairlysimple.Thefirstparameteristhenamethatyou’llgivethecookie.(Youseeshortlyhowyoucanretrieveavalueofacookiebasedonthenameyougaveit.)It’simportantthatthenamesyouusebeonlyalphanumericcharacters,withnospaces,punctuation,orspecialcharacters.Althoughyoucanusecookienameswiththesecharacters,doingsoismorecomplexandbestavoided.Nextyouhavethevalueyouwanttogivethecookie.Thethirdparameteristhepath,andthefourthparameteristhedateonwhichyouwantthecookietoexpire.
Forexample,takethefirstlinewhereyouusethesetCookie()function.HereyouaresettingacookiethatwillbenamedNameandhavethevalueBob.Youdon’twanttosetthepathorexpiresparts,soyouomitthoseparameters.
TheremainingtwolinesinthepreviouscodesnippetsetthecookiesnamedAgeandFirstVisitandsettheirvaluesto101and10May2007,respectively.
Ifyoudidwanttosetthepathandtheexpirationdate,howmightyouchangeyourcode?
Well,imaginethatyouwantthepathtobe/MyStoreandtheexpirationdatetobeoneyearinthefuture.ThenyoucanusethesetCookie()functioninthefollowingway:
varexpires=newDate();
expires.setMonth(expires.getMonth()+12);
setCookie("Name","Bob","/MyStore",expires.toUTCString());
First,youcreateanewDateobject,andbypassingnoparametertoitsconstructor,youletitinitializeitselftothecurrentdate.Inthenextline,youadd12monthstothatdate.WhensettingthecookieusingsetCookie()youpass"/MyStore"asthepathandexpires.toUTCString()astheexpiresparameter.
Whataboutthesituationinwhichyou’vecreatedyourcookie,say,onenamedNamewithavalueofBob,andyouwanttochangeitsvalue?Todothis,youcansimplysetthesamecookieagain,butwiththenewvalue.TochangethecookienamedNamefromavalueofBobtoavalueofBobby,you’dneedthefollowingcode:
setCookie("Name","Bobby");
Whatifyouwanttodeleteanexistingcookie?Well,that’seasy.Justmakeitexpirebychangingitsvalueandsettingitsexpirationdatetoadateinthepast,asinthefollowingexample:
setCookie("Name","","","Mon,1Jan199000:00:00");
GETTINGACOOKIE’SVALUEIntheprecedingexample,youuseddocument.cookietoretrieveastringcontaininginformationaboutthecookiesthathavebeenset.However,thisstringhastwolimitations:
Thecookiesareretrievedinname/valuepairs,witheachindividualcookieseparatedbyasemicolon.Theexpires,path,domain,andsecurepartsofthecookiearenotavailabletoyouandcannotberetrieved.
Thecookiepropertyenablesyoutoretrieveonlyallthecookiessetforaparticularpathand,whentheyarehostedonawebserver,thatwebserver.So,forexample,there’snosimplewayofjustgettingthevalueofacookiewiththenameAge.Todothisyou’llhavetousethestringmanipulationtechniquesyoulearnedinpreviouschapterstocuttheinformationyouwantoutofthereturnedstring.
Alotofdifferentwaysexisttogetthevalueofanindividualcookie,butthewayyou’llusehastheadvantageofworkingwithallcookie-enabledbrowsers.Youusethefollowingfunction,whichyouneedtoaddtoyourcookiefunctions.jsfile:
functiongetCookieValue(name){
varvalue=document.cookie;
varcookieStartsAt=value.indexOf(""+name+"=");
if(cookieStartsAt==-1){
cookieStartsAt=value.indexOf(name+"=");
}
if(cookieStartsAt==-1){
value=null;
}else{
cookieStartsAt=value.indexOf("=",cookieStartsAt)+1;
varcookieEndsAt=value.indexOf(";",cookieStartsAt);
if(cookieEndsAt==-1){
cookieEndsAt=value.length;
}
value=unescape(value.substring(cookieStartsAt,
cookieEndsAt));
}
returnvalue;
}
Thefirsttaskofthefunctionistogetthedocument.cookiestringandstoreitinthevaluevariable:
varvalue=document.cookie;
Next,youneedtofindoutwherethecookiewiththenamepassedasaparametertothefunctioniswithinthevaluestring.YouusetheindexOf()methodoftheStringobjectto
findthisinformation,asshowninthefollowingline:
varcookieStartsAt=value.indexOf(""+name+"=");
Themethodwillreturneitherthecharacterpositionwheretheindividualcookieisfoundor-1ifnosuchname,andthereforenosuchcookie,exists.Yousearchon"”+name+"="sothatyoudon’tinadvertentlyfindcookienamesorvaluescontainingthenamethatyourequire.Forexample,ifyouhavexFoo,Foo,andyFooascookienames,asearchforFoowithoutaspaceinfrontwouldmatchxFoofirst,whichisnotwhatyouwant!
IfcookieStartsAtis-1,thecookieeitherdoesnotexistorit’sattheverybeginningofthecookiestringsothereisnospaceinfrontofitsname.Toseewhichoftheseistrue,youdoanothersearch,thistimewithnospace:
if(cookieStartsAt==-1){
cookieStartsAt=value.indexOf(name+"=");
}
Inthenextifstatement,youchecktoseewhetherthecookiehasbeenfound.Ifithasn’t,yousetthevaluevariabletonull:
if(cookieStartsAt==-1){
value=null;
}
Ifthecookiehasbeenfound,yougetthevalueofthecookieyouwantfromthedocument.cookiestringinanelsestatement.Youdothisbyfindingthestartandtheendofthevaluepartofthatcookie.Thestartwillbeimmediatelyaftertheequalssignfollowingthename.Sointhefollowingline,youfindtheequalssignfollowingthenameofthecookieinthestringbystartingtheindexOf()searchforanequalssignfromthecharacteratwhichthecookiename/valuepairstarts:
else{
cookieStartsAt=value.indexOf("=",cookieStartsAt)+1;
Youthenaddonetothisvaluetomovepasttheequalssign.
Theendofthecookievaluewilleitherbeatthenextsemicolonorattheendofthestring,whichevercomesfirst.Youdoasearchforasemicolon,startingfromthecookieStartsAtindex,inthenextline:
varcookieEndsAt=value.indexOf(";",cookieStartsAt);
Ifthecookieyouareafteristhelastoneinthestring,therewillbenosemicolonandthecookieEndsAtvariablewillbe-1fornomatch.Inthiscaseyouknowtheendofthecookievaluemustbetheendofthestring,soyousetthevariablecookieEndsAttothelengthofthestring:
if(cookieEndsAt==-1){
cookieEndsAt=value.length;
}
Youthengetthecookie’svalueusingthesubstring()methodtocutthevaluethatyou
wantoutofthemainstring.Becauseyouhaveencodedthestringwiththeescape()function,youneedtounescapeittogettherealvalue,hencetheuseoftheunescape()function:
value=unescape(value.substring(cookieStartsAt,
cookieEndsAt));
Finally,youreturnthevalueofthecookietothecallingfunction:
returnvalue;
TRYITOUTWhat’sNew?Nowyouknowhowtocreateandretrievecookies.Let’susethisknowledgeinanexampleinwhichyouchecktoseeifanychangeshavebeenmadetoawebsitesincetheuserlastvisitedit.
You’llbecreatingtwopagesforthisexample.Thefirstisthemainpageforawebsite;thesecondisthepagewithdetailsofnewadditionsandchangestothewebsite.Alinktothesecondpagewillappearonthefirstpageonlyiftheuserhasvisitedthepagebefore(thatis,ifacookieexists)buthasnotvisitedsincethepagewaslastupdated.
Let’screatethefirstpage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Example2a</title>
</head>
<body>
<h1>WelcometoExample2a</h1>
<divid="whatsNew"></div>
<scriptsrc="cookiefunctions.js"></script>
<script>
varlastUpdated=newDate("Tue,28Dec2020");
varlastVisit=getCookieValue("LastVisit");
if(lastVisit){
lastVisit=newDate(lastVisit);
if(lastVisit<lastUpdated){
document.getElementById("whatsNew").innerHTML=
"<ahref='ch13_example2b.html'>What'sNew?</a>";
}
}
varnow=newDate();
setCookie("LastVisit",now.toUTCString());
</script>
</body>
</html>
Savethispageasch13_example2a.html.Notethatitusesthetwofunctions,setCookie()andgetCookieValue(),thatyoucreatedearlier.
Next,youjustcreateasimplepagetolinktofortheWhat’sNew?details:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Example2b</title>
</head>
<body>
<h1>WelcometoExample2b</h1>
<h3>Here'swhat'snew!</h3>
</body>
</html>
Savethispageasch13_example2b.html.
Loadch13_example2a.htmlintoabrowser.Thefirsttimeyougotothemainpage,therewillbenothingbutaheadingsaying“WelcometoExample2a.”Obviously,ifthiswerearealwebsite,itwouldhaveabitmorethanthat,butitsufficesforthisexample.However,refreshthepageandsuddenlyyou’llseethepageshowninFigure13.18.
Figure13.18
Ifyouclickthelink,you’retakentothech13_example2b.htmlpagedetailingallthethingsaddedtothewebsitesinceyoulastvisited.Obviously,nothinghasactuallychangedinyourexamplewebsitebetweenyouloadingthepageandthenrefreshingit.Yougotaroundthisfortestingpurposesbysettingthedatewhenthewebsitelastchanged,storedinvariablelastUpdated,toadateinthefuture(here,December28,2020).
Thech13_example2b.htmlpageisjustasimpleHTMLpagewithnoscript,soyouwillconfineyourattentiontoch13_example2a.html.Inthescriptblock,youdeclarethevariablelastUpdated:
varlastUpdated=newDate("Tue,28Dec2020");
Wheneveryoumakeachangetothewebsite,thisvariableneedstobechanged.It’scurrentlysettoTue,28Dec2020,justtomakesureyouseetheWhat’sNew?linkwhenyourefreshthepage.Abetteralternativeforlivepageswouldbethedocument.lastModifiedproperty,whichreturnsthedateonwhichthepagewaslastchanged.
Next,yougetthedateoftheuser’slastvisitfromtheLastVisitcookieusingthegetCookieValue()function:
varlastVisit=getCookieValue("LastVisit");
Ifit’sfalsy,theuserhaseitherneverbeenherebefore,orithasbeensixormoremonthssincethelastvisitandthecookiehasexpired.Eitherway,youwon’tputtheWhat’sNew?linkupbecauseeverythingisnewiftheuserisafirst-timevisitor,andalothasprobablychangedinthelastsixmonths—morethanwhatyourWhat’sNew?pagewilldetail.
IflastVisithasavalue,youneedtocheckwhethertheuservisitedthesitebeforeitwaslastupdated,andifsotodirecttheusertoapagethatshowswhatisnew.Youdothiswithintheifstatement:
if(lastVisit){
lastVisit=newDate(lastVisit);
if(lastVisit<lastUpdated){
document.getElementById("whatsNew").innerHTML=
"<ahref='ch13_example2b.html'>What'sNew?</a>";
}
}
YoufirstcreateanewDateobjectbasedonthevalueoflastVisitandstorethatbackintothelastVisitvariable.Then,intheconditionoftheinnerifstatement,youcomparethedateoftheuser’slastvisitwiththedateonwhichyoulastupdatedthewebsite.Ifthingshavechangedsincetheuser’slastvisit,youwritetheWhat’sNew?linktothepage,sotheusercanclickitandfindoutwhat’snew.Finally,attheendofthescriptyouresettheLastVisitcookietotoday’sdateandtimeusingthesetCookie()function:
varnow=newDate();
COOKIELIMITATIONSYoushouldbeawareofanumberoflimitationswhenusingcookies.
AUserMayDisableCookiesThefirstlimitationisthatalthoughallmodernbrowserssupportcookies,theusermayhavedisabledthem.InFirefoxyoucandothisbyselectingtheOptionsmenu,followedbythePrivacytabandtheCookiestab.InIEyouselectInternetOptionsonthegearmenu.SelectthePrivacytabandyoucanchangethelevelwiththescrollcontrol.AndinChrome,choosetheSettingsoptionfromthegearmenu,searchforcookies,andclick“Contentsettings.”Mostusershavesessioncookiesenabledbydefault.Sessioncookiesarecookiesthatlastforaslongastheuserisbrowsingyourwebsite.Afterhe’sclosedthebrowserthecookiewillbecleared.Morepermanentcookiesarealsonormallyenabledbydefault.However,third-partycookies,thosefromathird-partysite,areusuallydisabled.Thesearethecookiesusedfortrackingpeoplefromsitetositeandhencetheonesthatraisethemostprivacyconcerns.
Boththefunctionsthatyou’vemadeforcreatingandgettingcookieswillcausenoerrorswhencookiesaredisabled,butofcoursethevalueofanycookiesetwillbenullandyouneedtomakesureyourcodecancopewiththis.
Youcouldsetadefaultactionforwhencookiesaredisabled.Inthepreviousexample,ifcookiesaredisabled,theWhat’sNew?linkwillneverappear.
Alternatively,youcanlettheuserknowthatyourwebsiteneedscookiestofunctionbyputtingamessagetothateffectinthewebpage.
Anothertacticistoactivelychecktoseewhethercookiesareenabledand,ifnot,totakesomeactiontocopewiththis,suchasbydirectingtheusertoapagewithlessfunctionalitythatdoesnotneedcookies.Howdoyouchecktoseeifcookiesareenabled?
Inthefollowingscript,yousetatestcookieandthenreadbackitsvalue.Ifthevalueisnull,youknowcookiesaredisabled:
setCookie("TestCookie","Yes");
if(!getCookieValue("TestCookie")){
alert("Thiswebsiterequirescookiestofunction");
}
NumberandInformationLimitationAsecondlimitationisonthenumberofcookiesyoucansetontheuser’scomputerforyourwebsiteandhowmuchinformationcanbestoredineach.Inolderbrowsers,foreachdomain,itwascommonthatyoucouldstoreonlyupto20cookies,andeachcookiepair—thatis,thenameandvalueofthecookiecombined—mustnotbemorethan4,096characters(4KB)insize.It’salsoimportanttobeawarethatallbrowsersdosetsomeupperlimitforthenumberofcookiesstored.Whenthatlimitisreached,oldercookies,regardlessofexpirationdate,areoftendeleted.Somemodernbrowsershavea50-cookie
limit,thoughthismayvary.
Togetaroundthecookielimits,youcanstoremorethanonepieceofinformationpercookie.Thisexampleusesmultiplecookies:
setCookie("Name","Karen")
setCookie("Age","44");
setCookie("LastVisit","10Jan2001");
Youcouldcombinethisinformationintoonecookie,witheachdetailseparatedbyasemicolon:
setCookie("UserDetails","Karen;44;10Jan2001");
BecausethesetCookie()functionescapesthevalueofthecookie,thereisnoconfusionbetweenthesemicolonsseparatingpiecesofdatainthevalueofthecookie,andthesemicolonsseparatingthepartsofthecookie.WhenyougetthecookievaluebackusinggetCookieValue(),youjustsplititintoitsconstituentparts;however,youmustremembertheorderyoustoreditin:
varcookieValues=getCookieValue("UserDetails");
cookieValues=cookieValues.split(";");
alert("Name="+cookieValues[0]);
alert("Age="+cookieValues[1]);
alert("LastVisit="+cookieValues[2]);
Nowyouhaveacquiredthreepiecesofinformationandstillhave19cookiesleftinthejar.Thisapproach,however,islessthanideal,andyoulearnhowtostoredatausingnewertechnologieslaterinthischapter.
COOKIESECURITYANDIEIE6introducedanewsecuritypolicyforcookiesbasedontheP3PaninitiativesetupbytheWorldWideWebConsortium(W3C).ThegeneralaimofP3Pistoreassureuserswhoareworriedthatcookiesarebeingusedtoobtainpersonalinformationabouttheirbrowsinghabits.InIEyoucanselecttheGearmenu ➪ InternetOptionsandclickthePrivacytabtoseewhereyoucansetthelevelofprivacywithregardstocookies(seeFigure13.19).Youhavetostrikeabalancebetweensettingitsohighthatnowebsitewillworkandsolowthatyourbrowsinghabitsandpotentiallypersonaldatamayberecorded.
Figure13.19
Generally,bydefaultsessioncookies—cookiesthatlastforonlyaslongastheuserisbrowsingyourwebsite—areallowed.Assoonastheuserclosesthebrowser,thesessionends.However,ifyouwantcookiestooutlasttheuser’svisittoyourwebsite,youneedtocreateaprivacypolicyinlinewiththeP3Precommendations.Thissoundsalittlecomplex,andcertainlythefinedetailsofthepolicycanbe.Becauseofthiscomplexity,veryfewimplementationsofP3Pexist.Butmanygroupsareworkingtomakeiteasierforpeopletouse.
WEBSTORAGECookiesareausefultoolthatwebdeveloperscantakeadvantageoftostoredataontheuser’scomputer.Butcookiesareatooldesignedforadifferenttime,andthus,adifferentWeb.Althoughtheyservedaspecificpurpose(anddidsoreasonablywell),theirlimitationsarenotidealformodernJavaScriptdevelopment:
Thefirstissueistheapplicationprogramminginterface(API).Towriteandreadcookies,youusethedocument.cookieproperty.Writingacookieisrelativelystraightforward,butreadingaspecificcookierequiresalotofcode.Youwrotetwohelperfunctionstomakewritingandreadingcookieseasier,butideally,youshouldn’thaveto.
Cookiesarenotabrowserfeature,butafeatureofHTTP.Assuch,thebrowsersendsthemtotheserveroneveryrequest.Thisisusefulforapplicationsthatliveontheserver,butit’sunnecessaryforJavaScriptthatrunsinthebrowser.
Thebrowserlimitstheamountofcookiesitstoresandthesizetheycanbe.Asmentionedearlier,thiscanbeanywherefrom20to50cookiesforeachdomain,andeachcookiecannotexceed4KB.
Cookiesaresharedbetweenboththebrowserandtheserver.Ifyourserverapplicationneeds30cookies(120KB)tofunction,thatatbestleavesyouwith20cookies(80KB).You’reoutofluckifyouneedmore.
Theycanexpire.Althoughyoucancontrolthisbysettingandmaintaininganexpirationdate,it’ssimplertonothaveone.
HTML5introducedanewfeaturecalledwebstorage,anditsolveseachofcookies’aforementionedproblems.Sinceitsintroduction,webstoragehasbeenmovedoutoftheHTML5specificationandintoitsown(whichisnamedWebStorage).Itconsistsoftwocomponents:sessionstorageandlocalstorage.Asyoumayhaveguessed,sessionstorageistemporarystoragethatisclearedwhentheuserclosesthebrowser(likeacookiewithoutanexpirationdate).Butinmostcases,youwanttostoredatathatpersistsbetweenvisits,andthatislocalstorage’spurpose.Othernoteworthyfeaturesofwebstorageare:
Itstayswithinthebrowserandisnottransmittedtotheserver.ItisstorageforJavaScriptdevelopers.
Itprovidessignificantlymorestoragespace.ChromeandFirefoxsupport5MBperdomain.IEsupports10MB.
Thedatastoredinlocalstorageneverexpires;itremainsuntilyouortheuserdeletesit.
NOTEThissectionfocusesonlocalstorage,butyoucanapplythesameconceptstosessionstorage.
Thedatastoredinwebstorageisassociatedwithauniquename.Intechnicalterms,we
refertothisnameasakey,andthedataassociatedwithakeyisreferredtoasthevalue.Together,werefertothekeyanditsvalueasakey/valuepair.
YouaccesslocalstorageusingthelocalStorageobject(sessionstorageisaccessedthroughsessionStorage),anditmakesiteasytoset,get,andremovedata.
SettingDataThelocalStorageobjectexposesamethodcalledsetItem(),anditspurposeistosetavalueassociatedwithagivenkey.It’sverysimpletouse,asshownhere:
localStorage.setItem("userName","Paul");
ThefirstargumentpassedtosetItem()isthekey;thesecondisthevalueassociatedwiththatkey.Inthecaseofthiscode,thevalueofPaulisstoredinlocalstorageandisassociatedwiththekeyofuserName.
Youcanalsosetdatausingthemoretraditionalobject.propertyNamesyntax,likeso:
localStorage.userName="Paul";
TheresultofthiscodeisidenticaltotheprevioussetItem()example;thevalueofPaulissetforthekeyofuserName.
Iftheresultsareidentical,whyusesetItem()?Theansweristhatyoudon’thavetounlessyourkeyisaninvalidJavaScriptidentifier.Forexample,let’ssayyouwanttousethekeyusername.That’simpossibletouseasapropertyname:
localStorage.username="Paul";//invalid!
Butyoucanuse“username”asakeywiththesetItem()method:
localStorage.setItem("username","Paul");
Inmostcases,youwon’tusesetItem(),butitistheretouseifandwhenyouneedto.
GettingDataRetrievingdatafromlocalstorageisjustasstraightforwardassettingit.WiththegetItem()method,yousupplythekeyforwhichyouwantthevalueof:
varname=localStorage.getItem("userName");
ThiscodeusesthegetItem()methodtoretrievethevalueassociatedwiththe“userName”keyandassignsthatvaluetothenamevariable.Inthecaseoftheexamplefromtheprevioussection,namewouldcontain“Paul“.
YoucanalsousethekeyaslocalStorage’spropertyifitisavalididentifier:
varname=localStorage.userName;
ThiscodealsogetsthevalueofPaulandassignsittothenamevariable.
Awordofnote:Keysarecase-sensitive.Thatmayseemobviousifyouareusing
object.propertyNamesyntax,buttheruleappliestosetItem()andgetItem().Forexample:
localStorage.setItem("userName","Paul");
varname=localStorage.getItem("UserName");//null
ThiscodesetakeyofuserNamewithavalueofPaul.ItthentriestoretrieveavaluewiththekeyofUserName.BecauseoftheuppercaseU,UserNameanduserNamearetwodifferentkeys.Wehaven’tsetavaluewithUserName,sogetItem()returnsnull.
RemovingDataEventually,youwillwanttoremovesomedatathatyoustoredinlocalstorage,andyoucandothatwiththeremoveItem()method.Simplyprovidethekeyyouwanttoremove,andthekey/valuepairwillbedeletedfromlocalstorage.Forexample:
localStorage.removeItem("userName");
ThiscodedeletestheuserName/Paulkey/valuepairfromlocalstorage.IfthekeyisavalidJavaScriptidentifier,youcanalsouseobject.propertyNamesyntaxtodothesamething,likeso:
localStorage.userName=null;
Here,youassignthevalueofnulltotheuserNamekey/property,thusremovingthekey/valuepairfromlocalstorage.
Ifyourgoalistoremoveallkeysandvaluesfromlocalstorage,youcanusetheclear()method,likethis:
localStorage.clear();//nomorekey/valuepairs
StoringDataasStringsIt’simportanttonotethatwebstorageisastring-onlydatastore.Thismeansthatkeysandtheirvaluescanonlybestrings.Ifyoutrytostoresomeothertypeofvalue(likeanumber)orobject,itisconvertedtoastringandstoredasastring.Forexample,let’ssayyouwanttostoretheuser’sageinlocalstorage.Youcaneasilydosolikethis:
localStorage.age=35;
Asyourightlysuspect,thiscreatesakey/valuepairofage/35.But35wasconvertedtoastringbeforeitwasstoredinlocalstorage.Therefore,whenyouretrievethevalueassociatedwiththeagekey,youhavethestringof35:
varage=localStorage.age;
alert(typeofage);//string
Thismeansthattouseageinanymathematiccalculations,youneedtoconvertittoanumber.That’seasyenoughtofix:
varage=parseInt(localStorage.age,10);
Butwhataboutmorecomplexobjects?Considerthefollowingobjectasanexample:
varjohnDoe={
firstName:"John",
lastName:"Doe",
age:35
};
ThisjohnDoeobjectrepresentsanindividualpersonnamedJohnDoe,andheis35yearsold.Wewanttosavethisobjectinlocalstorage,soweassignitasthevaluetothepersonkey,likethis:
localStorage.person=johnDoe;
Butthere’saproblemhere:Thepersonobjectcannotbereasonablyconvertedintoastring.
Whenyouassignavalueorobjecttoakey,itstoString()methodisautomaticallycalledtoconvertittoastring.ForprimitivetypeslikeNumberandBoolean,wegetthestringrepresentationofthatvalue.Butbydefault,anobject’stoString()methodreturns“[objectObject]“.Thereforeintheprecedingexample,thestring“[objectObject]”isstoredinlocalStorage.person:
varsavedPerson=localStorage.person;
alert(typeofsavedPerson);//string
alert(savedPerson);"[objectObject]"
Thissoundslikeahugelimitation(anditis!),butwecanserializeobjectsintoJSONandparsethembackintoactualobjects.Therefore,wecanwritethis:
localStorage.person=JSON.stringify(johnDoe);
varsavedPerson=JSON.parse(localStorage.person);
ThiscodeserializesthejohnDoeobjectandstorestheresultingJSONwiththepersonkey.Then,whenyouneedtoretrieveandusethatinformation,youdeserializetheJSONusingJSON.parse()andassigntheresultingobjecttothesavedPersonvariable.Nowwecanstorejustaboutanythingweneedtoinlocalstorage,andwehaveatonofspacetostoreitin!
TRYITOUTWhat’sNew?NowwithLocalStorageLet’srewriteExample2usinglocalstorage.Feelfreetocopyandpastethecontentsofch13_example2a.htmlandch13_example2b.htmlasthebasisforthenewfiles.
Let’screatethefirstpage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Example3a</title>
</head>
<body>
<h1>WelcometoExample3a</h1>
<divid="whatsNew"></div>
<script>
varlastUpdated=newDate("Tue,28Dec2020");
varlastVisit=localStorage.lastVisit;
if(lastVisit){
lastVisit=newDate(lastVisit);
if(lastVisit<lastUpdated){
document.getElementById("whatsNew").innerHTML=
"<ahref='ch13_example3b.html'>What'sNew?</a>";
}
}
localStorage.lastVisit=newDate();
</script>
</body>
</html>
Savethispageasch13_example3a.html.Next,createasimplepagetolinktofortheWhat’sNew?details:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Example3b</title>
</head>
<body>
<h1>WelcometoExample3b</h1>
<h3>Here'swhat'snew!</h3>
</body>
</html>
Savethispageasch13_example3b.html.
Loadch13_example3a.htmlintoabrowser.ThispagebehavesexactlylikeExample2a.Thefirsttimeyougotothemainpage,therewillbenothingbutaheadingsaying“WelcometoExample3a.”Refreshingthepagedisplaysthe“What’sNew?”linkinthepage.Clickingthislinktakesyoutoch13_example3b.html.
Asbefore,we’llfocusontheJavaScriptcontainedwithinch13_example3b.html.
First,youdeclarethelastUpdatedvariable:
varlastUpdated=newDate("Tue,28Dec2020");
Next,yougetthedateoftheuser’slastvisitfromlocalstoragewiththelastVisitkey:
varlastVisit=localStorage.lastVisit;
ThisassignsoneoftwovaluestothelastVisitvariable.Ifthisistheuser’sfirstvisittothepage,thelocalStorage.lastVisitkeywon’texistandreturnsnulltolastVisit.Inwhichcase,youwon’tdisplaytheWhat’sNew?linkinthedocument.
ThesecondpossiblevalueoflastVisitisastringrepresentationofthedatetheuserlastvisitedthepage.Inthissituation,youneedtocheckwhethertheuservisitedthesitebeforeitwaslastupdatedanddirecttheusertotheWhat’sNew?pageifso:
if(lastVisit){
lastVisit=newDate(lastVisit);
if(lastVisit<lastUpdated){
document.getElementById("whatsNew").innerHTML=
"<ahref='ch13_example3b.html'>What'sNew?</a>";
}
}
Rememberthatthedatastoredinlocalstorageisstrings;so,youcreateanewDateobjectbasedonthevalueoflastVisitandstoreitinthelastVisitvariable.Then,iflastVisitislessthanlastUpdated,youdisplaytheWhat’sNew?linkinthedocument.
Inthefinallineofcode,youresetthevalueofthelocalState.lastVisitkey:
localStorage.lastVisit=newDate();
ViewingWebStorageContentLikecookies,youcanalsoviewthedatastoredinwebstorage,butdoingsorequiresyoutousethefeaturesfoundineachbrowser’sdevelopmenttools.YoulearnaboutthedevelopmenttoolsfoundinInternetExplorer,Chrome,andFirefoxinChapter18,butviewingthewebstoragecontentinChromeisstraightforward.SimplypressF12tobringupthedevelopmenttoolsandclicktheResourcestab.Figure13.20showsyouthelocalstorageforthebeginningjs.comdomain.
Figure13.20
Youcanonlyviewthewebstorageofthedomainofthepagecurrentlyloadedinagiventab;youcannotviewonedomain’swebstoragefromanotherdomain.
SUMMARYInthischapter,youlookedathowyoucanstoreinformationontheuser’scomputerandusethisinformationtopersonalizethewebsite.Inparticular,youfoundthefollowing:
Thekeytocookiesisthedocumentobject’scookieproperty.
Creatingacookiesimplyinvolvessettingthedocument.cookieproperty.Cookieshavesixdifferentpartsyoucanset.Thesearethename,thevalue,whenitexpires,thepathitisavailableon,thedomainit’savailableon,andfinallywhetheritshouldbesentonlyoversecureconnections.
Althoughsettinganewcookieisfairlyeasy,youfoundthatretrievingitsvalueactuallygetsallthecookiesforthatdomainandpath,andthatyouneedtosplitupthecookiename/valuepairstogetaspecificcookieusingStringobjectmethods.
Cookieshaveanumberoflimitations.First,theusercansetthebrowsertodisablecookies;andsecond,youarelimitedto50cookiesperdomaininIE7+andFirefoxandamaximumof4,096characterspercookiename/valuepair.
Webstorageisanewkey/valuepairdatastorethatreplacestheneedforcookiesforJavaScriptdevelopers.ThoughitwasoriginallyintroducedwithHTML5,itisnowitsownspecification.
Setting,getting,andremovingdatafromwebstorageissimple.YoucaneitheruselocalStorage’sgetItem(),setItem(),andremoveItem()methods,oryoucanassignandusepropertiesonlocalStorageitself.
Thedatastoredinwebstorageisconvertedtostrings.So,youhavetoconvertthedatabackintoitsappropriatedatatypeinordertoeffectivelyuseit.ThisiseasilydonethankstovariousfunctionslikeparseInt(),Date’sconstructor,andJSON.parse().
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. Usinglocalstorage,createapagethatkeepstrackofhowmanytimesthepagehasbeenvisitedbytheuserinthelastmonth.
2. Uselocalstoragetoloadadifferentadvertisementeverytimeauservisitsawebpage.
14AjaxWHATYOUWILLLEARNINTHISCHAPTER:
MakingHTTPrequestswiththeXMLHttpRequestobject
WritingacustomAjaxmodule
WorkingwitholderAjaxtechniquestopreserveusability
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Sinceitsinception,theInternethasusedatransaction-likecommunicationmodel;abrowsersendsarequesttoaserver,whichsendsaresponsebacktothebrowser,which(re)loadsthepage.ThisistypicalHTTPcommunication,anditwasdesignedtobethisway.Butthismodelisrathercumbersomefordevelopers,becauseitrequireswebapplicationstoconsistofseveralpages.Theresultinguserexperiencebecomesdisjointedandinterruptedduetotheseseparatepageloads.
Intheearly2000s,amovementbegantolookforanddevelopnewtechniquestoenhancetheuser’sexperience;tomakewebapplicationsbehavemorelikeconventionalapplications.Thesenewtechniquesofferedtheperformanceandusabilityusuallyassociatedwithconventionaldesktopapplications.Itwasn’tlongbeforedevelopersbegantorefinetheseprocessestoofferricherfunctionalitytotheuser.
Attheheartofthismovementwasonelanguage:JavaScript,anditsabilitytomakeHTTPrequeststransparenttotheuser.
WHATISAJAX?Essentially,Ajaxallowsclient-sideJavaScripttorequestandreceivedatafromaserverwithoutrefreshingthewebpage.Thistechniqueenablesthedevelopertocreateanapplicationthatisuninterrupted,makingonlyportionsofthepagereloadwithnewdata.
ThetermAjaxwasoriginallycoinedbyJesseJamesGarrettin2005.Hewroteanarticleentitled“Ajax:ANewApproachtoWebApplications”(www.adaptivepath.com/publications/essays/archives/000385.php).Init,Garrettstatesthattheinteractivitygapbetweenwebanddesktopapplicationsisbecomingsmaller,andhecitesapplicationssuchasGoogleMapsandGoogleSuggestasproofofthis.ThetermoriginallystoodforAsynchronousJavaScript+XML(XMLwastheformatinwhichthebrowserandservercommunicatedwitheachother).Today,AjaxsimplyreferstothepatternofusingJavaScripttosendandreceivedatafromthewebserverwithoutreloadingtheentirepage.
AlthoughthetermAjaxwasderivedin2005,theunderlyingmethodologywasusedyearsbefore.EarlyAjaxtechniquesconsistedofusinghiddenframes/iframes,dynamicallyadding<script/>elementstothedocument,and/orusingJavaScripttosendHTTPrequeststotheserver;thelatterhasbecomequitepopularinthepastfewyears.Thesenewtechniquesrefreshonlyportionsofapage,bothcuttingthesizeofdatasenttothebrowserandmakingthewebpagefeelmorelikeaconventionalapplication.
WhatCanItDo?Ajaxopenedthedoorsforadvancedwebapplications—onesthatmimicdesktopapplicationsinformandinfunction.AvarietyofcommercialwebsitesemploytheuseofAjax.Thesesiteslookandbehavemorelikedesktopapplicationsthanwebsites.ThemostnotableAjax-enabledwebapplicationscomefromthesearchgiantGoogle:GoogleMapsandGoogleSuggest.
GoogleMapsDesignedtocompetewithexistingcommercialmappingsites(andusingimagesfromitsGoogleEarth),GoogleMaps(http://maps.google.com)usesAjaxtodynamicallyaddmapimagestothewebpage.Whenyouenteralocation,themainpagedoesnotreloadatall;theimagesaredynamicallyloadedinthemaparea.GoogleMapsalsoenablesyoutodragthemaptoanewlocation,andonceagain,themapimagesaredynamicallyaddedtothemaparea(seeFigure14.1).
Figure14.1
GoogleSuggestThenowcommonplaceGoogleSuggestisanotherGoogleinnovationthatemploystheuseofAjax.Uponfirstglance,itappearstobeanormalGooglesearchpage.Whenyoustarttyping,however,adrop-downboxdisplayssuggestionsforsearchtermsthatmightinterestyou.Underthesuggestedwordorphraseisthenumberofresultsthesearchtermreturns(seeFigure14.2).
Figure14.2
BrowserSupportIntheearlyyearsofAjax,browsersupportwasmixed.Everybrowsersupportedthebasicsinsomeway,butsupportdifferedfrombrowsertobrowser.Today,AjaxisajustanothernormalpartofJavaScriptdevelopment,andtoday’smodernbrowsersunquestionablysupportAjax.
USINGTHEXMLHTTPREQUESTOBJECTAsstatedbefore,youcancreateAjax-enabledapplicationsinavarietyofways.However,probablythemostpopularAjaxtechniqueincorporatestheJavaScriptXMLHttpRequestobject,whichispresentinallmajorbrowsers.
NOTEDespiteitsname,youcanretrieveothertypesofdata,likeplaintext,withXMLHttpRequest.
TheXMLHttpRequestobjectoriginatedasaMicrosoftcomponent,calledXmlHttp,intheMSXMLlibraryfirstreleasedwithIE5.ItoffereddevelopersaneasywaytoopenHTTPconnectionsandretrieveXMLdata.MicrosoftimprovedthecomponentwitheachnewversionofMSXML,makingitfasterandmoreefficient.
AsthepopularityoftheMicrosoftXMLHttpRequestobjectgrew,MozilladecidedtoincludeitsownversionoftheobjectwithFirefox.TheMozillaversionmaintainedthesamepropertiesandmethodsusedinMicrosoft’sActiveXcomponent,makingcross-browserusagepossible.Soonafter,OperaSoftwareandApplecopiedtheMozillaimplementation,andGooglenaturallyimplementeditwithChrome’sinitialrelease.AsforInternetExplorer,XMLHttpRequestisnolongeranActiveXcomponentbutanativeobjectinthebrowser.
CreatinganXMLHttpRequestObjectTheXMLHttpRequestobjectislocatedinthewindowobject.CreatinganXMLHttpRequestobjectisassimpleascallingitsconstructor:
varrequest=newXMLHttpRequest();
ThislinecreatesanXMLHttpRequestobject,whichyoucanusetoconnectto,andrequestandreceivedatafrom,aserver.
UsingtheXMLHttpRequestObjectOnceyoucreatetheXMLHttpRequestobject,youarereadytostartrequestingdatawithit.Thefirststepinthisprocessistocalltheopen()methodtoinitializetheobject:
request.open(requestType,url,async);
Thismethodacceptsthreearguments.Thefirst,requestType,isastringvalueconsistingofthetypeofrequesttomake.ThevaluecanbeeitherGETorPOST.ThesecondargumentistheURLtosendtherequestto,andthethirdisanoptionaltrueorfalsevalueindicatingwhethertherequestshouldbemadeinasynchronousorsynchronousmode.
RequestsmadeinsynchronousmodehaltallJavaScriptcodefromexecutinguntilaresponseisreceivedfromtheserver.Thiscanslowdownyourapplication’sexecutiontime.Inmostcases,youwanttouseasynchronousmode,whichletsthebrowsercontinue
toexecuteyourapplication’scodewhiletheXMLHttpRequestobjectawaitsaresponsefromtheserver.AsynchronousmodeisthedefaultbehaviorofXMLHttpRequest,soyoucanusuallyomitthethirdargumenttoopen().
NOTEInthepast,itwasconsideredbestpracticetopasstrueasthethirdargument.
Thenextstepistosendtherequest;dothiswiththesend()method.Thismethodacceptsoneargument,whichisastringthatcontainstherequestbodytosendalongwiththerequest.GETrequestsdonotcontainanyinformation,sopassnullastheargument:
varrequest=newXMLHttpRequest();
request.open("GET","http://localhost/myTextFile.txt",false);
request.send(null);
ThiscodemakesaGETrequesttoretrieveafilecalledmyTextFile.txtinsynchronousmode.Callingthesend()methodsendstherequesttotheserver.
WARNINGThesend()methodrequiresanargumenttobepassed,evenifitisnull.
EachXMLHttpRequestobjecthasastatusproperty.ThispropertycontainstheHTTPstatuscodesentwiththeserver’sresponse.Theserverreturnsastatusof200forasuccessfulrequest,andoneof404ifitcannotfindtherequestedfile.Withthisinmind,considerthefollowingexample:
varrequest=newXMLHttpRequest();
request.open("GET","http://localhost/myTextFile.txt",false);
request.send(null);
varstatus=request.status;
if(status==200){
alert("Thetextfilewasfound!");
}elseif(status==404){
alert("Thetextfilecouldnotbefound!");
}else{
alert("Theserverreturnedastatuscodeof"+status);
}
Thiscodechecksthestatuspropertytodeterminewhatmessagetodisplaytotheuser.Ifsuccessful(astatusof200),analertboxtellstheusertherequestfileexists.Ifthefiledoesn’texist(status404),theuserseesamessagestatingthattheservercannotfindthefile.Finally,analertboxtellstheuserthestatuscodeifitequalssomethingotherthan200or404.
ManydifferentHTTPstatuscodesexist,andcheckingforeverycodeisnotfeasible.Mostofthetime,youshouldonlybeconcernedwithwhetheryourrequestissuccessful.Therefore,youcancutthepreviouscodedowntothis:
varrequest=newXMLHttpRequest();
request.open("GET","http://localhost/myTextFile.txt",false);
request.send(null);
varstatus=request.status;
if(status==200){
alert("Thetextfilewasfound!");
}else{
alert("Theserverreturnedastatuscodeof"+status);
}
Thiscodeperformsthesamebasicfunction,butitonlychecksforastatuscodeof200andsendsagenericmessagetoalerttheuserforotherstatuscodes.
AsynchronousRequestsThepreviouscodesamplesdemonstratethesimplicityofsynchronousrequests.Asynchronousrequests,ontheotherhand,addsomecomplexitytoyourcodebecauseyouhavetohandlethereadystatechangeevent.Inasynchronousrequests,theXMLHttpRequestobjectexposesareadyStateproperty,whichholdsanumericvalue;eachvaluereferstoaspecificstateinarequest’slifespan,asfollows:
0:Theobjecthasbeencreated,buttheopen()methodhasn’tbeencalled.
1:Theopen()methodhasbeencalled,buttherequesthasn’tbeensent.
2:Therequesthasbeensent;headersandstatusarereceivedandavailable.
3:Aresponsehasbeenreceivedfromtheserver.
4:Therequesteddatahasbeenfullyreceived.
ThereadystatechangeeventfireseverytimethereadyStatepropertychanges,callingtheonreadystatechangeeventhandler.Thefourthandfinalstateisthemostimportant;itletsyouknowthattherequestcompleted.
NOTEItisimportanttonotethateveniftherequestwassuccessful,youmaynothavetheinformationyouwanted.Anerrormayhaveoccurredontheserver’sendoftherequest(a404,500,orsomeothererror).Therefore,youstillneedtocheckthestatuscodeoftherequest.
Codetohandlethereadystatechangeeventcouldlooklikethis:
varrequest=newXMLHttpRequest();
functionreqReadyStateChange(){
if(request.readyState==4){
varstatus=request.status;
if(status==200){
alert(request.responseText);
}else{
alert("Theserverreturnedastatuscodeof"+status);
}
}
}
request.open("GET","http://localhost/myTextFile.txt");
request.onreadystatechange=reqReadyStateChange;
request.send(null);
ThiscodefirstdefinesthereqReadyStateChange()function,whichhandlesthereadystatechangeevent.ItfirstchecksiftherequestcompletedbycomparingreadyStateto4.Thefunctionthencheckstherequest’sstatustoensuretheserverreturnedtherequesteddata.Oncethesetwocriteriaaremet,thecodealertsthevalueoftheresponseTextproperty(theactualrequesteddatainplaintextformat).Notetheopen()method’scall;thethirdargumentisomitted.ThismakestheXMLHttpRequestobjectrequestdataasynchronously.
Thebenefitsofusingasynchronouscommunicationarewellworththeaddedcomplexityofthereadystatechangeevent,becausethebrowsercancontinuetoloadthepageandexecuteyourotherJavaScriptcodewhiletherequestobjectsendsandreceivesdata.Perhapsauser-definedmodulethatwrapsanXMLHttpRequestobjectcouldmakeasynchronousrequestseasiertouseandmanage.
NOTEAnXMLHttpRequestobjectalsohasapropertycalledresponseXML,whichattemptstoloadthereceiveddataintoanHTMLDOM(whereasresponseTextreturnsplaintext).
CREATINGASIMPLEAJAXMODULETheconceptofcodereuseisimportantinprogramming;itisthereasonwhyfunctionsaredefinedtoperformspecific,common,andrepetitivetasks.Chapter5introducedyoutotheobject-orientedconstructofcodereuse:referencetypes.Theseconstructscontainpropertiesthatcontaindataand/ormethodsthatperformactionswiththatdata.
Inthissection,youwriteyourownAjaxmodulecalledHttpRequest,therebymakingasynchronousrequestseasiertomakeandmanage.Beforegettingintowritingthismodule,let’sgooverthepropertiesandmethodstheHttpRequestreferencetypeexposes.
PlanningtheHttpRequestModuleThere’sonlyonepieceofinformationthatyouneedtokeeptrackof:theunderlyingXMLHttpRequestobject.Therefore,thismodulewillhaveonlyoneproperty,request,whichcontainstheunderlyingXMLHttpRequestobject.
TheHttpRequestexposesasinglemethodcalledsend().Itspurposeistosendtherequesttotheserver.
Nowlet’sbegintowritethemodule.
TheHttpRequestConstructorAreferencetype’sconstructordefinesitspropertiesandperformsanylogicneededtofunctionproperly:
functionHttpRequest(url,callback){
this.request=newXMLHttpRequest();
//morecodehere
}
Theconstructoracceptstwoarguments.Thefirst,url,istheURLtheXMLHttpRequestobjectwillrequest.Thesecond,callback,isacallbackfunction;itwillbecalledwhentheserver’sresponseisreceived(whentherequest’sreadyStateis4anditsstatusis200).Thefirstlineoftheconstructorinitializestherequestproperty,assigninganXMLHttpRequestobjecttoit.
Withtherequestpropertycreatedandreadytouse,youpreparetosendtherequest:
functionHttpRequest(url,callback){
this.request=newXMLHttpRequest();
this.request.open("GET",url);
functionreqReadyStateChange(){
//morecodehere
}
this.request.onreadystatechange=reqReadyStateChange;
}
ThefirstlineofthenewcodeusestheXMLHttpRequestobject’sopen()methodtoinitializetherequestobject.SettherequesttypetoGET,andusetheurlparametertospecifytheURLyouwanttorequest.Becauseyouomitopen()’sthirdargument,yousettherequestobjecttouseasynchronousmode.
ThenextfewlinesdefinethereqReadyStateChange()function.Definingafunctionwithinafunctionmayseemweird,butitisperfectlylegaltodoso.Thisinnerfunctioncannotbeaccessedoutsidethecontainingfunction(theconstructorinthiscase),butithasaccesstothevariablesandparametersofthecontainingconstructorfunction.Asitsnameimplies,thereqReadyStateChange()functionhandlestherequestobject’sreadystatechangeevent,andyoubindittodosobyassigningittotheonreadystatechangeeventhandler:
functionHttpRequest(url,callback){
this.request=newXMLHttpRequest();
this.request.open("GET",url);
vartempRequest=this.request;
functionreqReadyStateChange(){
if(tempRequest.readyState==4){
if(tempRequest.status==200){
callback(tempRequest.responseText);
}else{
alert("Anerroroccurredtryingtocontacttheserver.");
}
}
}
this.request.onreadystatechange=reqReadyStateChange;
}
Thenewlinesofcodemayonceagainlookalittlestrange,butit’sactuallyapatternyou’lloftenseewhenlookingatotherpeople’scode.ThefirstnewlinecreatesthetempRequestvariable.Thisvariableisapointertothecurrentobject’srequestproperty,andit’susedwithinthereqReadyStateChange()function.Thisisatechniquetogetaroundscopingissues.Ideally,youwouldusethis.requestinsidethereqReadyStateChange()function.However,thethiskeywordpointstothereqReadyStateChange()functioninsteadoftotheXMLHttpRequestobject,whichwouldcausethecodetonotfunctionproperly.SowhenyouseetempRequest,thinkthis.request.
InsidethereqReadyStateChange()function,youseethefollowingline:
callback(tempRequest.responseText);
Thislinecallsthecallbackfunctionspecifiedbytheconstructor’scallbackparameter,andyoupasstheresponseTextpropertytothisfunction.Thisallowsthecallbackfunctiontousetheinformationreceivedfromtheserver.
Creatingthesend()MethodThereisonemethodinthisreferencetype,anditenablesyoutosendtherequesttotheserver.SendingarequesttotheserverinvolvestheXMLHttpRequestobject’ssend()
method.Thissend()issimilar,withthedifferencebeingthatitdoesn’tacceptarguments:
HttpRequest.prototype.send=function(){
this.request.send(null);
};
Thisversionofsend()issimpleinthatallyoudoiscalltheXMLHttpRequestobject’ssend()methodandpassitnull.
TheFullCodeNowthatthecode’sbeencovered,openyourtexteditorandtypethefollowing:
functionHttpRequest(url,callback){
this.request=newXMLHttpRequest();
this.request.open("GET",url);
vartempRequest=this.request;
functionreqReadyStateChange(){
if(tempRequest.readyState==4){
if(tempRequest.status==200){
callback(tempRequest.responseText);
}else{
alert("Anerroroccurredtryingtocontacttheserver.");
}
}
}
this.request.onreadystatechange=reqReadyStateChange;
}
HttpRequest.prototype.send=function(){
this.request.send(null);
};
Savethisfileashttprequest.js.You’lluseitlaterinthechapter.
Thegoalofthismodulewastomakeasynchronousrequestseasiertouse,solet’slookatabriefcode-onlyexampleandseeifthatgoalwasaccomplished.
Thefirstthingyouneedisafunctiontohandlethedatareceivedfromtherequest;thisfunctiongetspassedtotheHttpRequestconstructor:
functionhandleData(text){
alert(text);
}
ThiscodedefinesafunctioncalledhandleData()thatacceptsoneargumentcalledtext.Whenexecuted,thefunctionmerelyalertsthedatapassedtoit.NowcreateanHttpRequestobjectandsendtherequest:
varrequest=newHttpRequest(
"http://localhost/myTextFile.txt",handleData);
request.send();
Passthetextfile’slocationandapointerofthehandleData()functiontotheconstructor,andsendtherequestwiththesend()method.ThehandleData()functioniscalledintheeventofasuccessfulrequest.
ThismoduleencapsulatesthecoderelatedtoasynchronousXMLHttpRequestrequestsnicely.Youdon’thavetoworryaboutcreatingtherequestobject,handlingthereadystatechangeevent,orcheckingtherequest’sstatus;theHttpRequestmoduledoesitallforyou.
VALIDATINGFORMFIELDSWITHAJAXYou’veprobablyseenitmanytimes:registeringasanewuseronawebsite’sforumorsigningupforweb-basede-mail,onlytofindthatyourdesiredusernameistaken.Ofcourse,youdon’tfindthisoutuntilafteryou’vefilledouttheentireform,submittedit,andwatchedthepagereloadwithnewdata(nottomentionthatyou’velostsomeofthedatayouentered).Asyoucanattest,formvalidationcanbeafrustratingexperience.Thankfully,Ajaxcansoftenthisexperiencebysendingdatatotheserverbeforesubmittingtheform—allowingtheservertovalidatethedata,andlettingtheuserknowtheoutcomeofthevalidationwithoutreloadingthepage!
Inthissection,youcreateaformthatusesAjaxtechniquestovalidateformfields.It’spossibletoapproachbuildingsuchaforminavarietyofways;theeasiestofwhichtoimplementprovidesalinkthatinitiatesanHTTPrequesttotheserverapplicationtocheckwhethertheuser’sdesiredinformationisavailabletouse.
Theformyoubuildresemblestypicalformsusedtoday;itwillcontainthefollowingfields:
Username(validated):Thefieldwheretheusertypeshisorherdesiredusername
Email(validated):Thefieldwheretheusertypeshisorhere-mail
Password(notvalidated):Thefieldwheretheusertypeshisorherpassword
VerifyPassword(notvalidated):Thefieldwheretheuserverifieshisorherpassword
NotethatthePasswordandVerifyPasswordfieldsarejustforshowinthisexample.Verifyingapasswordiscertainlysomethingtheserverapplicationcando;however,itisfarmoreefficienttoletJavaScriptperformthatverification.Doingsoaddsmorecomplexitytothisexample,andwewanttokeepthisassimpleaspossibletohelpyougetagraspofusingAjax.
NexttotheUsernameandEmailfieldswillbeahyperlinkthatcallsaJavaScriptfunctiontoquerytheserverwithyourHttpRequestmodulefromtheprevioussection.
Asmentionedearlier,Ajaxiscommunicationbetweenthebrowserandserver.Sothisexampleneedsasimpleserverapplicationtovalidatetheformfields.PHPprogrammingisbeyondthescopeofthisbook.However,weshoulddiscusshowtorequestdatafromthePHPapplication,aswellaslookattheresponsetheapplicationsendsbacktoJavaScript.
RequestingInformationThePHPapplicationlooksforoneoftwoargumentsinthequerystring:usernameandemail.
Tochecktheavailabilityofausername,usetheusernameargument.TheURLtodothislookslikethefollowing:
http://localhost/formvalidator.php?username=[usernameToSearchFor]
Whensearchingforausername,replace[usernameToSearchFor]withtheactualname.
Searchingforane-mailfollowsthesamepattern.Thee-mailURLlookslikethis,whereyoureplace[emailToSearchFor]withtheactualname:
http://localhost/formvalidator.php?email=[emailToSearchFor]
TheReceivedDataAsuccessfulrequestresultsinasimpleJSONstructurethatdefinestwomemberscalledsearchTermandavailable,likethis:
{
"searchTerm":"jmcpeak",
"available":true
}
Asitsnameimplies,thesearchTermitemcontainsthestringusedintheusernameore-mailsearch.Theavailableitemisabooleanvalue.Iftrue,therequestedusernameand/ore-mailisavailableforuse.Iffalse,theusernameand/ore-mailisinuseandthereforenotavailable.
BeforeYouBeginThisisalive-codeAjaxexample;therefore,yoursystemmustmeetafewrequirementsifyouwanttorunthisexamplefromyourcomputer.
AWebServerFirst,youneedawebserver.IfyouareusingWindows,youhaveMicrosoft’swebserversoftware,InternetInformationServices(IIS),freelyavailabletoyou.ToinstallitonWindows,openProgramsandFeaturesintheControlPanelandclickTurnWindowsfeaturesonoroff.Figure14.3showstheWindowsFeaturesdialogboxinWindows8.
Figure14.3
ExpandInternetInformationServicesandcheckthefeaturesyouwanttoinstall.YoumustcheckWorldWideWebServices(Figure14.4).Youmayneedyouroperatingsystem’sinstallationCDtocompletetheinstallation.
Figure14.4
Ifyouuseanotheroperatingsystem,oryouwanttouseanotherwebserverapplication,youcaninstallApacheHTTPServer(www.apache.org).Thisisanopensourcewebserverandcanrunonavarietyofoperatingsystems,suchasLinux,Unix,andWindows,tolistonlyafew.MostwebsitesrunonApache,sodon’tfeelnervousaboutinstallingitonyourcomputer.Itisextremelystable.
IfyoudochoosetouseApache,don’tdownloadandinstallitjustyet;therearedifferentversionsofApache.Instead,downloadPHPfirstbecausePHP’swebsitegivesyouaccurateinformationonwhichApacheversionyoushoulddownloadandinstall.
PHPPHPisapopularopensourceserver-sidescriptinglanguageandmustbeinstalledonyourcomputerifyouwanttorunPHPscripts.YoucandownloadPHPinavarietyofforms(binaries,Windowsinstallationwizards,andsourcecode)atwww.php.net.ThePHPcodeusedinthisexamplewaswritteninPHP5.
TRYITOUTXMLHttpRequestSmartForm
InthisTryItOut,youwilluseAjaxtovalidateformfields.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter14:Example1</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="httprequest.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=document.getElementById("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varurl="ch14_formvalidator.php?username="+userValue;
varrequest=newHttpRequest(url,handleResponse);
request.send();
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_formvalidator.php?email="+emailValue;
varrequest=newHttpRequest(url,handleResponse);
request.send();
}
functionhandleResponse(responseText){
varresponse=JSON.parse(responseText);
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
document.getElementById("usernameAvailability")
.addEventListener("click",checkUsername);
document.getElementById("emailAvailability")
.addEventListener("click",checkEmail);
</script>
</body>
</html>
Savethisfileinyourwebserver’srootdirectory.Ifyou’reusingIISforyourwebserver,saveitasc:\inetpub\wwwroot\ch14_example1.html.Ifyou’reusingApache,you’llwanttosaveitinsidethehtdocsfolder:path_to_htdocs\htdocs\ch14_example1.html.
Youalsoneedtoplacehttprequest.js(theHttpRequestmodule)andthech14_formvalidator.phpfile(fromthecodedownload)intothesamedirectoryasch14_example1.html.
Nowopenyourbrowserandnavigatetohttp://localhost/ch14_formvalidator.php.Ifeverythingisworkingproperly,youshouldseethetext“PHPisworkingcorrectly.Congratulations!”asinFigure14.5.
Figure14.5
Nowpointyourbrowsertohttp://localhost/ch14_example1.html,andyoushouldseesomethinglikeFigure14.6.
Figure14.6
TypejmcpeakintotheUsernamefieldandclicktheCheckAvailabilitylinknexttoit.You’llseeanalertboxliketheoneshowninFigure14.7.
Figure14.7
Nowtypesomeone@xyz.cominthee-mailfieldandclicktheCheckAvailabilitylinknexttoit.Again,you’llbegreetedwithanalertboxstatingthatthee-mail’salreadyinuse.Nowinputyourownusernameande-mailintothesefieldsandclicktheappropriatelinks.Chancesareanalertboxwilltellyouthatyourusernameand/ore-mailisavailable(theusernamesjmcpeakandpwiltonandthee-mailssomeone@[email protected]).
ThebodyofthisHTMLpagecontainsasimpleformwhosefieldsarecontainedwithinatable.Eachformfieldexistsinitsownrow.Thefirsttworowscontainthefieldsyou’remostinterestedin:theUsernameandEmailfields:
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<!––HTMLtobecontinuedlater––>
Thefirstcolumncontainstextidentifiersforthefields.Thesecondcolumncontainsthe<input/>elementsthemselves.Eachofthesetagshasanidattribute:usernamefortheUsernamefieldandemailfortheEmailfield.Thisenablesyoutoeasilyfindthe<input/>elementsandgetthetextenteredintothem.
Thethirdcolumncontainsan<a/>element.ThesehyperlinksexistforthesolepurposeofkickingoffAjaxrequests.Assuch,theyhaveahash(#)intheirhrefattributes,thuspreventingthebrowserfromnavigatingtoadifferentpage(tobeconsideredavalid,clickablehyperlink,an<a/>elementmusthaveanhrefvalue).Eachoftheselinkshasanidattributethatyou’lluselaterinyourJavaScriptcode.
TheremainingthreerowsinthetablecontaintwopasswordfieldsandtheSubmitbutton(thesmartformcurrentlydoesnotusethesefields):
<!––HTMLcontinuedfromearlier––>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
TheCSSinthisHTMLpageconsistsofonlyacoupleofCSSrules:
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
Theserulesalignthefieldstogivetheformacleanandunifiedlook.
Asstatedearlier,thehyperlinksarekeytotheAjaxfunctionality,becausetheycallJavaScriptfunctionswhenclicked.Thefirstfunction,checkUsername(),retrievesthetexttheuserenteredintotheUsernamefieldandissuesanHTTPrequesttotheserver.
Thisfunctionexecutesbecausetheuserclickedalink.Therefore,youwanttopreventthebrowserfromnavigatingtotheURLspecifiedinitshrefattribute.EventhoughtheURListhehash(#),youstillwanttocallpreventDefault():
functioncheckUsername(e){
e.preventDefault();
varuserValue=document.getElementById("username").value;
Usethedocument.getElementById()methodtofindthe<inputid="FileName_username"/>elementanduseitsvaluepropertytoretrievethetexttypedintothetextbox.Youthenchecktoseeiftheusertypedanytext:
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
Ifthetextboxisempty,thefunctionalertstheusertoinputausernameandstopsthefunctionfromfurtherprocessing.Theapplicationwouldmakeunnecessaryrequeststotheserverifthecodedidn’tdothis.
NextconstructtheURLtomaketherequesttothePHPapplicationandassignittotheurlvariable.ThencreateanHttpRequestobjectbypassingtheURLandthehandleResponse()callbackfunctiontotheconstructor,andsendtherequestbycallingsend():
varurl="ch14_formvalidator.php?username="+userValue;
varrequest=newHttpRequest(url,handleResponse);
request.send();
}
YoulookatthehandleResponse()functionlater.Fornow,let’sexaminethecheckEmail()function.
Checkingthee-mailaddressavailabilityisalmostidenticaltotheusernameprocess.ThecheckEmail()functionretrievesthetexttypedintheEmailfieldandsendsthatinformationtotheserverapplication:
functioncheckEmail(e){
e.preventDefault();
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_formvalidator.php?email="+emailValue;
varrequest=newHttpRequest(url,handleResponse);
request.send();
}
ThisfunctionalsouseshandleResponse()tohandletheserver’sresponse.ThehandleResponse()functionexecuteswhentheHttpRequestobjectreceivesacompleteresponsefromtheserver.Thisfunctionusestherequestedinformationtotelltheuserwhethertheusernameore-mailaddressisavailable.Remember,theresponsefromtheserverisJSON-formatteddata.So,youneedtofirstparsethedataintoaJavaScriptobject:
functionhandleResponse(responseText){
varresponse=JSON.parse(responseText);
Theserver’sresponseisparsedintoanobjectthatisstoredintheresponsevariable.Youthenusethisobject’savailablepropertytodisplaytheappropriatemessagetotheuser:
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+"isnot
available.");
}
}
Ifavailableistrue,thefunctiontellstheuserthathisdesiredusernameore-mailaddressisokaytouse.Ifnot,thealertboxsaysthattheuser’sdesiredusernameore-mailaddressistaken.
Finally,youneedtosetuptheeventlistenersforyourtwolinks:
document.getElementById("usernameAvailability")
.addEventListener("click",checkUsername);
document.getElementById("emailAvailability")
.addEventListener("click",checkEmail);
Youdothisbysimplyretrievingthe<a/>elementsbytheirrespectiveidvaluesandlisteningfortheclickevent.
THINGSTOWATCHOUTFORUsingJavaScripttocommunicatebetweenserverandclientaddstremendouspowertothelanguage’sabilities.However,thispowerdoesnotcomewithoutitsshareofcaveats.Thetwomostimportantissuesaresecurityandusability.
SecurityIssuesSecurityisahottopicintoday’sInternet,andasawebdeveloperyoumustconsiderthesecurityrestrictionsplacedonAjax.KnowingthesecurityissuessurroundingAjaxcansaveyoudevelopmentanddebuggingtime.
TheSame-OriginPolicySincetheearlydaysofNetscapeNavigator2.0,JavaScriptcannotaccessscriptsordocumentsfromadifferentorigin.Thisisasecuritymeasurethatbrowsermakersadhereto;otherwise,maliciouscoderscouldexecutecodewherevertheywanted.Thesame-originpolicydictatesthattwopagesareofthesameoriginonlyiftheprotocol(HTTP),port(thedefaultis80),andhostarethesame.
Considerthefollowingtwopages:
Page1islocatedathttp://www.site.com/folder/mypage1.htm.
Page2islocatedathttp://www.site.com/folder10/mypage2.htm.
Accordingtothesame-originpolicy,thesetwopagesareofthesameorigin.Theysharethesamehost(www.site.com),usethesameprotocol(HTTP),andareaccessedonthesameport(noneisspecified;therefore,theybothuse80).Becausetheyareofthesameorigin,JavaScriptononepagecanaccesstheotherpage.
Nowconsiderthenexttwopages:
Page1islocatedathttp://www.site.com/folder/mypage1.htm.
Page2islocatedathttps://www.site.com/folder/mypage2.htm.
Thesetwopagesarenotofthesameorigin.Thehostisthesame,buttheirprotocolsandportsaredifferent.Page1usesHTTP(port80),whereasPage2usesHTTPS(port443).Thisdifference,thoughslight,isenoughtogivethetwopagestwoseparateorigins.Therefore,JavaScriptononeofthesepagescannotaccesstheotherpage.
SowhatdoesthishavetodowithAjax?Everything,becausealargepartofAjaxisJavaScript.Forexample,becauseofthispolicy,anXMLHttpRequestobjectcannotretrieveanyfileordocumentfromadifferentoriginbydefault.Thereis,however,alegitimateneedforcross-originrequests,andtheW3CrespondedwiththeCross-OriginResourceSharing(CORS)specification.
CORSTheCORSspecificationdefineshowbrowsersandserverscommunicatewithoneanother
whensendingrequestsacrossorigins.ForCORStowork,thebrowsermustsendacustomHTTPheadercalledOriginthatcontainstheprotocol,domainname,andportofthepagemakingtherequest.Forexample,iftheJavaScriptonthepagehttp://www.abc.com/xyz.htmlusedXMLHttpRequesttoissuearequesttohttp://beginningjs.com,theOriginheaderwouldlooklikethis:
Origin:http://www.abc.com
WhentheserverrespondstoaCORSrequest,itmustalsosendacustomheadercalledAccess-Control-Allow-Origin,anditmustcontainthesameoriginspecifiedintherequest’sOriginheader.Continuingfromthepreviousexample,theserver’sresponsemustcontainthefollowingAccess-Control-Allow-OriginheaderforCORStowork:
Access-Control-Allow-Origin:http://www.abc.com
Ifthisheaderismissing,oriftheoriginsdon’tmatch,thebrowserdoesn’tprocesstherequest.
Alternatively,theservercanincludetheAccess-Control-Allow-Originheaderwithavalueof*,signifyingthatalloriginsareaccepted.Thisisprimarilyusedbypubliclyavailablewebservices.
NOTEThesecustomheadersareautomaticallyhandledbythebrowser.YoudonotneedtosetyourownOriginheader,andyoudonothavetomanuallychecktheAccess-Control-Allow-Origin.
UsabilityConcernsAjaxbreaksthemoldoftraditionalwebapplicationsandpages.Itenablesdeveloperstobuildapplicationsthatbehaveinamoreconventional,non-“webbish”way.This,however,isalsoadrawback,becausetheInternethasbeenaroundformany,manyyears,andusersareaccustomedtotraditionalwebpages.
Therefore,itisuptodeveloperstoensurethatuserscanusetheirwebpages,andusethemastheyexpectto,withoutcausingfrustration.
TheBrowser’sBackButtonOneoftheadvantagesofXMLHttpRequestisitseaseofuse.Yousimplycreatetheobject,sendtherequest,andawaittheserver’sresponse.Unfortunately,thisobjectdoeshaveadownside:Mostbrowsersdonotlogahistoryofrequestsmadewiththeobject.Therefore,XMLHttpRequestessentiallybreaksthebrowser’sBackbutton.Thismightbeadesiredside-effectforsomeAjax-enabledapplicationsorcomponents,butitcancauseserioususabilityproblemsfortheuser.
CreatingaBack/Forward-CapableFormwithanIFrameIt’spossibletoavoidbreakingthebrowser’snavigationalbuttonsbyusinganolderbutreliableAjaxtechnique:usinghiddenframes/iframestofacilitateclient-server
communication.Youmustusetwoframesforthismethodtoworkproperly.Onemustbehidden,andonemustbevisible.
NOTENotethatwhenyouareusinganiframe,thedocumentthatcontainstheiframeisthevisibleframe.
Thehidden-frametechniqueconsistsofafour-stepprocess:
1. TheuserinitiatesaJavaScriptcalltothehiddenframebyclickingalinkinthevisibleframeorperformingsomeothertypeofuserinteraction.Thiscallisusuallynothingmorecomplicatedthatredirectingthehiddenframetoadifferentwebpage.Thisredirectionautomaticallytriggersthesecondstep.
2. Therequestissenttotheserver,whichprocessesthedata.
3. Theserversendsitsresponse(awebpage)backtothehiddenframe.
4. ThebrowserloadsthewebpageinthehiddenframeandexecutesanyJavaScriptcodetocontactthevisibleframe.
Theexampleinthissectionisbasedontheformvalidatorbuiltearlierinthechapter,butyou’lluseahiddeniframetofacilitatethecommunicationbetweenthebrowserandtheserverinsteadofanXMLHttpRequestobject.Beforegettingintothecode,youshouldfirstknowaboutthedatareceivedfromtheserver.
TheServerResponseYouexpectedaJSONdatastructureastheserver’sresponsewhenusingXMLHttpRequesttogetdatafromtheserver.Theresponseinthisexampleisdifferentandmustconsistoftwothings:
Thedata,whichmustbeinHTMLformat
AmechanismtocontacttheparentdocumentwhentheiframereceivestheHTMLresponse
ThefollowingcodeisanexampleoftheresponseHTMLpage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>ReturnedData</title>
</head>
<body>
<script>
//morecodehere
</script>
</body>
</html>
ThissimpleHTMLpagecontainsasingle<script/>elementinthebodyofthedocument.TheJavaScriptcodecontainedinthisscriptblockisgeneratedbythePHP
application,callinghandleResponse()inthevisibleframeandpassingittheexpectedJSON.
TheJSONdatastructurehasanewmember:thevaluefield.Itcontainstheusernameore-mailthatwassentintherequest.Therefore,thefollowingHTMLdocumentisavalidresponsefromthePHPapplication:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>ReturnedData</title>
</head>
<body>
<script>
top.handleResponse('{"available":false,"value":"jmcpeak"}');
</script>
</body>
</html>
TheHTMLpagecallsthehandleResponse()functionintheparentwindowandpassestheJSONstructuresignifyingthattheusernameore-mailaddressisavailable.Withtheresponseinthisformat,youcankeepagoodportionoftheJavaScriptcodeidenticaltoExample1.
TRYITOUTIframeSmartFormThecodeforthisrevisedsmartformisverysimilartothecodeusedpreviouslywiththeXMLHttpRequestexample.Thereare,however,afewchanges.Openupyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter14:Example2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
#hiddenFrame{
display:none;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td></td>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td></td>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td></td>
</tr>
</table>
</form>
<iframesrc="about:blank"id="hiddenFrame"name="hiddenFrame">
</iframe>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=document.getElementById("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varurl="ch14_iframevalidator.php?username="+userValue;
frames["hiddenFrame"].location=url;
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_iframevalidator.php?email="+emailValue;
frames["hiddenFrame"].location=url;
}
functionhandleResponse(responseText){
varresponse=JSON.parse(responseText);
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
document.getElementById("usernameAvailability")
.addEventListener("click",checkUsername);
document.getElementById("emailAvailability")
.addEventListener("click",checkEmail);
</script>
</body>
</html>
Savethisfileasch14_example2.html,andsaveitinyourwebserver’srootdirectory.Alsolocatethech14_iframevalidator.phpfilefromthecodedownloadandplaceitinthesamedirectory.
Openyourwebbrowserandnavigatetohttp://localhost/ch14_example2.html.YoushouldseeapagesimilartoExample1.
Checkforthreeusernamesande-mailaddresses.Afteryouclearthefinalalertbox,clickthebrowser’sBackbuttonafewtimes.You’llnoticethatitiscyclingthrough
theinformationyoupreviouslyentered.Thetextinthetextboxwillnotchange;however,thealertboxwilldisplaythenamesande-mailsyouentered.YoucandothesamethingwiththeForwardbutton.
TheHTMLinthebodyofthepageremainsunchangedexceptfortheadditionofthe<iframe/>tagaftertheclosing<form/>tag:
<iframesrc="about:blank"id="hiddenFrame"name="hiddenFrame"/>
ThisframeisinitializedtohaveablankHTMLpageloaded.ItsnameandidattributescontainthevalueofhiddenFrame.YouusethevalueofthenameattributelatertoretrievethisframefromtheframescollectionintheBOM.Next,yousettheCSSfortheframe:
#hiddenFrame{
display:none;
}
Thisrulecontainsonestyledeclarationtohidetheiframefromview.
NOTEHidinganiframethroughCSSenablesyoutoeasilyshowitifyouneedtodebugtheserver-sideapplication.
Nextup,theJavaScript:
functioncheckUsername(e){
e.preventDefault();
varuserValue=document.getElementById("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varurl="ch14_iframevalidator.php?username="+userValue;
frames["hiddenFrame"].location=url;
}
ThischeckUsername()functionisalmostidenticaltoExample1.Thevalueoftheurlvariableischangedtothenewch14_iframvalidator.phpfile.Theactualrequestismadebyaccessingthe<iframe/>elementusingtheframescollectionandsettingitslocationpropertytothenewURL.
ThecheckEmail()functionhasthesamemodifications:
functioncheckEmail(e){
e.preventDefault();
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_iframevalidator.php?email="+emailValue;
frames["hiddenFrame"].location=url;
}
Asbefore,thecheckEmail()functionretrievesthetextbox’svalueandcheckstoseeiftheuserentereddata.ItthenconstructstheURLusingch14_iframevalidator.phpandloadstheURLintothe<iframe/>.
DealingwithDelaysThewebbrowserisjustlikeanyotherconventionalapplicationinthatuserinterface(UI)cuestelltheuserthatsomethingisgoingon.Forexample,whenauserclicksalink,thethrobberanimationmayrunorthecursormightchangetodisplaya“busy”animation.
ThisisanotherareainwhichAjaxsolutions,andXMLHttpRequestspecifically,missthemark.However,thisproblemissimpletoovercome:SimplyaddUIelementstotelltheusersomethingisgoingonandremovethemwhentheactioniscompleted.Considerthefollowingcode:
functionrequestComplete(responseText){
//dosomethingwiththedatahere
document.getElementById("divLoading").style.display="none";
}
varmyRequest=newHttpRequest("http://localhost/myfile.txt",
requestComplete);
//showthatwe'reloading
document.getElementById("divLoading").style.display="block";
myRequest.send();
ThiscodeusestheHttpRequestmoduletorequestatextfile.Beforesendingtherequest,itretrievesanHTMLelementinthedocumentwithanidofdivLoading.This<div/>elementtellstheuserthatdataisloading.Thecodethenhidestheelementwhentherequestcompletes,thuslettingtheuserknowthattheprocesscompleted.
Offeringthisinformationtoyourusersletsthemknowtheapplicationisdoingsomething.Withoutsuchvisualcues,usersarelefttowonderiftheapplicationisworkingonwhatevertheyrequested.
DegradeGracefullyWhenAjaxFailsInaperfectworld,thecodeyouwritewouldworkeverytimeitruns.Unfortunately,youhavetofacethefactthatmanytimesAjax-enabledwebpageswillnotusetheAjax-
enabledgoodnessbecauseauserturnedoffJavaScriptinhisbrowser.
Theonlyrealanswertothisproblemistobuildanold-fashionedwebpagewithold-fashionedforms,links,andotherHTMLelements.Then,usingJavaScript,youcandisablethedefaultbehaviorofthoseHTMLelementsandaddAjaxfunctionality.Considerthishyperlinkasanexample:
<ahref="http://www.wrox.com"title="WroxPublishing">WroxPublishing</a>
Thisisanormal,run-of-the-millhyperlink.Whentheuserclicksit,thebrowserwilltakehimtohttp://www.wrox.com.ByusingJavaScript,youofcoursecanpreventthisbehaviorbyusingtheEventobject’spreventDefault()method.Simplyregisteraclickeventhandlerforthe<a/>elementandcallpreventDefault().BothExamples1and2demonstratedthistechnique.
Asaruleofthumb,buildyourwebpagefirstandaddAjaxlater.
SUMMARYThischapterintroducedyoutoAjax,anditbarelyscratchedthesurfaceofAjaxanditsmanyuses:
YoulookedattheXMLHttpRequestobject,andlearnedhowtomakebothsynchronousandasynchronousrequeststotheserverandhowtousetheonreadystatechangeeventhandler.
YoubuiltyourownAjaxmoduletomakeasynchronousHTTPrequestseasierforyoutocode.
YouusedyournewAjaxmoduleinasmarterform,onethatchecksusernamesande-mailstoseeiftheyarealreadyinuse.
YousawhowXMLHttpRequestbreaksthebrowser’sBackandForwardbuttons,andaddressedthisproblembyrebuildingthesameformusingahiddeniframetomakerequests.
YoulookedatsomeofthedownsidestoAjax,includingthesecurityissuesandthegotchas.
EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.
1. ExtendtheHttpRequestmoduletoincludesynchronousrequestsinadditiontotheasynchronousrequeststhemodulealreadymakes.You’llhavetomakesomeadjustmentstoyourcodetoincorporatethisfunctionality.(Hint:Createanasyncpropertyforthemodule.)
2. Itwasmentionedearlierinthechapterthatyoucouldmodifythesmartformtonotusehyperlinks.ChangetheformthatusestheHttpRequestmodulesothattheUsernameandEmailfieldsarecheckedwhentheusersubmitstheform.Listenfortheform’ssubmiteventandcancelthesubmissionifausernameore-mailistaken.
15HTML5MediaWHATYOUWILLLEARNINTHISCHAPTER:
Playingaudioandvideonativelyinmodernwebbrowsers
WritingacustomcontrolUIformediaplayback
SynchronizingyourUIwiththebrowser’snativecontrols
ParsingJSONbackintoactualobjectsandvaluesyoucanuseinyourpages
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
Atitsinception,theInternetwasatextdeliverysystem.WhereasthefirstHTMLspecificationdescribedthe<img>tagforembeddingimageswithinadocument,HTTPandHTMLweredesignedprimarilyfortransmittinganddisplayingtext(hence,Hyper-Text).
Inthelate1990s,personalcomputerswerefindingtheirwayintomorehouseholds,andordinarypeoplewereabletoaccesstheweb.Naturally,peoplewantedmorefromtheweb,andbrowsermakersaccommodatedthisbydesigningtheirbrowserstouseplug-ins,third-partyapplicationsthatweredesignedtodothingsbrowsersnormallydidn’t,suchasplayingvideoandaudio.Plug-inssolvedaparticularproblem,buttheyweren’twithouttheirfaults—thelargestbeingtheneedforsomanyofthem.Awidevarietyofmusicandvideoformatswereavailable,andcertainplug-inswouldonlyplaycertainformats.Stabilitywasalsoanissuebecauseamalfunctioningplug-incouldcrashthebrowser.
Thenin2005,someenterprisingfolkscreatedYouTube,avideo-sharingwebsite.InsteadofrelyingonQuickTimeorWindowsMediaPlayer,YouTube’svideoswereservedtousersasMacromedia/AdobeFlashfiles.ThiswasadvantageousbecauseofFlash’subiquity;Macromedia/AdobehadFlashplug-insforeverymajorbrowserandoperatingsystem.Soonthereafter,websitesstartedusingFlashfordeliveringtheirvideoandaudiocontenttousers,andeverythingwasrightintheworld.Orwasit?
Manypeoplebelievethebrowsershouldhavethebuilt-incapabilityforplayingvideoandaudio.SothepeopledevelopingtheHTML5specificationincludedtwonewtags,<video>and<audio>,forthatexpresspurpose.Andalthoughit’swonderfulthat,aftersomanyyears,browsersfinallyhavethebuilt-incapabilityofplayingmedia,issuesstillexistthatwedevelopershavetodealwith.Butfirst,let’stakeabrieflookatthesenewtagsandhowtheyworkwithinthebrowser.
APRIMERBeforewebegin,thevideousedinthischapteriscalledBigBuckBunny,anditisCreativeCommons-licensedasanopenmovie.Becauseofitssize,youwillnotfindthevideointhecodedownload.Youcan,however,downloadBigBuckBunnyinavarietyofformatsathttp://www.bigbuckbunny.org.
It’salsoworthnotingthatvideoandaudioareverysimilar;infact,theprimarydifferencebetweenthetwoelementsisthat<audio/>elementshavenoplaybackareaforvisualcontent.Althoughthisdiscussionfocusesprimarilyonvideo,thesameconceptscanbeappliedtoaudio.
BeforeHTML5,embeddingvideowithinawebpagewascumbersomebecauseitrequiredyoutousenolessthanthreeelementsforthevideotoworkinallbrowsers.WithHTML5,however,allyouneedisthe<video/>element:
<videosrc="bbb.mp4"></video>
The<video/>element’ssrcattributecontainsthelocationofthevideofile.Inthiscase,thebrowserwillattempttoloadthebbb.mp4filethatisinthesamedirectoryasthepage.
Ofcourse,olderbrowsersdonotsupportthe<video/>element,andassuch,theywillsimplyignorethe<video/>element.Youcan,however,addsomecontentinsidethe<video/>elementlikethis:
<videosrc="bbb.mp4">
<ahref="bbb.mp4">Downloadthisvideo.</a>
</video>
Browsersthatsupportnativevideowillnotdisplaythelink,butbrowsersthatdonotsupportnativevideowill,asshowninFigure15.1.
Figure15.1
Inmostcases,youwon’tusethesrcattributeinyourHTML.Instead,you’lldefinea<source/>elementinside<video/>,likethis:
<video>
<sourcesrc="bbb.mp4"/>
<ahref="bbb.mp4">Downloadthisvideo.</a>
</video>
Thereasonisfairlysimple:Differentbrowserssupportdifferentformats.Thisistheprimaryissuewefacewithnativevideosupport.Forexample,Figure15.2showsIE11withapagethatcontainsthepreviouscode.
Figure15.2
ThevideoisinH.264format,whichissupportedbyIE11andChrome.Firefox,atthetimeofthiswriting,haspartialsupport,andviewingthesamepagegivesyouFigure15.3.
Figure15.3
Bupkis.Butyoucanskirtaroundthisissuebyprovidingthesamevideoindifferentformats.FirefoxhascompletesupportforWebM,andyoucanaccommodateotherWebM-supportingbrowsersbyaddinganother<source/>element,likethis:
<video>
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
<ahref="bbb.mp4">Downloadthisvideo.</a>
</video>
BrowserswillreadeachsourceintheorderinwhichitappearsintheHTML.Theydownloadthevideo’smetadatatodeterminewhichvideotoload,andtheyloadthefirstvideothatitsupports.ChromesupportsbothH.264andWebM;so,ifChromeweretoloadapagewiththiscode,itwouldloadthe.mp4file.
Youcanpreventthebrowserfromdownloadingavideo’smetadatabyprovidingtheMIMEtypeforeach<source/>element.Youdothiswiththetypeattribute,asshownhere:
<video>
<sourcesrc="bbb.mp4"type="video/mp4"/>
<sourcesrc="bbb.webm"type="video/webm"/>
<ahref="bbb.mp4">Downloadthisvideo.</a>
</video>
Youcanalsoprovidethecodecinformationinthetypeattributetoallowthebrowsertomakemoreintelligentdecisionslikethis:
<video>
<sourcesrc="bbb.mp4"
type='video/mp4;codecs="avc1.4D401E,mp4a.40.2"'/>
<sourcesrc="bbb.webm"type'video/webm;codecs="vp8.0,vorbis"'/>
<ahref="bbb.mp4">Downloadthisvideo.</a>
</video>
NOTEIt’sbeyondthescopeofthisbooktoprovideanin-depthdiscussiononthevariouscodecsusedandthebrowsersthatsupportthem.Soforthesakeofsimplicity,thischapteromitsthetypeattributealtogether—alongwiththetext-basedfallback.
Bydefault,videosdonotdisplaycontrols,butyoucaneasilyaddthedefaultcontrolsbyaddingthecontrolsattributetothe<video/>element:
<videocontrols>
Youdon’thavetosetcontrolstoanyvalue;itspresenceisenoughtoturnonthebrowser’sdefaultcontrolsforthevideo.
Youcanalsotellthebrowsertopreloadthevideowiththepreloadattribute:
<videocontrolspreload>
Thistellsthebrowsertoimmediatelystartloadingthevideo.Likethecontrolsattribute,youdon’thavetosetavalueforpreload.
Bydefault,thebrowserusesthefirstframeofthevideoastheposterofthevideo,theinitialvisualrepresentationofthevideo.Youcanusetheposterattributetodisplaya
customimageforthevideo’sposter:
<videocontrolspreloadposter="bbb.jpg">
Theposterattribute,asyoumightimagine,isspecificallyfor<video/>elements,butyoucanaddafewotherattributestothe<video/>and<audio/>elements.Probablythemostimportant,fromaJavaScriptperspective,istheidattribute.Itis,afterall,howyoufindspecificmediainthepagesothatyoucanscriptthem.
SCRIPTINGMEDIAIntheDOM,<video/>and<audio/>elementsareHTMLMediaElementobjects,andtheHTML5specificationdefinesanAPIforworkingwiththeseobjects.Butnaturally,beforeyoucanuseanyofthemethods,properties,oreventsofamediaobject,youneedtofirstobtainone.Youcanretrieveanexisting<video/>or<audio/>elementinthepageusinganyofthevariousmethodsforfindingelements.Forthesakeofsimplicity,assumethere’sa<videoid="bbbVideo">taginthepage.Youcouldgetitwiththefollowingcode:
varvideo=document.getElementById("bbbVideo");
Oryoucancreateonedynamicallyusingdocument.createElement(),likethis:
varvideo=document.createElement("video");
AndonceyouhaveanHTMLMediaElementobject,youcanbegintoprogramitwithitsrobustAPI.
MethodsMediaobjectshavejustahandfulofmethods,andthey’reprimarilyusedforcontrollingmediaplayback,asshowninthefollowingtable.
METHODNAME DESCRIPTIONcanPlayType(mimeType) Determinesthelikelihoodthatthebrowsercanplaymediaof
theprovidedMIMEtypeand/orcodecload() Beginstoloadthemediafromtheserverpause() Pausesthemediaplaybackplay() Beginsorcontinuestheplaybackofthemedia
ThesearethemethodsdefinedbytheHTML5specification,butbeawarethatthevariousbrowserscanalsoimplementtheirownmethodsinadditiontothesefour.Forexample,FirefoxaddsmanymoremethodstoHTMLMediaElementobjects.Thisbook,however,doesnotcoverthem.
Thepause()andplay()methodsarestraightforward;youusethemtopauseandplaythemedia,respectively:
video.play();
video.pause();
Theothertwomethodsareusedwhenyouwanttoloadmediadynamically.Theload()method,obviously,tellsthebrowsertoloadthespecifiedmedia.ThecanPlayType()method,however,isabitmoreinvolvedbecauseitdoesn’treturntrueorfalse.Instead,itreturnsavarietyofvaluesindicatingthelikelihoodthatthebrowsersupportsthegiventype.ThepossiblevaluesreturnedbycanPlayType()are:
"probably":Indicatesthatthetypeappearstobeplayable
"maybe":It’simpossibletotellifthetypeisplayablewithoutactuallyplayingit.
"":Themediadefinitelycannotbeplayed.
ThecanPlayType()andload()methodsareonlyneededifyouplantoloadavideodynamically.Here’sanexampleofhowthatcodecouldlook:
if(video.canPlayType("video/webm")=="probably"){
video.src="bbb.webm";
}else{
video.src="bbb.mp4";
}
video.load();
video.play();
ThiscodeusesthecanPlayType()methodtodetermineifthebrowsersupportstheWebMformat.Ifitdoes,thevideo’ssrcproperty(whichyoulearnmoreaboutinthenextsection)issettotheWebMversionofthevideo.IfWebMisn’tsupported,thebrowser’ssrcissettotheMP4version.Then,afterthevideoisloadedwiththeload()method,theplay()methodplaysthevideo.
TRYITOUTControllingMediaPlaybackLet’sapplysomeofthisnewfoundknowledgewithasimpleexample.Youwriteawebpagethatplaysandpausesavideo.Notethatthisexampleassumesyouhavetwovideos:bbb.mp4andbbb.webm.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter15:Example1</title>
</head>
<body>
<div>
<buttonid="playbackController">Play</button>
</div>
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
<script>
functionplaybackClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
if(target.innerHTML=="Play"){
video.play();
target.innerHTML="Pause";
}else{
video.pause();
target.innerHTML="Play";
}
}
document.getElementById("playbackController")
.addEventListener("click",playbackClick);
</script>
</body>
</html>
Savethisfileasch15_example1.htmlandopenitinyourbrowser.YoushouldseeabuttonwiththetextPlayandavideodirectlybeneathitasshowninFigure15.4.
Figure15.4
ClickingthebuttonchangesitstexttoPauseandstartsplayingthevideo.ClickingthebuttonagainchangesthetextbacktoPlayandpausesthevideo.
Inthebodyofthepage,youhavea<button/>elementwiththeidofplaybackController.AsitsIDimplies,itisusedforcontrollingtheplaybackofthemedia,avideoembeddedwiththe<video/>element:
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
ThemainportionoftheJavaScriptcodeisafunctioncalledplaybackClick(),aneventhandlerforthe<button/>’sclickevent.Thefirsttwostatementsofthisfunctioncreatetwovariablescalledtargetandvideo:
functionplaybackClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
Thetargetvariableistheeventtarget(thebutton),andvideocontainsareferencetothe<video/>elementobject.
Nextyoudeterminewhetheryouneedtoplayorpausethevideo,andyoudothatbycheckingthetextofthe<button/>element:
if(target.innerHTML=="Play"){
video.play();
target.innerHTML="Pause";
}
Ifit’sPlay,youwanttoplaythevideo.YoudosobyusingtheHTMLMediaElementobject’splay()method,andyouchangethebutton’stexttoreadPause.
Iftheresultofthisifstatementisfalse,youcanassumethatyouwanttopausethevideo:
else{
video.pause();
target.innerHTML="Play";
}
}
So,intheelsestatement,youusethemediaobject’spause()methodandchangethebutton’stextbacktoPlay.
Ofcourse,thisfunctionwon’texecuteitself,soyouregisteraclickeventlisteneronthe<button/>object:
document.getElementById("playbackController")
.addEventListener("click",playbackClick);
Thisexampleworks,butit’snotanidealsolutionforcontrollingmedia.Specifically,youshouldn’trelyuponthetextofanelementtodetermineifyoushouldplayorpause.YoucanbettercontrolmediabyincorporatingsomeofthemanypropertiesdefinedbytheHTML5specification.
PropertiesAlthoughtheHTML5specificationdefinesjustafewmethodsformediaobjects,itdefinesalotofproperties.Youwon’tfindacompletelistofpropertiesinthissection,butAppendixClistsallofthem.
MostoftheHTMLMediaElement’spropertiesareforqueryingand/ormodifyingthestateofthemedia;others,likecontrolsandposter(thelatterforvideo)arecosmetic.
Thefollowingtablelistsafewofthepropertiesandtheirdescriptions.
PROPERTYNAME
DESCRIPTION
autoplay GetsorsetstheautoplayHTMLattribute,indicatingwhetherplaybackshouldautomaticallybeginassoonasenoughmediaisavailable
controls ReflectsthecontrolsHTMLattributecurrentTime Getsthecurrentplaybacktime.Settingthispropertyseeksthemediato
thenewtime.duration Getsthelengthofthemediainseconds;zeroifnomediaisavailable.
ReturnsNaNifthedurationcannotbedeterminedended Indicateswhetherthemediaelementhasendedplaybackloop ReflectstheloopHTMLattribute.Indicateswhetherthemediaelement
shouldstartoverwhenplaybackreachestheendmuted Getsorsetswhethertheaudioismutedpaused IndicateswhetherthemediaispausedplaybackRate Getsorsetstheplaybackrate.1.0isnormalspeed.poster GetsorsetstheposterHTMLattributepreload ReflectsthepreloadHTMLelementattributesrc GetsorsetsthesrcHTMLattributevolume Theaudiovolume.Validvaluesrangefrom0.0(silent)to1.0(loudest).
Likethemethodsfromtheprevioussection,thesepropertiesaredefinedbytheHTML5specification,butsomebrowsermakersalsoimplementtheirownproprietaryproperties.Alsoliketheaforementionedmethods,themajorityofthesepropertiesarestraightforward;theirnamesdoaprettygoodjobofdescribingwhatthey’reusedfor.
Forexample,theaptlynamedpausedpropertycantellyouifthemediaispaused,likethis:
if(video.paused){
video.play();
}else{
video.pause();
}
It’simportanttoknowthatthedefaultstateofanymediaispaused.Thebrowseronlyplaysmediawhenit’stoldtodoso—eitherexplicitlywiththeplay()methodorviathebuilt-incontrols,orimplicitlywiththeautoplayproperty/HTMLattribute.
Youcanusethemutedpropertytonotonlytellyouiftheaudioismuted,buttoalsomutetheaudio.Forexample:
if(video.muted){
video.muted=false;
}else{
video.muted=true;
}
Ortowriteitinamoresimplifiedmanner:
video.muted=!video.muted;
Thiscodeachievesthesameresultsasthepreviousexample;itsetsvideo.mutedtotheoppositeofitscurrentvalue.
Thesrcproperty,however,isabitdifferent.It’sclearthatitsetsthemediaofa<video/>or<audio/>element,butwhenyousetthesrcofamediaobject,youhavetoloaditexplicitlywiththeload()method.Otherwise,whatevermediaiscurrentlyloadedbythebrowserwillplaywhenyoucalltheplay()method.Therefore,thefollowingcodedoesnotcorrectlychangeandplaythemediaofamediaobject:
//incorrect
video.src="new_media.mp4";
video.play();
Thiscodesetsthesrcproperty,butitdoesn’tloadthenewmediawiththeload()method.Therefore,whenthevideoplaysagain,itstillplaysthemediacurrentlyloadedbythebrowser.Tofixthis,youhavetocallload()beforeyoucallplay(),likethis:
video.src="new_media.mp4";
video.load();
video.play();
TRYITOUTControllingMediaPlaybackIILet’srevisitExample1andimproveitbytakingadvantageofsomeoftheHTMLMediaElementobject’sproperties.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter15:Example2</title>
</head>
<body>
<div>
<buttonid="playbackController">Play</button>
<buttonid="muteController">Mute</button>
</div>
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
<script>
functionplaybackClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
if(video.paused){
video.play();
target.innerHTML="Pause";
}else{
video.pause();
target.innerHTML="Resume";
}
}
functionmuteClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
if(video.muted){
video.muted=false;
target.innerHTML="Mute";
}else{
video.muted=true;
target.innerHTML="Unmute";
}
}
document.getElementById("playbackController")
.addEventListener("click",playbackClick);
document.getElementById("muteController")
.addEventListener("click",muteClick);
</script>
</body>
</html>
Savethisasch15_example2.htmlandopenitinyourbrowser.Youshouldnowseetwobuttons:PlayandMute.Directlybeneaththesebuttonsisthevideo,asshowninFigure15.5.
Figure15.5
StartplayingthevideoandclicktheMutebutton.You’llnoticethattheaudioisnowmutedandthebutton’stextreadsUnmute.Clickthebuttonagaintounmutetheaudio.
NowclickthePausebutton.You’llnoticethatthevideopausesandthebutton’stextchangestoResume.Clickingthebuttonagainresumesthevideo.
ThisexampleisquitedifferentfromExample1.StartingwiththeHTML,youaddedanew<button/>element:
<div>
<buttonid="playbackController">Play</button>
<buttonid="muteController">Mute</button>
</div>
IthasanidofmuteControllerandthetextofMute.Asyoualreadyknow,it’susedformutingandunmutingtheaudio.Youregistertheclickeventlisteneratthebottomofthecode:
document.getElementById("muteController")
.addEventListener("click",muteClick);
ThefunctionusedtohandlethiseventiscalledmuteClick().Itsfirsttwolinescreatethetargetandvideovariables—theformercontainingareferencetothe<button/>elementobject,andthelatterreferencingtheHTMLMediaElementobject:
functionmuteClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
Thisfunctiontogglesthemutedpropertyofthemediaobject,soyoufirstneedtocheckitscurrentvaluewithanifstatement:
if(video.muted){
video.muted=false;
target.innerHTML="Mute";
}
Ifit’strue,theaudioiscurrentlymuted.So,yousetvideo.mutedtofalseandchangethetextofthebuttontoMute,thusunmutingthevideo.
Butifmutedisfalse,theelsestatementexecutes,mutingthevideo:
else{
video.muted=true;
target.innerHTML="Unmute";
}
}
Yousetthevideo’smutedpropertytotruetomuteit,andthenyouchangethebutton’stexttoUnmute.
TheplaybackClick()functionislogicallyidenticaltomuteClick().Afteryousetthetargetandvideo,youthendeterminewhetheryouneedtoplayorpausethevideo.Youcanaccomplishthiseasilywiththemediaobject’spausedproperty:
functionplaybackClick(e){
vartarget=e.target;
varvideo=document.getElementById("bbbVideo");
if(video.paused){
video.play();
target.innerHTML="Pause";
}
Ifit’strue,youcalltheplay()methodtoeitherstartorresumeplayback.Ifpausedisfalse,youwanttopauseplayback:
else{
video.pause();
target.innerHTML="Resume";
}
}
Youdosowiththepause()method,andyouchangethebutton’stexttoResume.Theword“resume”waschosentoenhancetheuser’sexperience;peopleexpecttoresumefromapausedstate.YoucouldhaveimplementedsomethingsimilarinExample1,butbecausethevideo’sstatewasdeterminedbythetextofabutton,itwould’verequiredextracodetomakeitwork.
Now,thisexampleisamarkedimprovementoverExample1,butitstillhasanissue:Userscancontrolthevideothroughthecontextmenu(Figure15.6).
Figure15.6
Thisinandofitselfisn’texactlyaproblem;afterall,thebestuserinterfaceshaveredundancies.ItbecomesproblemwhenyourcustomUIdoesn’taccuratelyportraytheactualstateofthemedia.ReferbacktoFigure15.6.ThecontextmenusaysPlaywhereasthecustomPlay/PausebuttonsaysPause.Ideally,boththecontextmenuandthecustomUIshouldbeinsync,andyoucandothatbylisteningforcertainevents.
EventsEventsarethelifebloodofgraphicalapplications,andmedia-basedeventsarenoexception.ThefolksbehindtheHTML5specificationdidaverythoroughjobofdefiningtheeventswebdevelopersneedtowriterobustmedia-drivenpagesandapplications.
Asyoumightsuspect,therearealotofevents,andyoucanviewthecompletelistinAppendixC.Thefollowingtable,however,listsjustafew.
EVENTNAME DESCRIPTIONabort Fireswhenplaybackisabortedcanplay Sentwhenenoughdataisavailabletoplaythemediacanplaythrough Indicatesthattheentiremediacanbeplayedthroughwithout
interruptiondurationchange Themedia’smetadatahaschanged,indicatingachangeinthemedia’s
duration.ended Fireswhenplaybackcompleteserror Sentwhenanerroroccursloadstart Downloadinghasbegun.pause Fireswhenplaybackispausedplaying Sentwhenthemediastartsorresumesplayingprogress Downloadingisinprogress.ratechange Fireswhentheplaybackspeedchangesseeked Seekinghasended.seeking Fireswhenplaybackismovedtoanewpositiontimeupdate ThecurrentTimepropertyhaschanged.volumechange Eitherthevolumepropertyormutedpropertyhaschanged.
Youregisterlistenersfortheseeventsexactlylikeyouwouldanyotherstandardevent:withaddEventListener().Forexample,youcanexecutecodewhenthemediaispausedbylisteningforthepauseevent,likethis:
functionmediaPaused(e){
alert("Youpausedthevideo!");
}
video.addEventListener("pause",mediaPaused);
Andjustlikeanyothertypeofevent,youcanregisterdifferenteventlistenersusingthesamehandlerfunction:
functionmediaPausedPlaying(e){
if(e.type=="pause"){
alert("Youpausedthevideo!");
}else{
alert("You'replayingthevideo!");
}
}
video.addEventListener("pause",mediaPausedPlaying);
video.addEventListener("playing",mediaPausedPlaying);
Thisisadvantageousifyouneedtoexecutethesameorsimilarcodeforbothevents.Inmany(andperhapsmost)cases,however,you’llmorethanlikelywanttodefineanduse
differentfunctionsfordifferentevents.
Listeningforthese“statechange”eventsisidealwhencodingyourowncustomcontrollerUI.YouwantyourUItoaccuratelyreflectthestateofthemedia,andthe“statechange”eventsfireonlywhenthemedia’sstatechanges.This,ofcourse,makesthemidealforkeepingacustomUIinsyncwiththebuilt-inUIofthebrowser,asyouseeinthenextexample.
TRYITOUTControllingMediaPlaybackIIILet’susesomeoftheeventsintheprevioustabletorewriteExample2.Thefollowingcodecontainssubstantialchanges,soyoucanuseExample2asastartingpointortypeitallfromscratch:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter15:Example3</title>
</head>
<body>
<div>
<buttonid="playbackController">Play</button>
<buttonid="muteController">Mute</button>
</div>
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
<script>
functionpauseHandler(e){
playButton.innerHTML="Resume";
}
functionplayingHandler(e){
playButton.innerHTML="Pause";
}
functionvolumechangeHandler(e){
muteButton.innerHTML=video.muted?"Unmute":"Mute";
}
functionplaybackClick(e){
video.paused?video.play():video.pause();
}
functionmuteClick(e){
video.muted=!video.muted;
}
varvideo=document.getElementById("bbbVideo");
varplayButton=document.getElementById("playbackController");
varmuteButton=document.getElementById("muteController");
video.addEventListener("pause",pauseHandler);
video.addEventListener("playing",playingHandler);
video.addEventListener("volumechange",volumechangeHandler);
playButton.addEventListener("click",playbackClick);
muteButton.addEventListener("click",muteClick);
</script>
</body>
</html>
Savethisasch15_example3.htmlandopenitinyourbrowser.ItwilllookexactlylikeExample2.Eachtimeyouplay,pause,mute,orunmutethevideo,besuretoopenthemedia’scontextmenu.BoththecustomUIandthecontroloptionsinthecontextmenuwillbeinsync,asshowninFigure15.7.
Figure15.7
TheHTMLinthisexampleisuntouchedfromExample2,solet’sjumprighttothecode.Outsideofanyfunction,youdefinethreevariablesforreferencingthe<video/>andtwo<button/>elements:
varvideo=document.getElementById("bbbVideo");
varplayButton=document.getElementById("playbackController");
varmuteButton=document.getElementById("muteController");
You’llusethesevariablesthroughoutthevariousfunctions,butfirst,youregistertheeventlisteners.
Forthe<video/>element,youregisterpause,playing,andvolumechangeevent
listeners:
video.addEventListener("pause",pauseHandler);
video.addEventListener("playing",playingHandler);
video.addEventListener("volumechange",volumechangeHandler);
Eacheventlistenerusesauniquefunction—thepauseHandler()functionhandlesthepauseevent,playingHandler()handlestheplayingevent,andvolumechangeHandler()handlesthevolumechangeevent.Youcouldmaketheargumentthattheplayingandpauseeventcodeissimilarenoughtouseasinglefunction,butkeepitsimple!Simplefunctionsarehappyfunctions.
Andonceagain,thetwo<button/>elementsregisterclickeventsusingtheplaybackClick()andmuteClick()functions:
playButton.addEventListener("click",playbackClick);
muteButton.addEventListener("click",muteClick);
Eachofthefivefunctionsinthisexampleisreducedtoasingleresponsibility.Thisisagoodthingbecauseitmakesyourcodeeasiertomanageandmaintain(aswellasfindandfixerrorsiftheyoccur).ThefirstfunctionisthepauseHandler()function,whichasyouknow,handlesthemedia’spauseevent:
functionpauseHandler(e){
playButton.innerHTML="Resume";
}
Itsjobissimple;changethetextofthePlay/PausebuttontoResumewhenthepauseeventfires.Thisway,thebutton’stextchangesasthestateofthevideochanges.
ThenextfunctionisplayingHandler(),thecounterparttothepauseHandler()function:
functionplayingHandler(e){
playButton.innerHTML="Pause";
}
Whenthemediaplays,thisfunctionchangesthePlay/Pausebutton’stexttoPause.
ThevolumechangeHandler()functionisslightlymorecomplicatedbecauseitfiresfortwotypesofevents—whenthevolumechangesandwhenthemediaismuted:
functionvolumechangeHandler(e){
muteButton.innerHTML=video.muted?"Unmute":"Mute";
}
Liketheothermediaeventhandlers,volumechangeHandler()isresponsibleforchangingthetextofbuttonsintheUI.Buttoknowwhichtextvaluetouse,youhavetocheckthevalueofvideo.muted.Youusetheternaryoperatorheretoreducethecodetoasingleline.Youcoulduseif…elseifyouwantedto:
if(video.muted){
muteButton.innerHTML="Unmute";
}else{
muteButton.innerHTML="Mute";
}
Thisapproachwouldbeidealifyouneededtoexecutemorecodewithintheif…elsestatement,butinthiscase,theternaryapproachmightbebetter.
NextistheplaybackClick()function,andithaschangedsignificantly.BecausethepauseandplayingeventhandlersareresponsibleforupdatingtheUI,theplaybackClick()functionisonlyresponsibleforplayingandpausingthemedia:
functionplaybackClick(e){
video.paused?video.play():video.pause();
}
Onceagain,youusetheternaryoperatortodeterminewhichmethodtoexecute.Ifvideo.pausedistrue,youcalltheplay()method.Otherwise,youcallpause().
ThemuteClick()functionhasalsobeensimplifiedbecauseitisnolongerresponsibleforupdatingtheUI.Itissolelyresponsibleformutingandunmutingthemedia:
functionmuteClick(e){
video.muted=!video.muted;
}
Yousetthemutedpropertytotheoppositevalue.Therefore,ifmutedistrue,it’ssettofalse,andviceversa.
Nativemediaisafeaturethatwebdevelopershaveclamoredfor,formanyyears,andthefirstimplementation(asspecifiedbyHTML5)isveryrobustandfeature-filled.Weunfortunately,however,stillhavetobattlewiththedifferentbrowsersandthecodecstheysupport.Hopefully,thewebdevelopmentcommunitywillseeaunifiedsetofcodecsthataresupportedbyallbrowsers.
Naturally,we’veonlyscratchedthesurfaceofthenativemediaAPIandwhatyoucandowithit.Aswitheverything,experiment!Thesky’sthelimitwithsucharobustandcapableAPI.
SUMMARYThischapterintroducedyoutotheHTML5videoandaudioAPI.
YoulearnedthatHTML5bringstwonewmediaelements:<video/>and<audio/>.Italsodefinesa<source/>elementtodescribeamediasource.
Unsurprisingly,differentbrowserssupportdifferentvideoandaudioformatsandcodecs,butyoucanaddressthisissuebyprovidingmultiplesources.Thebrowserissmartenoughtoknowwhichonetoload.
Videoandaudioareprogrammaticallyidentical—exceptvideohasaposterproperty.BothtypesofmediaarerepresentedasHTMLMediaElementobjectsintheDOM.
Youlearnedhowtoplayandpausemedia.
Youlearnedhowtomutemediaandquerythestateofplaybackusingthepausedproperty.
Youlearnedhowtoregistereventlistenersforthemanymedia-basedevents,whichallowedyoutosimplifyyourcustomUI’scode.
EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.
1. Beingabletocontrolplaybackiscool,butyourcustomUIneedstoalsocontrolvolume.Addan<inputtype="range"/>elementtoExample3tocontrolthevolume.Rememberthattherangeofvolumesupportedbymediaelementsis0.0to1.0.LookbackatChapter11ifyouneedarefresheroftherangeinputtype.ThisunfortunatelywillnotworkinIE.
2. AddanotherrangeformcontroltoQuestion1’sanswer,andprogramittoseekthemedia.Itshouldalsoupdateasthemediaplays.Usethedurationchangeeventtosettheslider’smaxvalue,andthetimeupdateeventtoupdatetheslider’svalue.
16jQueryWHATYOUWILLLEARNINTHISCHAPTER:
UsingjQuerycansimplifycommontasks
Creating,modifying,andremovingelementswithjQueryiseasierthanwithtraditionalDOMmethods
jQuerymakesstylemodifications,bothwithindividualCSSpropertiesandCSSclasses,abreeze
HandlingHTTPrequestsandresponsesismucheasierthanwritingpureXMLHttpRequestcode
Deferredobjectsareuseful,especiallywhenusedwithAjaxrequests
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
JavaScriptisessentialtowebdevelopment.AndeventhoughJavaScriptdevelopmentisrelativelystraightforwardtoday,itwasextremelychallenginguntilearly2011whenMicrosoftreleasedtheninthversionofInternetExplorer.
Let’srewindtheclocktotheyear2001.Thefirstbrowserwarswerecomingtoaclose,andMicrosoftsealeditsoverwhelmingvictorywithIE6’srelease.AfewmonthslaterthesoftwaregiantreleasedWindowsXP,thelongest-supportedoperatingsysteminMicrosoft’shistory,withIE6asitsdefaultbrowser.
Atfirst,Microsoftenjoyedits85percentmarketshare,butastheyearspassed,growingpressurefromMozilla’sFirefoxspurredMicrosofttoresumedevelopmentonIE.In2006,MicrosoftreleasedIE7.Thisnewversionincludedmanybugfixes,aswellastheimplementationofnew(andoftennonstandard)features.
ThiswasthebeginningofaverychallengingtimeforJavaScriptdevelopers.Theproblemwithclient-sidedevelopmentwasthemanydifferentwebbrowsersdevelopersneededtosupport.NotonlydiddevelopershavetosupportIEandFirefox,butdevelopershadtosupportthreemajorversionsofIE(6,7,and8).Beitwritingevent-drivencodeoranAjaxapplication,somewheredownthelinedevelopersranintothemanyincompatibilitiesbetweendifferentbrowsersandversions.
Manyprofessionaldevelopersfoundcross-browserdevelopmenttobetootime-consumingandcumbersometodealwithonadailybasis,sotheysetouttodevelopframeworksorlibrariestoaidintheircross-browserdevelopment.Somedevelopersreleasedtheirframeworkstothepublic,andafewofthemgainedquiteafollowing.And
muchlikethebrowserwarsofold,eventuallyavictoremerged.FrameworkssuchasMooToolsandPrototypewerequitepopular,butjQuerybecamethedefactostandard.
jQuery,likemostotherframeworks,originatedasanAjaxlibrarytosimplifyclient/servercommunication.Today,however,jQuerysimplifiesjustabouteverycommonaspectofJavaScriptdevelopment;DOMmanipulation,Ajax,animation,andcomponentdevelopmentaremucheasierwithjQuery.Inthischapter,youlookatjQueryandlearnhowtouseittosimplifyyourJavaScriptdevelopment.
Beforebeginning,awordofnote:ThereisnodoubtthatjQueryaddsbenefittoyourdevelopmenttimeandprocess.ButitisnotasubstituteforasolidunderstandingoftheJavaScriptlanguageandtheintricaciesofthedifferentbrowsersforwhichyouhavetodevelop.Frameworksandlibrariescomeandgo,butknowledge(andpureJavaScript)isforever.
GETTINGJQUERYInstallingjQuery(oranyframeworkforthatmatter)isverydifferentfrominstallinganapplicationonyourcomputer;thereisnosetupprogram,andtheinstallationdoesn’tchangeanyportionofyoursystem.Basically,allyoudoisreferencethejQueryJavaScriptfileinyourwebpage.
Openyourbrowserandgotohttp://jquery.com/download/.Onthispage,you’llfindseverallinkstodifferentjQuery-relatedfiles.First,you’llseetwoversionsofjQuery:1.xand2.x.Thetwoversionsarealmostidenticalexceptthatv1.xsupportsIE6,7,and8andv2.xdoesnot.
Second,you’llneedtochoosethecompressedoruncompressedversion:
Compressedversion:Thisisminified(allcommentsandunnecessarywhitespaceareremovedfromthecodefiles)tomaketheirsizeassmallaspossible;doingsomakesthemfastertodownloadwhensomeonevisitsyourwebpage.Unfortunately,theminificationprocessmakestheJavaScriptcodedifficulttoreadifyouopenitinatexteditor,butthat’sareasonabletrade-offinaproductionenvironment.
Uncompressedversion:Thisisnotminified;itissimplynormalJavaScriptcodefileswiththeirwhitespaceandcommentsintact.It’sperfectlyOKtouseuncompressedJavaScriptfiles.Becausetheyareeasiertoreadthancompressedfiles,youcanlearnmuchfromtheguruswhodesignanddeveloptheseframeworks.However,ifyouplantorolloutawebpageusingaframework,besuretodownloadandusethecompressedversion,becauseitsfilesizesaresmalleranddownloadfaster.
NOTETheproductionversionofjQuery2.1.1isprovidedinthecodedownloadfromWrox.
YoucanobtainjQueryinoneoftwoways.First,simplydownloadwhicheverversionyoupreferbyright-clicking(orcontrol-clickingonaMac)thelink,andsaveitinalocationyoucaneasilygetto.
Alternatively,youcanusejQuery’sContentDeliveryNetwork(CDN)toaddjQuerytoyourwebpages.ThispreventsyoufromhavingtodownloadyourowncopyofjQuery,anditcanalsoslightlyincreasetheperformanceofyourwebpages.
RegardlessofhowyouobtainjQuery,youaddittoyourpagesjustlikeanyotherexternalJavaScriptfilewiththe<script/>element:
<scriptsrc="jquery-2.1.1.min.js"></script>
<scriptsrc="//code.jquery.com/jquery-2.1.1.min.js"></script>
Theonlydifferenceisthevalueofthesrcattribute.Thefirst<script/>elementinthisexampleusesalocalcopyofjQuery2.1.1,whereasthesecondusesjQuery’sCDN.TheexamplesinthischapterusealocalcopyofjQuery.
jQUERY’SAPIjQueryisJavaScript,butitchangesthewaythatyouinteractwiththebrowseranddocument.Whetheryou’recreatingHTMLelementsandappendingthemtothepageormakingAjaxcallstotheserver,jQueryletsyoudoitinaneasyfashion.
AttheheartofjQueryisthejQuery()function,butinmostcases,youwon’twriteyourcodewithjQuery().Instead,you’lluseanalias:thedollarfunction,$().Thiscanseemveryweirdatfirst,butitwillbecomecompletelynaturalthemoreyouuseit.
You’llusethe$()functionforjustabouteverything,including:
Findingandselectingelements
Creating,appending,andremovingelements
WrappingnormalDOMobjectswithjQueryobjects
SelectingElementsjQueryrevolutionizedthewaydevelopersfindelementsintheDOM:withCSSselectors.Infact,thequerySelector()andquerySelectorAll()methodsdiscussedinChapter9existbecauseofjQuery.ToretrieveelementswithjQuery,youuse$()andpassityourCSSselector,likethis:
varelements=$("a");
Thiscodeassignsaspecialobject,calledajQueryobject,thatrepresentsanarrayofall<a/>elementsinthepagetotheelementsvariable.
jQuerywasdesignedtomakeDOMmanipulationeasy,andbecauseofthisdesignphilosophy,youcanmakechangestoseveralelementsatthesametime.Forexample,imagineyoubuiltawebpagewithmorethan100linksinthedocument,andonedayyoudecideyouwantthemtoopeninanewwindowbysettingthetargetattributeto_blank.That’satalltasktotakeon,butitissomethingyoucaneasilyachievewithjQuery.Becauseyoucanretrieveall<a/>elementsinthedocumentbycalling$("a"),youcancalltheattr()method,whichgetsorsetsthevalueofanattribute,tosetthetargetattribute.Thefollowingcodedoesthis:
elements.attr("target","_blank");
Calling$("a")resultsinajQueryobject,butthisobjectalsodoublesasanarray.AnymethodyoucallonthisparticularjQueryobjectwillperformthesameoperationonallelementsinthearray.Byexecutingthislineofcode,yousetthetargetattributeto_blankonevery<a/>elementinthepage,andyoudidn’tevenhavetousealoop!
BecausejQueryobjectsareanarray,youcanusethelengthpropertytofindouthowmanyelementswereselectedwithaCSSquery:
varlength=elements.length;
Thisinformationcanbeuseful,butyouusuallywon’tneedtoknowthelengthofajQueryobject.Themostcommonuseofanarray’slengthpropertyisforlooping,andjQueryisdesignedtoworkwithmultipleelementsatthesametime.ThemethodsyouexecuteonajQueryobjecthavebuilt-inloops;so,thelengthpropertyisrarelyused.
jQueryhasabuilt-inCSSselectorengine,andyoucanusejustaboutanyvalidCSSselectortoretrieveyourdesiredelements—evenifthebrowserdoesn’tsupportit.Forexample,IE6doesnotsupporttheparent>childCSSselector.Ifyouhavetheunfortunateneedtosupportthatbrowser,jQuerycanstillselecttheappropriateelementswiththatselector.ConsiderthefollowingHTMLasanexample:
<p>
<div>Div1</div>
<div>Div2</div>
<span>Span1</div>
</p>
<span>Span2</span>
ThisHTMLcodedefinesa<p/>elementthatcontainstwo<div/>elementsanda<span/>element.Outsidethe<p/>elementisanother<span/>element.Let’ssaythatyouneedthe<span/>elementinsidetheparagraph.Youcaneasilyselectthatelementwiththefollowing:
varinnerSpan=$("p>span");
Thislineofcodeusestheparent>childCSSselectorsyntax,andbecausejQueryhasitsownCSSselectorengine,thiscodewillworkineverybrowser.
jQueryalsoletsyouusemultipleselectorsinonefunctioncall.Simplydelimiteachselectorwithacommaasshowninthefollowingcode:
$("a,#myDiv,.myCssClass,p>span")
Thiscoderetrievesall<a/>elements,anelementwithanidofmyDiv,elementswiththeCSSclassmyCssClass,andall<span/>childrenof<p/>elements.Ifyouwantedtochangethetext’scoloroftheseelementstored,youcouldsimplyusethefollowingcode:
$("a,#myDiv,.myCssClass,p>span").attr("style","color:red;");
Thisisn’tthebestwaytochangeanelement’sstyle.Infact,jQueryprovidesyouwithmanymethodstoalteranelement’sstyle.
NOTEForacompletelistofsupportedselectors,seehttp://docs.jquery.com/Selectors.
ChangingStyleChanginganelement’sstylerequiresyoutoeithermodifyindividualCSSpropertiesormanipulateitsCSSclasses.jQuerymakesiteasytodoboth.TochangeindividualCSS
properties,thejQueryobjecthasamethodcalledcss(),andyoucanusethismethodintwoways.
First,youcanpasstwoargumentstothecss()method:theCSSproperty’snameanditsvalue.Forexample:
$("#myDiv").css("color","red");
Thiscodesetsthecolorpropertytored,thuschangingtheelement’stextcolortored.Thepropertynamesyoupasstothecss()methodcanbeineitherstylesheetformatorinscriptformat.Thatmeansifyouwanttochangeanelement’sbackgroundcolor,youcanpassbackground-colororbackgroundColortothemethod,likethis:
varallParagraphs=$("p");
allParagraphs.css("background-color","yellow");//correct!
allParagraphs.css("backgroundColor","blue");//correct,too!
Thiscodechangesthebackgroundcolorofevery<p/>elementinthepagetoyellowandthentoblue.
NOTEIt’simportanttorememberthatjQuery’smethodsworkwithoneormultipleelements.Itdoesn’tmatterhowmanyelementsarereferencedbyajQueryobject,amethodlikecss()willchangethestyleofeveryelementintheobject.
Manytimes,however,youneedtochangemorethanoneCSSproperty.Althoughyoucaneasilyaccomplishthisbycallingcss()multipletimeslikethis:
//don'tdothis
allParagraphs.css("color","blue");
allParagraphs.css("background-color","yellow");
abettersolutionwouldbetopassanobjectthatcontainstheCSSpropertiesandtheirvaluestothecss()method.Thefollowingcodecallscss()onceandachievesthesameresults:
allParagraphs.css({
color:"blue",
backgroundColor:"yellow"
});
Here,youpassanobjectthathascolorandbackgroundColorpropertiestothecss()method,andjQuerychangestheelement’sorelements’textcolortoblueandbackgroundcolortoyellow.
Typically,though,ifyouwanttochangeanelement’sstyle,it’sbettertochangetheelement’sCSSclassinsteadofindividualstyleproperties.
AddingandRemovingCSSClassesThejQueryobjectexposesseveralmethodstomanipulateanelement’sclassNameproperty;youcanadd,remove,andeventoggletheclassesthatareappliedtoanelement.
NOTEDidyouknowyoucanassignmultipleCSSclassestoanelement?Simplyseparateeachclassnamewithaspace!
Let’sassumethatthefollowingHTMLisinoneofyourwebpages:
<divid="content"class="class-oneclass-two">
MydivwithtwoCSSclasses!
</div>
ThisHTMLdefinesa<div/>elementwithtwoCSSclasses,class-oneandclass-two.Youneedtoapplytwomoreclasses(class-threeandclass-four)tothiselement,andjQuerymakesthatveryeasytodowiththeaddClass()method.Forexample:
varcontent=$("#content");
content.addClass("class-three");
content.addClass("class-four");
Thiscodefirstretrievesthe<div/>elementandthencallstheaddClass()methodtoaddthedesiredclasses.Butyoucansimplifythiscodebyusingatechniquecalledmethodchaining.MostjQuerymethodsreturnajQueryobject,soit’spossibletocallamethodimmediatelyaftercallinganothermethod—essentiallychainingthemethodcallsasdemonstratedwiththiscode:
content.addClass("class-three").addClass("class-four");
Thiscodeachievesthesameresultsasbeforebutwithfewerkeystrokes.
NOTEMostjQuerymethodsreturnajQueryobject,allowingyoutoimmediatelycallmethodsoneafteranother.
ButyoucansimplifythiscodeevenmorebecauseyoucanpassbothCSSclassnamestoaddClass(),likethis:
content.addClass("class-threeclass-four");
Youjusthavetoseparatetheclassnameswithaspace.
TheremoveClass()methodremovesoneormultipleclasses:
content.removeClass("class-one");
ThiscodeusestheremoveClass()methodtoremovetheclass-oneclassfromtheelement.Ifyouneedtoremovemultipleclasses,simplyseparatethemwithaspace,likethis:
content.removeClass("class-twoclass-four");
Asyoucansee,thesameconceptsthatletyouaddclassestoanelementapplytoremovingclasses.Butthere’soneveryimportantdifference:Theargumentsyoupassto
removeClass()areoptional.IfyoudonotpassanyargumentstoremoveClass(),itwillremoveallclassesfromtheelement:
content.removeClass();
Thiscode,therefore,removesallCSSclassesfromtheelement(s)representedbythecontentobject.
TogglingClassesAlthoughtheaddClass()andremoveClass()methodsarecertainlyuseful,sometimesyouneedtojusttoggleaclass.Inotherwords,youremoveaclassifit’spresentoradditifit’snot.jQuerymakesthiseasywiththeaptlynamedtoggleClass()method:
content.toggleClass("class-one");
Thiscodefirsttogglestheclass-oneclass.Ifitisalreadyappliedtotheelement,jQueryremovesclass-one.Otherwise,itaddsclass-onetotheelement’sclasslist.
Thisbehaviorisusefulwhenyouneedtoaddorremoveaspecificclassfromtheelement.Forexample,thefollowingcodeisvanillaJavaScriptandDOMcodingtoaddandremoveaspecificCSSclassdependingonthetypeofevent:
vartarget=e.target;
if(e.type=="mouseover"){
target.className="class-one";
}elseif(e.type=="mouseout"){
eSrc.className="";
}
YoucangreatlysimplifythiscodebyusingthetoggleClass()method,likethis:
vartarget=$(e.target);
if(e.type=="mouseover"||e.type=="mouseout"){
target.toggleClass("class-one");
}
Noticehowthe$()functionisusedinthiscode:Itpassese.target,aDOMobject,to$().Thiscanatfirstseemlikeastrangethingtodo,butrememberwhatwesaidearlier:$()isusedformanythings.OneofthosethingsistowrapanormalDOMobjectwithajQueryobject.
Intechnicalterms,wecalltheresultingjQueryobjectawrapperobject.Wrapperobjectsaretypicallyusedtoenhancethefunctionalityofanotherobject.WithjQuery,you’rewrappingajQueryobjectaroundanelementobject,enablingyoutousejQuery’sAPItomanipulatetheelement.Inthecaseofthiscode,you’rewrappingajQueryobjectaroundanelementobjectsothatyoucanusetoggleClass()totoggletheclass-oneclass.
CheckingifaClassExistsThelastCSSclassmethodisthehasClass()method,anditreturnstrueorfalse
dependingonifanelementhasthespecifiedCSSclass.Forexample:
varhasClassOne=content.hasClass("class-one");
ThiscodeuseshasClass()todetermineiftheclass-oneisappliedtocontent.Ifitis,hasClassOneistrue.Otherwise,it’sfalse.
Creating,Appending,andRemovingElementsThinkbacktoChapter9andhowyoucreateandappendelementstothepage.Thefollowingcodewillrefreshyourmemory:
vara=document.createElement("a");
a.id="myLink";
a.setAttribute("href","http://jquery.com");
a.setAttribute("title","jQuery'sWebsite");
vartext=document.createTextNode("ClicktogotojQuery'swebsite");
a.appendChild(text);
document.body.appendChild(a);
Thiscodecreatesan<a/>element,assignsitanid,andsetsthehrefandtitleattributes.Itthencreatesatextnodeandassignstheobjecttothetextvariable.Finally,itappendsthetextnodetothe<a/>elementandappendsthe<a/>elementtothedocument’s<body/>element.ItgoeswithoutsayingthatcreatingelementswiththeDOMmethodsrequiresalotofcode.
CreatingElementsjQuerysimplifieshowyoucreateelementswithJavaScript.Thefollowingcodeshowsyouoneway:
vara=$("<a/>").attr({
id:"myLink",
href:"http://jquery.com",
title:"jQuery'sWebsite"
}).text("ClickheretogotojQuery'swebsite");
$(document.body).append(a);
Let’sbreakdownthiscodetogetabetterunderstandingofwhat’stakingplace.First,thiscodecalls$()andpassesittheHTMLtocreate.Inthiscase,it’san<a/>element:
vara=$("<a/>")
Next,itchainstheattr()methodtosetthe<a/>element’sattributes:
.attr({
id:"myLink",
href:"http://jquery.com",
title:"jQuery'sWebsite"
})
Theattr()methodisalotlikethecss()methodinthatyoucansetanindividualattributebypassingittheattribute’snameandvalue,oryoucansetmultipleattributesbypassinganobjectthatcontainstheattributesandtheirvalues.
Thecodethenchainsthetext()method,settingtheelement’stext:
.text("ClickheretogotojQuery'swebsite");
YoucanalsocreatethesameelementbypassingtheentireHTMLto$(),likethis:
vara=$('<ahref="http://jquery.com"title="jQuery\'sWebsite">'+
"ClickheretogotojQuery'swebsite</a>");
Thisapproach,however,canbecomelessofabenefitandmoreofahassle.Notonlydoyouhavetokeeptrackofwhichtypeofquoteyouusewhere,butyoumightalsohavetoescapequotes.
AppendingElementsTheappend()methodissimilartotheDOMappendChild()methodinthatitappendschildnodestotheparentobject.ThesimilaritiesendtherebecausejQuery’sappend()methodismuchmoreflexiblethanitsDOMcounterpart.Theappend()methodcanacceptaDOMobject,ajQueryobject,orastringcontainingHTMLortextcontent.Regardlessofwhatyoupassastheparametertoappend(),itwillappendthecontenttotheDOMobject.
ThepreviouscodeappendsthejQuery-created<a/>elementtothedocument’sbody,likethis:
$(document.body).append(a);
Onceagain,the$()functionwrapsajQueryobjectaroundthenativedocument.bodyobjecttotakeadvantageofjQuery’ssimpleAPI.
RemovingElementsRemovingelementsfromtheDOMisalsomucheasierwithjQuerythanwithtraditionalDOMmethods.WithDOMmethods,youneedatleasttwoelementobjects:theelementyouwanttoremoveanditsparentelement.
Aswitheverythingthusfar,jQuerysimplifiesthisprocess.Theonlythingyouneedistheelementthatyouwanttoremove.SimplycalljQuery’sremove()method,anditremovestheelement.Forexample:
$(".class-one").remove();
Thiscodefindsallelementsthathavetheclass-oneCSSclassandremovesthemfromthedocument.
Youcanalsocompletelyempty,orremoveallchildrenof,anelementwiththeaptlynamedempty()method.Ifyouwantedtoremoveeveryelementwithinthe<body/>,youcouldusethefollowingcode:
$(document.body).empty();
MostDOMchangesyou’llmakeareinresponsetosomethingtheuserdid,whethermovingthemouseoveraparticularelementorclickingsomewhereonthepage.Sonaturally,you’llhavetohandleeventsatsomepoint.
HandlingEventsWhenjQuerywascreated,JavaScriptdevelopershadtocontendwithboththeW3CstandardandlegacyIEeventmodels.Althoughmanydeveloperswroteandusedtheirowneventutilities,thevastmajoritylookedtothird-partytoolstomakecross-browsercodeeasiertowriteandmaintain.jQuerywasonesuchtool,andwhilestandardsupporthasgottensubstantiallybetterinallbrowsers,jQuery’seventAPI,specificallythemethodsusedtoregistereventlisteners,isstilleasiertouse.
AlljQueryobjectsexposeamethodcalledon()thatyouusetoregistereventlistenersforoneormoreeventsontheselectedelements.Itsmostbasicusageisverysimple,asdemonstratedhere:
functionelementClick(e){
alert("Youclickedme!");
}
$(".class-one").on("click",elementClick);
Thiscoderegistersaclickeventlisteneronallelementsthathaveaclass-oneCSSclass.Therefore,theelementClick()functionexecuteswhentheuserclicksanyoftheseelements.
Youcanalsoregistermultipleeventlistenerswiththesameeventhandlerfunctionbypassingmultipleeventnamesinthefirstargument.Simplyseparateeacheventnamewithaspace,likethis:
functioneventHandler(e){
if(e.type=="click"){
alert("Youclickedme!");
}else{
alert("Youdouble-clickedme!");
}
}
$(".class-two").on("clickdblclick",eventHandler);
Thiscoderegisterseventlistenersfortheclickanddblclickeventsonallelementswithaclass-twoCSSclass.ThecodeinsideeventHandler()determineswhateventcausedthefunctiontoexecuteandrespondsappropriately.
Althoughitcanbeusefultouseasinglefunctionforhandlingmultipleevents,jQueryalsoletsyoudefinemultipleeventlistenerswithdifferentfunctions.Insteadofpassingtwoargumentstoon()asshowninthepreviousexamples,youpassanordinaryJavaScriptobjectinwhichthepropertiesaretheeventnames,andtheirvaluesarethefunctionsthathandletheevents.Forexample:
functionclickHandler(e){
alert("Youclickedme!");
}
functiondblclickHandler(e){
alert("Youdouble-clickedme!");
}
$(".class-three").on({
click:clickHandler,
dblclick:dblclickHandler
});
Thiscoderegistersclickanddblclickeventlistenersforeveryelementwiththeclass-threeCSSclass;differentfunctionshandletheclickanddblclickevents.
Removingeventlistenersisequallysimplewiththeoff()method.Simplysupplythesameinformationyoupassedtoon().Thefollowingcoderemovestheeventlistenersregisteredinthepreviousexamples:
$(".class-one").off("click",elementClick);
$(".class-two").off("clickdblclick",eventHandler);
$(".class-three").off({
click:clickHandler,
dblclick:dblclickHandler
});
Youcanalsousetheoff()methodtoremovealleventlistenersfortheselectedelementsbynotpassinganyargumentstothemethod:
$(".class-four").off();
ThejQueryEventObjectAsyoulearnedinChapter10,somebigdifferencesexistbetweenthestandardandlegacyIEeventmodels.RememberthatjQuerywascreatedtomakecross-browserJavaScripteasiertowriteandmaintain.Sowhenitcametoevents,JohnResig,thecreatorofjQuery,decidedtocreatehisownEventobjectandbaseitonthestandardDOMEventobject.Thismeansthatyoudonothavetoworryaboutsupportingmultipleeventmodels;it’salreadydoneforyou.Allyouhavetodoiswritestandardcodeinsideyoureventhandlers.
Todemonstrate,youcanwritesomethinglikethefollowingcode,andit’llworkineverybrowser:
functionclickHandler(e){
e.preventDefault();
alert(e.target.tagName+"clickedwasclicked.");
}
$(".class-two").on("click",clickHandler);
NOTEForacompletelistofsupportedevents,seejQuery’swebsiteathttp://docs.jquery.com/Events.
RewritingtheTabStripwithjQueryYouhavelearnedhowtoretrieveelementsintheDOM,changeanelement’sstylebyaddingandremovingclasses,addandremoveelementsfromthepage,anduseeventswithjQuery.
Nowyou’llputthisnewfoundknowledgetoworkbyrefactoringthetoolbarfromChapter10.
TRYITOUTRevisitingtheTabStripwithjQueryOpenyourtexteditorandtypethefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter16:Example1</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="jquery-2.1.1.min.js"></script>
<script>
functionhandleEvent(e){
vartarget=$(e.target);
vartype=e.type;
if(type=="mouseover"||type=="mouseout"){
target.toggleClass("tabStrip-tab-hover");
}elseif(type=="click"){
target.addClass("tabStrip-tab-click");
varnum=target.attr("data-tab-number");
showDescription(num);
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("#descContainer").text(text);
}
$(".tabStrip>div").on("mouseovermouseoutclick",
handleEvent);
</script>
</body>
</html>
Savethisasch16_example1.htmlandopenitinyourbrowserandnoticethatitsbehaviorisidenticaltothatofch10_example17.html.
Ifyoucomparethisexamplewithch10_example17.html,you’llnoticequiteafewdifferencesinthecode’sstructure.Let’sstartwiththeverylastlineofcodewhereyouregistertheeventlisteners.Yourtabstripneedstorespondtothemouseover,mouseout,andclickeventsonthe<div/>elementsinsideofthetabstrip.jQuerymakesitextremelyeasytoregistereventlistenersonthese<div/>elementsforthedesiredevents:
$(".tabStrip>div").on("mouseovermouseoutclick",handleEvent);
Thiscodeselectsall“tabelements”inthedocumentwithjQuery’s$()functionandusestheon()methodtoregisterthemouseover,mouseout,andclickeventlistenersonthoseelements.
jQuerycodeaside,thisapproachisdifferentfromtheoriginal.Here,theevent
listenersareonthe<div/>elementsthemselvesasopposedtodocument.ThiswillsimplifythehandleEvent()function.Let’slookatthatnow.
ThefirsttwolinesofhandleEvent()dotwothings.ThefirstlinewrapsajQueryobjectaroundtheeventtarget,andthesecondgetsthetypeofeventthatoccurred:
functionhandleEvent(e){
vartarget=$(e.target);
vartype=e.type;
Intheoriginalversionofthiscode,youusedboththeeventtypeandthetarget’sCSSclasstodeterminewhichnewCSSclassyouassignedtotheelement’sclassNameproperty.Inthisnewversion,youonlyneedtoknowtheeventtype.Formouseoverandmouseoutevents,yousimplytogglethetabStrip-tab-hoverclass:
if(type=="mouseover"||type=="mouseout"){
target.toggleClass("tabStrip-tab-hover");
}
Butforclickevents,yournewcodecloselyresemblestheoriginal’s.First,youaddthetabStrip-tab-clickclasstotheelementusingjQuery’saddClass()method:
elseif(type=="click"){
target.addClass("tabStrip-tab-click");
varnum=target.attr("data-tab-number");
showDescription(num);
}
Thenyougetthevalueofthedata-tab-numberattribute.YoucouldoptionallyusejQuery’sdata()methodtodothesamethingbypassingittheattributenamewithoutdata-,likethis:data("tab-number").
Onceyouhavethetab’snumber,youpassitontoshowDescription().Thisfunctiondidnotchangemuch;itsimplyusesjQuery’sAPItoaccomplishitstask:
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("#descContainer").text(text);
}
Afteryoubuildthedescriptiontext,youselecttheelementservingasthedescriptioncontainerandsetitstextusingjQuery’stext()method.
Asyoucanseefromthisexample,jQuerysimplifiesDOMmanipulationandeventhandling.Inthisparticularexample,youwrotelessJavaScripttoattainthesameresults.That’swellworththetimeoflearningjQuery,isn’tit?
Butthat’snotall;jQuerycandothesamethingforyourAjaxcode.
UsingjQueryforAjax
InChapter14,youlearnedaboutAjaxandhowasynchronousrequestsrequireyoutowritealotofextracode.YouwroteasimpleutilitytohelpalleviatethecomplexityofAjaxcode,butjQuerycansimplifyAjaxevenmore.
UnderstandingthejQueryFunctionThejQueryfunction($())isthedoorwayintoallthingsjQuery,andyou’veuseditquiteabitthroughoutthischapter.However,thisfunctionhasotheruses.
Functionsareobjectsandtheyhaveapropertycalledprototype.Likeallotherobjects,youaccessaFunctionobject’spropertiesandmethodsusingtheobject.propertyorobject.method()syntax.Well,jQuery’s$functionhasmanymethods,andsomeofthemareformakingAjaxrequests.Oneofthemistheget()method,whichisformakingGETrequests.Thefollowingcodeshowsanexample:
$.get("textFile.txt");
ThiscodemakesaGETrequesttotheserverforthetextFile.txtfile.Butthiscodeisn’tveryusefulbecauseitdoesn’tdoanythingwiththeserver’sresponse.SoliketheHttpRequestmoduleyoubuiltinChapter14,the$.get()methodletsyoudefineacallbackfunctionthathandlestheresponsefromtheserver:
functionhandleResponse(data){
alert(data);
}
$.get("textFile.txt",handleResponse);
ThiscodedefinesafunctioncalledhandleResponse()andpassesitto$.get().jQuerycallsthisfunctiononasuccessfulrequestandpassesittherequesteddata(representedbythedataparameter).
RemembertheexamplesfromChapter14?Youcreatedaformthatcheckedifusernamesande-mailaddresseswereavailableusingAjax,andyousentthosevaluestotheserverasparametersintheURL.Forexample,whenyouwantedtotestausername,youusedtheusernameparameter,likethis:
phpformvalidator.php?username=jmcpeak
Withthe$.get()method,youcandothesamethingbypassinganobjectcontainingthekey/valuepairstothemethod.Forexample:
varparms={
username="jmcpeak"
};
functionhandleResponse(json){
varobj=JSON.parse(json);
//dosomethingwithobj
}
$.get("phpformvalidator.php",parms,handleResponse);
Thiscodecreatesanewobjectcalledparms,andithasausernamepropertywiththevalueofjmcpeak.Thisobjectispassedtothe$.get()methodasthesecondargument,withthehandleResponse()callbackfunctionpassedasthethird.
Youcansendasmanyparametersasyouneed;simplyaddthemaspropertiestotheparameterobject.
AutomaticallyParsingJSONDataInChapter14,theformvalidatorPHPfilereturnstherequesteddatainJSONformat,andnoticethattheprevioussamplecodeexpectsJSONdataandparsesitwiththeJSON.parse()method.jQuerycaneliminatethisstepandparsetheresponseforyou.Simplyusethe$.getJSON()methodinsteadof$.get().Forexample:
varparms={
username="jmcpeak"
};
functionhandleResponse(obj){
//objisalreadyanobject
}
$.getJSON("phpformvalidator.php",parms,handleResponse);
Thiscodeisalmostidenticaltothepreviousexampleexceptfortwothings.First,thiscodeuses$.getJSON()toissuearequesttothePHPfile.Bydoingso,youareexpectingJSON-formatteddataintheresponse,andjQuerywillautomaticallyparseitintoaJavaScriptobject.
TheseconddifferenceisinsidethehandleResponse()function.Becausetheresponseisautomaticallyparsed,youdon’thavetocallJSON.parse()inhandleResponse().
ThejqXHRObjectAsyou’veseenintheprevioussections,jQuery’sget()andgetJSON()methodsdonotactuallyreturnthedatayourequested;theyrelyuponacallbackfunctionthatyouprovideandpasstherequesteddatatoit.Butthesemethodsdo,infact,returnsomethinguseful:aspecialjqXHRobject.
ThejqXHRobjectiscalledadeferredobject;itrepresentsataskthathasn’tyetcompleted.Whenyouthinkaboutit,anasynchronousAjaxrequestisadeferredtaskbecauseitdoesn’timmediatelycomplete.Afteryoumaketheinitialrequest,you’releftwaitingforaresponsefromtheserver.
jQuery’sjqXHRobjecthasmanymethodsthatrepresentdifferentstagesofadeferredtask,butforthesakeofthisdiscussion,you’lllookatonlythree.Theyare:
METHODNAME DESCRIPTIONdone() Executeswhenthedeferredtasksuccessfullycompletesfail() Executeswhenthetaskfailsalways() Alwaysexecutes,regardlessifthetaskcompletedorfailed
Thesemethodsletyouaddfunctionstowhatarecalledcallbackqueues—collectionsoffunctionsthatserveascallbacksforaspecifiedpurpose.Forexample,thedone()methodletsyouaddfunctionstothe“done”callbackqueue,andwhenthedeferredactionsuccessfullycompletes,allofthefunctionsinthe“done”queueexecute.
Withthisinmind,youcanrewritethepreviouscodelikethis:
varparms={
username="jmcpeak"
};
functionhandleResponse(obj){
//objisalreadyanobject
}
varxhr=$.getJSON("phpformvalidator.php",parms);
xhr.done(handleResponse);
Noticethatinthiscode,thehandleResponse()functionisn’tpassedtothegetJSON()method;instead,it’saddedtothe“done”queuebypassingittothejqXHRobject’sdone()method.Inmostcases,you’dseethiscodewrittenasfollows:
$.getJSON("phpformvalidator.php",parms).done(handleResponse);
Youcanalsochainthesemethodcallstoeasilyaddmultiplefunctionstothecallbackqueues:
$.getJSON("phpformvalidator.php",parms)
.done(handleResponse)
.done(displaySuccessMessage)
.fail(displayErrorMessage);
Inthisexample,twofunctions,handleResponse()anddisplaySuccessMessage(),areaddedtothe“done”queue;whentheAjaxcallsuccessfullycompletes,bothofthesefunctionswillexecute.Additionally,thiscodeaddsthedisplayErrorMessage()functiontothe“fail”queue,anditexecutesiftheAjaxrequestfails.
Usingthesecallbackqueuemethodsdoesrequireyoutowriteslightlymorecode,buttheymakeyourcode’sintentionsabsolutelyclear.Plus,usingthemisgenerallyacceptedasabestpractice,andyou’llfindthemusedinmostmodernjQuery-basedcodethatyouread.
TRYITOUTRevisitingtheFormValidatorApplywhatyou’velearnedandmodifytheformvalidatorfromch14_example1.html.Openyourtexteditorandtypethefollowingcode:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter16:Example2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="jquery-2.1.1.min.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("#username").val();
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varparms={
username:userValue
};
$.getJSON("ch14_formvalidator.php",
parms).done(handleResponse);
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("#email").val();
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varparms={
email:emailValue
};
$.getJSON("ch14_formvalidator.php",
parms).done(handleResponse);
}
functionhandleResponse(response){
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
$("#usernameAvailability").on("click",checkUsername);
$("#emailAvailability").on("click",checkEmail);
</script>
</body>
</html>
Savethisasch16_example2.htmlinyourwebserver’srootdirectory.LiketheexamplesinChapter14,thisfilemustbehostedonawebserverinordertoworkcorrectly.Openyourwebbrowsertohttp://yourserver/ch16_example2.html.TypejmcpeakintotheUsernamefieldandclicktheCheckAvailabilitylinknexttoit.You’llseeanalertboxtellingyoutheusernameistaken.
Nowtypesomeone@xyz.comintheEmailfieldandclicktheCheckAvailabilitylinknexttoit.Again,you’llbegreetedwithanalertboxstatingthatthee-mailisalreadyinuse.Nowinputyourownusernameande-mailintothesefieldsandclicktheappropriatelinks.Chancesareanalertboxwilltellyouthatyourusernameand/ore-mailisavailable(theusernamesjmcpeakandpwiltonandthee-mailssomeone@[email protected]).
TheHTMLandCSSinthisexampleareidenticaltoch14_example1.html.So,let’sdigintotheJavaScriptstartingwiththefinaltwolinesofcodethatsetuptheclickeventlistenersontheCheckAvailabilitylinks.Youcouldeasilyreusethecodefromtheoriginal,butjQuerymakesitalittleeasiertosetupevents:
$("#usernameAvailability").on("click",checkUsername);
$("#emailAvailability").on("click",checkEmail);
YouselecttheelementsbytheirIDandusejQuery’son()methodtoregistertheclickeventonthoseelements.Onceagain,checkingtheusernamevalueisthejobofcheckUsername(),andcheckEmail()isresponsibleforcheckingthee-mailvalue.
ThenewcheckUsername()functionissomewhatsimilartotheoriginal.Youstartbypreventingthedefaultbehavioroftheeventbycallinge.preventDefault():
functioncheckUsername(e){
e.preventDefault();
Next,youneedtogetthevalueoftheappropriate<input/>element.Youhaven’tlearnedhowtoretrievethevalueofaformcontrolwithjQuery,butdon’tworry—it’sverysimple:
varuserValue=$("#username").val();
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
Youuse$()toselecttheappropriate<input/>elementandcalltheval()method.ThisretrievesthevalueoftheformcontrolandassignsittotheuserValuevariable.
Afteryouvalidatetheuser’sinput,you’rereadytostartissuingaGETrequesttotheserver.First,youcreateanobjecttocontaintheinformationyouwanttosendtotheserver:
varparms={
username:userValue
};
Youcallthisobjectparmsandpopulateitwiththeusernameproperty.Asyoulearnedearlierinthischapter,jQuerywilladdthispropertyanditsvaluetothequerystring.
Now,youcansendtherequestusingjQuery’sgetJSON()method:
$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);
}
YouaddthehandleResponse()functiontothe“done”queue,sothatwhentherequestsuccessfullycompletes,analertboxwilldisplaythesearchresults.
ThenewcheckEmail()functionisverysimilartocheckUsername().Thetwomaindifferences,ofcourse,arethedatayouretrievefromtheformandthedatayousendtotheserver:
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("#email").val();
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varparms={
email:emailValue
};
$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);
}
Thefinalfunction,handleResponse(),ismostlyunchangedfromtheoriginalversion.BecausejQuery’sgetJSON()methodautomaticallyparsestheresponseintoaJavaScriptobject,thenewhandleResponse()functionsimplyusesthepasseddataas-is:
functionhandleResponse(response){
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+"isnot
available.");
}
}
jQueryisanextensiveframework,andadequatelycoveringthetopicindepthrequiresmuchmorethanthischaptercanprovide.EntirebooksaredevotedtojQuery!However,thejQuerydocumentationisquitegood,andyoucanviewitathttp://docs.jquery.com.jQuery’swebsitealsolistsavarietyoftutorials,sodon’tforgettocheckthemoutat
SUMMARYThischapterintroducedyoutojQuery,themostpopularJavaScriptlibrary.
YoulearnedwhereandhowtoobtainjQueryandreferenceitinyourpages.
YoualsolearnedaboutjQuery’s$()function,andhowitiscentraltojQuery’sfunctionality.
jQuerypopularizedusingCSSselectorstofindelementswithintheDOM,andyoulearnedhowfindelementswiththe$()function.
Youcanchangeelementstyleswitheitherthecss()method,orbymodifyingtheCSSclasseswiththeaddClass(),removeClass(),andtoggleClass()methods.
Cross-browsereventscanbeadragwhendealingwitholderbrowserversions,butjQuerymakeregisteringeventlistenersandworkingwitheventdataeasy(andmostlystandardscompliant).
jQueryalsosimplifiesAjaxwithitsget()andgetJSON()methods,andyoulearnedthatgetJSON()automaticallyparsestheresponseintoaJavaScriptobject.
Youlearnedaboutdeferredobjects.Youalsolearnedaboutthe“done,”“fail,”and“always”queues,andhowyoucanchainthemtogethertoassignmultiplehandlerstothedifferentqueues.
EXERCISES1. Example1isbasedonChapter10’sExample17,andasyouprobablyremember,you
modifiedthatexampleinresponsetooneofChapter10’sexercisequestions.Modifythischapter’sExample1sothatonlyonetabisactiveatatime.
2. ThereissomerepetitivecodeinExample2.Refactorthecodetoreducetheduplication.Additionally,addafunctiontohandleanyerrorsthatmayoccurwiththerequest.
17OtherJavaScriptLibrariesWHATYOUWILLLEARNINTHISCHAPTER:
UsingModernizrtowritefeature-specificcode
Loadingexternalresourcesforbrowsersthatdonotsupportcertainfeatures
UsingPrototypeandMooToolstoperformcommontasks,suchasDOMmanipulationandAjaxrequests
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
jQueryisthemostpopularJavaScriptlibrarytoday.It’susedonhundredsofthousandsofwebsites,andyetit’snottheonlylibraryJavaScriptdevelopersuse.Infact,thousandsofJavaScriptlibrariesandutilitiesareavailable,andeachonecantypicallybecategorizedintotwogroups:generalandspecialty.
Theaimofgeneralframeworksistobalancethedifferencesbetweenbrowsersbycreatinganew,unifiedAPItoperformgeneraltaskslikeDOMmanipulationandAjaxfunctionality(jQueryisageneralframework).Specialtyframeworks,ontheotherhand,focusonaspecificability,suchasfeaturedetection.Soidentifywhatitisyouwanttoachieveandchooseaframeworkbasedonthat.Forexample,ifyouwantedtoperformanimationsandonlyanimations,thescript.aculo.usframework(http://script.aculo.us/)couldbeagoodchoiceforyou.
Thischapterlooksatbothgeneralandspecificframeworks.Whendecidingwhichframeworktouse,lookattheframework’sbrowsersupport,documentation,andcommunityinvolvement.Theframeworkscoveredinthischapterareestablished,stable,popular,andcompatiblewitheverymajormodernbrowser(andevenlegacyversionsofIE).You’lllearnabout:
Modernizr:AlibrarydesignedtodetectHTML5andCSSfeaturessupportedbythebrowser.(http://modernizr.com/)
Prototype:AframeworkthatprovidesasimpleAPItoperformwebtasks.AlthoughitofferswaysofmanipulatingtheDOM,Prototype’sprimaryaimistoenhancetheJavaScriptlanguagebyprovidingclassdefinitionandinheritance.(http://www.prototypejs.org)
MooTools:AframeworkthataimstobecompactwhileofferingasimpleAPItomakecommontaskseasier.LikePrototype,MooToolsalsoaimstoenhancetheJavaScriptlanguage—notjustmakeDOMmanipulationandAjaxeasier.Italsoincludesalightweighteffectscomponentoriginallycalledmoo.fx.
(http://www.mootools.net)
Thesearejustatinysamplingofwhatisavailableforyoutouseinyourwebpages.Someothersolutionsnotcoveredinthischapterare:
Yahoo!UserInterfaceFramework(YUI):AframeworkthatrangesfrombasicJavaScriptutilitiestocompleteDHTMLwidgets.Yahoo!hasateamdevotedtodevelopingYUI.(http://developer.yahoo.com/yui/)
ExtJS:ThisframeworkstartedasanextensiontotheYUI.ItofferscustomizableUIwidgetsforbuildingrichInternetapplications.(http://www.extjs.com)
Dojo:Atoolkitdesignedaroundapackagesystem.Thecorefunctionalityresemblesthatofanyotherframework(DOMmanipulation,eventnormalization,DHTMLwidgets,andsoon),butitprovidesandallowsawaytoaddmorefunctionalitybyaddingmorepackages.(http://www.dojotoolkit.org)
MochiKit:Aframeworkthatpridesitselfonitswell-testedness(hundredsoftestsaccordingtotheMochiKitsite)anditscompatibilitywithotherJavaScriptframeworksandlibraries.(http://www.mochikit.com)
DIGGINGINTOMODERNIZRAsyouundoubtedlyknowfromvariouspreviouschapters,JavaScriptdevelopmentisnotutopia.Itneverhasbeen,andrealistically,itneverwillbesimplyduetothefactthatmultiplebrowsersexist(whichisagoodthing—don’tgetuswrong),andthereisacertaindisparitybetweenthefeaturesthosebrowsersimplement.Thisisespeciallytrueasnewfeaturesaredevelopedandintroducedtothebrowser.Forexample,HTML5andCSS3introducemanynewfeaturesthatsomebrowsershaven’tyetimplemented.Ifyouwanttouseanyofthesenewfeaturesinyourpageorapplication,youhavetoensurethatthebrowseryourvisitorisusingproperlysupportsthem.Otherwise,yourpagewillbreak.
InChapter8,youlearnedhowtowritecodethattargetsspecificfeaturesthroughaprocesscalledfeaturedetection,andalthoughfeaturedetectionisatime-testedstrategy,twoproblemsexist:
Somefeaturescanbedifficulttodetect.
Differentbrowsersmaysupportwhatisessentiallythesamefeature,butitmaybeimplementeddifferently.
ModernizrfixestheseproblemsbyprovidingaunifiedAPIfordetectingHTML5andCSSfeaturesinthebrowser.
NOTEEventhoughModernizroffersmanyCSS-basedfeatures,thischapterfocusesonModernizr’sJavaScriptcapabilities.IfyouareinterestedinitsCSScapabilities,seehttp://modernizr.com/docs/formoreinformation.
GettingModernizrJustlikeeveryotherJavaScriptlibraryandframework,ModernizrisnothingmorethanaJavaScriptfilethatyouincludewithinyourpage.Itcomesintwodifferentflavors:development(uncompressed)andproduction(minified).Inmostcases,theproductionversioniswhatyouwanttouseinyourpageorapplicationbecauseitissmallerinsize,butthedevelopmentversioncouldproveusefulincertainsituationswhereyouneedtodebugyourcodealongwithModernizr’s(youlearnaboutdebugginginChapter18).
Modernizralsoletsyoupickandchoosethetestsyouneedtoperforminyourpageorapplication(Figure17.1).Forexample,ifyouonlyuselocalStorageornativedraganddropinyourpage,youcanbuildacustomizedversionofModernizrthatcontainsonlythenecessarycodefortestingthebrowser’ssupportforthosefeatures.
Figure17.1
AfeaturethatModernizrincludesbydefaultisautilitycalledHTML5Shiv.ThisutilityisonlyforlegacyversionsofIE,anditenablesyoutostyleHTML5elementsthatarenotsupportedinversionspriortoIE9.IfyoudonotplantotargetlegacyIE,youcanomitHTML5Shivinyourcustomizedbuild.
Modernizr’sdownloadexperiencevariesdependingontheversionyouwanttodownload.Thedevelopmentversionincludesmosttestsbydefault(youcanstillcustomizethebuildifthat’syourthing),butthedownloadpagealsohasaneasy-to-useDownloadbutton(asshowninFigure17.1).SimplyclickingthebuttondownloadsModernizrtoyourcomputer,andyoucansaveitwhereveryouneedto.
Theproductionversionisjustassimpletodownload.Mostfeaturesareexcludedbydefault,forcingyoutopickthefeaturesthatyouneedforyourpageorapplication.ThisisactuallyagoodmovebytheModernizrfolksbecauseyouwantacustomized(andthusoptimized)buildforyourspecificneeds.AfteryouselectyourdesiredfeaturesandclicktheGeneratebutton,theDownloadbuttonappears.
NOTEForthesakeofsimplicity,youcanfindthefullproductionversion(v2.8.3)inthecodedownloadforthischapter.Youcanalsodownloaditathttp://beginningjs.com/modernizr.js.
Modernizr’sdeveloperssuggestthat,forbestperformance,youreferenceModernizr’s<script/>elementinsidethe<head/>andafteryourstylesheetreferences.
Modernizr’sAPIModernizerhasastraightforwardAPIthatrevolvesaroundasingleobjectcalledModernizr.Ithasasetofpropertiesandmethodsthatyouusetodetermineifabrowser
supportsaparticularfeature.Forexample,youcandetermineifabrowsersupportsthegeolocationAPIfromChapter8likethis:
if(Modernizr.geolocation){
//usegeolocation
}
Atfirstglance,itlookslikeyouhaven’tgainedmuchbyusingModernizrbecauseinChapter8,youlearnedthatyoucandothesamethingwiththenavigatorobject,likethis:
if(navigator.geolocation){
//usegeolocation
}
ButrememberthatModernizrisalibraryfordetectingmanyfeatures,eventhosethatrequireabitmoreinvolvementtodetect.Forexample,thecodefordeterminingsupportfornativedraganddropismorecomplex.Theelementsinbrowsersthatsupportnativedraganddrophaveadraggableattribute,ortheysupporteventslikedragstartanddrop.Thatmeansthecodeneededtocheckfordraganddropsupportcouldlooklikethis:
varel=document.createElement("span");
if(typeofel.draggable!="undefined"||
(typeofel.ondragstart!="undefined"&&
typeofel.ondrop!="undefined")){
//usenativedraganddrop
}
Thiscodecreatesanarbitrary<span/>elementandchecksifithasadraggablepropertyorondragstartandondropproperties.Ifanyoftheseconditionsaretrue,thebrowsersupportsdraganddrop.
NOTETheaforementionedtestiswrittentoaccommodateIE8becauseitsupportsnativedraganddrop,butitdoesn’tsupportthedraggableattribute/property.
Thiscode,however,iscumbersometowriteandread.Modernizrsimplifiesitto:
if(Modernizr.draganddrop){
//usedraganddrop
}
Here,youcheckthebrowser’ssupportfordraganddropwithModernizr’sdraganddropproperty,andyougetthesameresultsastheprevioustest.
ModernizrchecksforawidevarietyofHTML5(andCSS3)features.Thefollowingtablelistsjustafew:
HTML5FEATURE MODERNIZRPROPERTYHTML5Audio audio
M4AAudio audio.m4a
MP3Audio audio.mp3
OGGAudio audio.ogg
WAVAudio audio.wav
HTML5Video video
H.264Video video.h264
OGGVideo video.ogg
WebMVideo video.webm
DragandDrop draganddrop
LocalStorage localstorage
Geolocation geolocation
Inadditiontothebuilt-intests,youcanalsoextendModernizrwithyourowntests.
CustomTestsYoucanaddyourownteststoModernizrwithitsaddTest()method.Theprocessissimple:simplycallModernizr.addTest(),passitthenameofyourtest,andpassthefunctionthatperformsthetest.
Forexample,itwasmentionedearlierthatalthoughIE8supportsnativedraganddrop,itdoesnotsupportthedraggableattribute/property.YoucanextendModernizrtotestforthisspecificfunctionalitylikethis:
Modernizr.addTest("draggable",function(){
varspan=document.createElement("span");
returntypeofspan.draggable!="undefined"
});
Thiscodeaddsanewtestcalled"draggable".Itsfunctioncreatesanarbitrary<span/>elementandchecksifithasadraggableproperty.Inmodernbrowsers,thedraggablepropertydefaultstofalse,butitisundefinedinIE8.Therefore,whenyouusethetestlikethis:
if(!Modernizr.draggable){
//codeforIE8
}
youcanruncodeforbrowsersthatdonotsupportthedraggableattribute/property.
Sometimes,however,youdon’twanttouseanifstatementtoruncodeforaspecificbrowser(orasetofbrowsers).Instead,wouldn’titbeniceifyoucouldloadanexternalJavaScriptfileforbrowsersthatpassedorfailedacertaintest?Modernizrcandothat!
LoadingResourcesModernizrhasanoptionalmethodcalledload()(youcanomititfromyourcustombuild),andit’susedtoloadexternalJavaScriptandCSSfilesbasedontheresultofatest.
Theload()method’sbasicusageissimple;youpassitanobjectthatdescribesthetestandresourcesyouwanttoload.Forexample:
Modernizr.load({
test:Modernizr.geolocation,
nope:"geo-polyfill.js",
yep:"geo.js"
});
ThiscodecallsModernizr.load()andpassesanobjectthathastest,nope,andyepasproperties(we’llcallthisayepnopeobject).Thetestpropertycontainstheresultofthetest.Ifitpasses,Modernizrloadsthefileassignedtotheyepproperty(geo.jsinthisexample).Butifitfails,thefileassignedtothenopeproperty(geo-polyfill.js)isloadedinstead.
NOTEApolyfillisathird-partyJavaScriptcomponentthatreplicatesthestandardAPIforolderbrowsers.
Theyepandnopepropertiesareoptional,soyoucanloadonlyoneresourceifyouneedto.Forexample,thefollowingcodeloadsaJavaScriptfileonlyforbrowsersthatdonotsupportthedraggableattribute/property:
Modernizr.load({
test:Modernizr.draggable,
nope:"draggable-polyfill.js"
});
Thistypeofbehaviorisidealinthesesituations.Youdon’twantorneedtoloadapolyfillforthedraggableattribute/propertyformodernbrowsers,butyoudoforolderbrowsers,likeIE8,thatdonotsupportit.
Modernizr’sload()methodalsoletsyourunmultipletests.Insteadofpassingasingleyepnopeobject,youcanpassanarrayofthem,likethis:
Modernizr.load([{
test:Modernizr.draggable,
nope:"draggable-polyfill.js"
},
{
test:document.addEventListener,
nope:"event-polyfill.js"
}]);
Thiscodepassesanarrayoftwoyepnopeobjectstotheload()method.Thefirstobjectisthesamecustomdraggabletestfromthepreviousexample.Thesecondobjectchecksifthebrowsersupportsthedocument.addEventListener()method;ifitdoesn’t,Modernizr
loadsaneventpolyfill.
Modernizrloadsexternalresourcesasynchronously.ThismeansthatthebrowserwillcontinuetoloadtherestofthepagewhileModernizrdownloadsandexecutestheexternalresources.Thiscancauseissuesifyourpagereliesonthoseresources;youhavetoensuretheyarecompletelyloadedbeforeyouattempttousethem.
Youcanavoidthistypeofissuebyaddingacompletepropertytoyouryepnopeobject.Thispropertyshouldcontainafunction,anditexecutesregardlessofwhathappenswhenall(orevennone)oftheresourcesarefinishedloading.Forexample:
functioninit(){
alert("Pageinitializationgoeshere!");
}
Modernizr.load([{
test:Modernizr.draggable,
nope:"draggable-polyfill.js"
},
{
test:document.addEventListener,
nope:"event-polyfill.js",
complete:init
}]);
Thisnewcodeaddstwochangestothepreviousexample.First,itdefinesafunctioncalledinit().ThisfunctionwouldnormallycontaincodetoinitializetheJavaScriptusedonthepage(suchassettingupeventlisteners).
Thesecondchangeistheadditionofthecompletepropertytooneoftheyepnopeobjects.It’ssettotheaforementionedinit()function,anditalwaysexecutes—eitherwhentheresourcesarecompletelyloaded,orimmediatelyforbrowsersthatdonotneedtheresources.
TRYITOUTRevisitingNativeDragandDropAsmentionedearlierinthissection,IE8supportsnativedraganddrop,butitdoesn’tsupportthedraggableattribute/property.Inthisexample,yourevisitch10_example21.htmlanduseModernizrtoloadtwopolyfills:onetosupportdraggable,andanothertosupportthestandardDOMeventmodel.
ThesepolyfillsarewrittenbyJeremyandareprovidedinthecodedownload.Theyareevent-polyfill.jsanddraggable-polyfill.js.Bothareopensource.Loadingthesepolyfillswillmakethisexampleworkwithminimalmodificationstotheexistingcode.
Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example1</title>
<style>
[data-drop-target]{
height:400px;
width:200px;
margin:2px;
background-color:gainsboro;
float:left;
}
.drag-enter{
border:2pxdashed#000;
}
.box{
width:200px;
height:200px;
}
.navy{
background-color:navy;
}
.red{
background-color:red;
}
</style>
<scriptsrc="modernizr.min.js"></script>
</head>
<body>
<divdata-drop-target="true">
<divid="box1"draggable="true"class="boxnavy"></div>
<divid="box2"draggable="true"class="boxred"></div>
</div>
<divdata-drop-target="true"></div>
<script>
functionhandleDragStart(e){
e.dataTransfer.setData("text",this.id);
}
functionhandleDragEnterLeave(e){
if(e.type=="dragenter"){
this.className="drag-enter";
}else{
this.className="";
}
}
functionhandleOverDrop(e){
e.preventDefault();
if(e.type!="drop"){
return;
}
vardraggedId=e.dataTransfer.getData("text");
vardraggedEl=document.getElementById(draggedId);
if(draggedEl.parentNode==this){
this.className="";
return;
}
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
this.className="";
}
functioninit(){
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-
target]");
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",
handleDragStart);
}
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",
handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",
handleDragEnterLeave);
targets[i].addEventListener("dragleave",
handleDragEnterLeave);
}
}
Modernizr.addTest('draggable',function(){
varspan=document.createElement("span");
returntypeofspan.draggable!="undefined";
});
Modernizr.load([{
test:Modernizr.draggable,
nope:"draggable-polyfill.js"
},
{
test:document.addEventListener,
nope:"event-polyfill.js",
complete:init
}]);
</script>
</body>
</html>
Savethisasch17_example1.htmlandloaditintoanybrowser(youcanalsoviewit
athttp://beginningjs.com/examples/ch17_example1.html).You’llseethatitbehavesexactlylikech10_example21.html,andifyoucanviewitinIE8,you’llseethatitworksthere,too.
Thiscodeisalmostidenticaltoch10_example21.html,solet’sjustgooverthenew/changedcode.First,youaddareferencetoModernizr:
<scriptsrc="modernizr.min.js"></script>
AsrecommendedbythefolksatModernizr,the<script/>elementresideswithinthedocument’s<head/>.
Thenextchangeistheadditionoftheinit()function.Thefunctionitselfisnew,butthecodeitexecutesisthesameinitializationcodefromch10_example21.html:
functioninit(){
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-target]");
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",handleDragStart);
}
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",handleDragEnterLeave);
targets[i].addEventListener("dragleave",handleDragEnterLeave);
}
}
Thiscodewaswrappedwithintheinit()functionsothatModernizrcanuseitasthecompletecallbackfunction,thereforesettinguptheeventlistenersaftertheevent-polyfill.jsfilehasbeencompletelyloaded.Thisiscrucialbecauseiftheeventpolyfillisn’tready,thepagewillnotworkinIE8.
Thefinaltwoadditionsarefamiliartoyou;thefirstcreatesacustomModernizrtestcalleddraggable:
Modernizr.addTest('draggable',function(){
varspan=document.createElement("span");
returntypeofspan.draggable!="undefined";
});
ThesecondcallsModernizr’sload()methodtoloadthenecessarypolyfillsifthey’reneeded:
Modernizr.load([{
test:Modernizr.draggable,
nope:"draggable-polyfill.js"
},
{
test:document.addEventListener,
nope:"event-polyfill.js",
complete:init
}]);
Weshouldadmitthat,inthecaseofthisexample,creatingthecustomdraggabletestisabitoverboard.Youonlyusethetestonce,soitwouldbeslightlymoreefficienttoomitthecustomtestandwritethefirstyepnopeobjectlikethis:
{
test:typeofdocument.createElement("span").draggable!=
"undefined",
nope:"draggable-polyfill.js"
}
Atthesametime,thisslightlymoreefficientversionisabituglier.Ultimately,thechoiceisyours.Incaseslikethis,however,manypeoplecreatethecustomtestinautilityfilebecauseitcouldbereusedinotherprojects.
DIVINGINTOPROTOTYPEjQueryisthemostpopularframeworktoday,butthatcrownusedtosituponPrototype’shead.UnlikejQuery,Prototype’sfocusisaugmentingthewayyouprogramwithJavaScriptbyprovidingclassesandinheritance.Itdoes,however,alsoprovidearobustsetoftoolsforworkingwiththeDOMandAjaxsupport.
GettingPrototypePointyourbrowsertoPrototype’sdownloadpageathttp://prototypejs.org/download.Here,you’llbegiventhechoicetodownloadthelateststableversion,oranolderversion.Theexamplesinthisbookusethelateststableversionatthetimeofthiswriting:v1.7.2.
NOTEThestableversionofPrototype1.7.2isprovidedinthecodedownload.
NocompressedversionsofPrototypeexist.
TestingYourPrototypeInstallationThelargestportionofthePrototypelibraryisitsDOMextensions.LikejQuery,itprovidesavarietyofhelpfulutilityfunctionstomakeDOMprogrammingabiteasier;itevenhasitsown$()function(unlikejQuery,Prototypedoesn’thaveaspecialnameforthisfunction;it’ssimplycalledthedollarfunction):
varbuttonObj=$("theButton");
Prototype’s$()functiononlyacceptselementidattributevaluesorDOMelementobjectstoselectandaddextrafunctionalitytoDOMobjects.PrototypedoeshaveafunctionthatallowsyoutouseCSSselectorstoselectelements;youlearnaboutthatlater.
LikejQuery,PrototypeprovidesitsownAPIforregisteringeventlisteners.ItextendstheEventobjectwithamethodcalledobserve(),whichisnotunliketheevt.addListener()methodyouwroteinChapter10.Forexample:
functionbuttonClick(){
alert("Hello,PrototypeWorld!");
}
Event.observe(buttonObj,"click",buttonClick);
TheEvent.observe()methodacceptsthreearguments:ThefirstistheDOMorBOMobjectyouwanttoregisteraneventlistenerfor,thesecondistheeventname,andthethirdisthefunctiontocallwhentheeventfires.YoucanuseEvent.observe()toregisteraneventlistenertoanyDOMorBOMobject.Youlookatthismethod,andotherwaystolistenforevents,laterinthischapter.
LikejQuery,youcanchainmethodcallstogetheronwrapperobjectscreatedwiththe$()function.Prototype’smethodnames,however,areabitmoreverbose:
functionbuttonClick(){
$(document.body).writeAttribute("bgColor","yellow")
.insert("<h1>Hello,Prototype!</h1>");
}
Event.observe(buttonObj,"click",buttonClick);
ThebuttonClick()functionnowmodifiesthe<body/>elementbychangingthebackgroundcolortoyellowandaddingcontenttothepage.Let’sbreakdownthisstatement.
First,youpassdocument.bodytothe$()function:
$(document.body)
Thisextendsthestandard<body/>elementwithPrototype’sextensionmethods—oneofwhichisthewriteAttribute()method.Asitsnameimplies,it“writes”orsetsanattributeontheelement:
writeAttribute("bgColor","yellow")
Thissetsthebody’sbgColorattributetoyellow.ThewriteAttribute()methodreturnstheDOMobjectitwascalledon,theextendeddocument.bodyobjectinthiscase.Soyoucancallanotherextensionmethod,calledinsert(),tosetitscontent:
insert("<h1>Hello,Prototype!</h1>")
Let’susethisasthebasisforafiletotestyourPrototypeinstallation.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example2</title>
</head>
<body>
<buttonid="theButton">ClickMe!</button>
<scriptsrc="prototype.1.7.2.js"></script>
<script>
varbuttonObj=$("theButton");
functionbuttonClick(){
$(document.body).writeAttribute("bgColor","yellow")
.insert("<h1>Hello,Prototype!</h1>");
}
Event.observe(buttonObj,"click",buttonClick);
</script>
</body>
</html>
Savethisasch17_example2.htmlandopenitinyourbrowser(http://beginningjs.com/examples/ch17_example2.html).YoushouldseesomethinglikeFigure17.2.Ifyoudon’t,makesurethatthePrototypeJavaScriptfileisinthesame
directoryastheHTMLfile.
Figure17.2
RetrievingElementsPrototype’s$()functionisverydifferentfromjQuery’s.Ifyourememberfromthepreviouschapter,jQuery’s$()functioncreatesajQueryobjectthatwrapsitselfaroundoneormultipleDOMelementobjects.Incontrast,Prototype’s$()functionreturnstheactualDOMobject(muchlikedocument.getElementById()),butitalsoextendstheelementobjectwithmanynewpropertiesandmethods:
varel=$("myDiv");
ThiscoderetrievestheelementwithanidofmyDiv,andyoucanusethisobjectjustlikeyouuseanyotherelementobject.Forexample,thefollowingcodealertstheelement’stagnamewiththetagNameproperty:
alert(el.tagName);
Youcanalsoextendanelementbypassingtheelement’sobjecttothedollarfunction.Thefollowingcodepassesthedocument.bodyobjecttothedollarfunctioninordertoextendit:
varbody=$(document.body);
Bydoingthis,youcanusebothnativeDOMmethodsandpropertiesaswellasPrototype’smethods.
NOTEPrototype’sdollarfunctionreturnsnullifthespecifiedelementcannotbefound.ThisisunlikejQuery’s$()functionbecausePrototypereturnsanextendedDOMelementobject;eventhoughitisextended,itisstillaDOMelementobject.
SelectingElementswithCSSSelectors
Asmentionedbefore,Prototype’sdollarfunctiondoesnotselectelementsbaseduponCSSselectors;itonlyacceptselementidvaluesandelementobjects.Prototypedoes,however,haveanotherfunctionthatbehavessimilarlytothejQueryfunction:the$$()function.
Youcanusethe$$()functiontolocateandretrieveelementsthatmatchtheprovidedCSSselector.Forexample,thefollowingcoderetrievesall<div/>elementsinthepageandreturnstheminanarray:
vardivEls=$$("div");
The$$()functionalwaysreturnsanarray—evenifyouuseanidselector.Onedownsideto$$()isthatitreturnsanarrayofextendedelements;soifyouwanttoperformanoperationoneveryelementinthearray,youhavetoiterateoverthearraywitheitheralooporaniterativeArraymethod(fromChapter5).
PerforminganOperationonElementsSelectedwith$$()Because$$()returnsanarray,youcanusetheArraymethodstoperformiterativeoperations.Forexample,thefollowingcodeusestheforEach()methodtoinsertcontentintoeachelementinthearray:
functioninsertText(element){
element.insert("ThistextinsertedusingtheforEach()method.");
}
$$("div").forEach(insertText);
YoucanalsousemultipleCSSselectorstoselectelementswiththe$$()function.Insteadofpassingasinglestringthatcontainsthemultipleselectors,youpasseachselectorasanargumenttothemethod,likethis:
varelements=$$("#myDiv","p>span,.class-one");
Thiscodeselectselementsbasedupontwoselectors:#myDivandp>span,.class-one,anditreturnsanarraythatcontainsalloftheextendedelementobjectsthatmatchthoseselectors.
NOTEFormoreinformationontheCSSselectorssupportedinPrototype,seehttp://prototypejs.org/doc/latest/dom/dollar-dollar/.
ManipulatingStylePrototypegivesyouseveralmethodsyoucanusetochangeanelement’sstyle.ThemostbasicisthesetStyle()method,whichsetsindividualstyleproperties.TousesetStyle(),youcreateanobjectthatcontainstheCSSpropertiesandvaluesthatyouwanttoset.Forexample,thefollowingcodesetsanelement’sforegroundandbackgroundcolors:
varstyles={
color:"red",
backgroundColor:"blue"
};
$("myDiv").setStyle(styles);
Asyouknowfrompreviouschapters,changinganelement’sstyleinthismannerisusuallyundesirable.AbettersolutionistomanipulatetheCSSclassesappliedtoanelement,andPrototypegivesyoufoureasy-to-usemethodstodojustthat.
Thefirstmethod,addClassName(),addsaCSSclasstotheelement.Thefollowingcodeaddstheclass-oneCSSclasstotheelement:
$("myDiv").addClassName("class-one");
Thesecondmethod,removeClassName(),removesthespecifiedclassfromtheelement.Thefollowingcoderemovestheclass-twoCSSclassfromtheelement:
$("myDiv").removeClassName("class-two");
NextisthetoggleClassName()method,andittogglesthespecifiedclass.Thefollowingcodetogglestheclass-threeCSSclass.Ifitisalreadyappliedtotheelement,theclassisremoved.Otherwise,itisappliedtotheelement:
$("myDiv").toggleClassName("class-three");
Thefinalmethod,hasClassName(),checksifthespecifiedclassisappliedtotheelement:
$("myDiv").toggleClassName("class-three");
Naturally,iftheclassexists,thetoggleClassName()methodreturnstrue.Otherwise,itreturnsfalse.
TheseCSSmethodsareverysimilartojQuery’sCSSclassmanipulationmethods,butPrototype’smethodsforcreatingandinsertingelementsdiffergreatlyfromjQuery’smethods.Removingelements,however,isverysimilartojQuery.
Creating,Inserting,andRemovingElementsPrototypemakesiteasytomanipulatetheDOMbecauseitextendstheElementobject.Let’sstartbycreatingelements.
CreatinganElementPrototypeaddsaconstructorfortheElementobject,anditacceptstwoarguments:theelement’stagnameandanobjectcontainingattributesandtheirvalues.Thefollowingcodecreatesan<a/>elementandpopulatesitsidandhrefattributes:
varattributes={
id="myLink",
href="http://prototypejs.org"
};
vara=newElement("a",attributes);
Thefirstfewlinesofthiscodecreateanobjectcalledattributesanddefineitsidandhrefproperties.Theythencreatean<a/>elementbyusingtheElementobject’sconstructor,passing"a"asthefirstargumentandtheattributesobjectasthesecond.
AddingContentPrototypeextendselementobjectswithtwomethodsforaddingcontent:insert()andupdate().Theaptlynamedinsert()methodinsertsnewcontentattheendoftheelement.Thefollowingcodeinsertstheaobjectfromthepreviousexampleintothedocument’sbody:
$(document.body).insert(a);
Theupdate()methodreplacesallexistingcontentwithintheelement.Thefollowingcodeupdatesthedocument’sbodywiththeaobject,therebyreplacingtheexistingcontentwiththe<a/>element:
$(document.body).update(a);
It’simportanttorememberthedistinctionbetweenthetwomethods;otherwise,youmayexperienceunexpectedresultsinyourwebpage.
RemovinganElementPrototypemakesiteasytoremoveanelementfromtheDOM;simplycalltheremove()methodontheelementobjectyouwanttoremove,likethis:
a.remove();
UsingEventsWhenyouextendanElementobjectwiththe$()function,yougainaccesstoitsobserve()method.LikethenativeaddEventListener()method,thisregistersaneventlistenerforaDOMelement,anditacceptstwoarguments:theeventnameandthefunctiontocallwhentheeventfires.Forexample,thefollowingcoderegistersaclickeventlistenerthatexecutesthedivClick()function:
functiondivClick(event){
//dosomething
}
$("myDiv").observe("click",divClick);
Andasyousawearlier,youcanalsousetheEvent.observe()method.ThefollowingcodeachievesthesameresultsusingEvent.observe():
functiondivClick(event){
//dosomething
}
Event.observe("myDiv","click",divClick);
ThiscodeisslightlydifferentfromthefirsttimeyousawEvent.observe()becausethefirstargument,inthiscase,isastring.YoucanpasstheidofanelementoraDOM/BOMobjectasthefirstargumenttoEvent.observe().Thismethodisparticularlyusefulforobjectslikewindow.Youcannotcall$(window).observe()becausethebrowserwillthrowanerror.Instead,youhavetouseEvent.observe().
Prototypedoesn’temulatetheW3CDOMeventmodel.Instead,itextendstheeventobjectsoflegacy-IEandstandards-compliantbrowserstogiveyouasetofutilitymethodstoworkwitheventdata.
Forexample,theelement()methodreturnstheeventtarget(thesrcElementpropertyforlegacy-IE,andthetargetpropertyforW3CDOMbrowsers).Thefollowingcodeusestheelement()methodtoretrievethetargetoftheclickeventandtogglestheclass-oneCSSclass:
functiondivClick(e){
vartarget=e.element();
target.toggleClassName("class-one");
}
$("myDiv").observe("click",divClick);
Theelementreturnedbytheelement()methodisalreadyextendedwithPrototype’smethods;so,there’snoneedtopassitto$()togettheextrafunctionality.
RewritingtheTabStripwithPrototypeYounowknowhowtoretrieveandmanipulateelements,addandremoveelements,andregistereventlistenerswithPrototype.Let’sadaptthejQueryversionofthetabstripfromch16_example2.html.
TRYITOUTRevisitingtheToolbarwithPrototypeOpenyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example3</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="prototype.1.7.2.js"></script>
<script>
functionhandleEvent(e){
vartarget=e.element();
vartype=e.type;
if(type=="mouseover"||type=="mouseout"){
target.toggleClassName("tabStrip-tab-hover");
}elseif(type=="click"){
target.addClassName("tabStrip-tab-click");
varnum=target.getAttribute("data-tab-number");
showDescription(num);
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("descContainer").update(text);
}
$$(".tabStrip>div").forEach(function(element){
element.observe("mouseover",handleEvent);
element.observe("mouseout",handleEvent);
element.observe("click",handleEvent);
});
</script>
</body>
</html>
Savethisfileasch17_example3.htmlandloaditintoyourbrowser(http://beginningjs.com/examples/ch17_example3.html).You’llnoticeitbehavesthesameastheothertabstripscripts.
BecausetheCSSandmarkupremainsunchangedinthejQueryversion,let’sfocusontheJavaScriptthatchanged—startingwiththehandleEvent()function:
functionhandleEvent(e){
vartarget=e.element();
Here,yougettheeventtargetusingtheelement()extensionmethodandassignittothetargetvariable.
Next,youdeterminethetypeofeventthattookplace.Youfirstcheckformouseoverandmouseoutevents:
if(type=="mouseover"||type=="mouseout"){
target.toggleClassName("tabStrip-tab-hover");
Ifeitheroftheseeventstakesplace,youwanttotogglethetabStrip-tab-hoverCSSclass.Formouseoverevents,thisCSSclassisappliedtothetargetelement,andformouseout,theclassisremoved.
Nowyouneedtodetermineiftheclickeventfired:
}elseif(type=="click"){
target.addClassName("tabStrip-tab-click");
Ifso,youaddthetabStrip-tab-clickCSSclasstothetargetelementtochangeitsstyletothatofaclickedtab.Then,youneedtogetthetab’snumberfromtheelement’sdata-tab-numberattribute:
varnum=target.getAttribute("data-tab-number");
showDescription(num);
}
}
YouusethenativegetAttribute()methodtoretrievethatattribute’svalueandpassittoshowDescription().
Asyouknow,theshowDescription()functionaddsthetab’sdescriptiontothepage.
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("descContainer").update(text);
}
Here,youselecttheelementrepresentingthedescriptioncontainerandreplaceitscontentswiththeupdate()method.
Thefinalbitofcodesetsuptheeventlistenersforthetabelements.Usingthe$$()function,youretrievethemusingthe.tabStrip>divselector:
$$(".tabStrip>div").forEach(function(element){
element.observe("mouseover",handleEvent);
element.observe("mouseout",handleEvent);
element.observe("click",handleEvent);
});
YouusetheArrayobject’sforEach()methodtoiterateoverthearrayreturnedby$$().ThefunctionyoupasstoforEach()isresponsibleforregisteringthemouseover,mouseout,andclickeventlistenersoneachelement,andyouregisterthoseeventsusingtheobserve()extensionmethod.
Prototypeisn’tjustaboutDOMmanipulationandlanguageenhancement.It,too,providesyouwithAjaxcapabilitiesthatareeasytolearnanduse.
UsingAjaxSupportUnfortunately,Prototype’sAjaxsupportisn’tasstraightforwardasjQuery’s.Prototype’sAjaxfunctionalitycentersonitsAjaxobject,whichcontainsavarietyofmethodsyoucanusetomakeAjaxcalls.ThisobjectismuchlikethejQueryobjectinthatyoudonotcreateaninstanceofAjax;youusethemethodsmadeavailablebytheobjectitself.
AttheheartoftheAjaxobjectistheAjax.Request()constructor.Itacceptstwoarguments:theURLandanobjectcontainingasetofoptionsthattheAjaxobjectuseswhenmakingarequest.TheoptionsobjectcancontainavarietyofoptionpropertiestoalterthebehaviorofAjax.Request().Thefollowingtabledescribesjustafewofthem.
OPTION DESCRIPTIONasynchronous DetermineswhetherornottheXMLHttpRequestobjectmakestherequest
inasynchronousmode.Thedefaultistrue.method TheHTTPmethodusedfortherequest.Thedefaultis"post"."get"is
anothervalidvalue.onSuccess AcallbackfunctioninvokedwhentherequestcompletessuccessfullyonFailure Acallbackfunctioninvokedwhentherequestcompletes,butresultsinan
errorstatuscodeparameters Eitherastringcontainingtheparameterstosendwiththerequest,oran
objectcontainingtheparametersandtheirvalues
NOTEForacompletelistofoptions,visitthePrototypedocumentationathttp://prototypejs.org/doc/latest/ajax/.
MakingarequestwithPrototypelookssomethinglikethefollowingcode:
functionrequestSuccess(transport){
alert(transport.responseText);
}
functionrequestFailed(transport){
alert("Anerroroccurred!HTTPstatuscodeis"+transport.status);
}
varoptions={
method:"get",
onSuccess:requestSuccess,
onFailure:requestFailed
};
newAjax.Request("someTextFile.txt",options);
ThefirstfewlinesofcodedefinetherequestSuccess()andrequestFailed()functions.Thesefunctionsacceptaparametercalledtransport—aspecialobjectthatcontainstheserver’sresponse(moreonthislater).
Afterthefunctiondefinitions,youcreateanoptionsobjectthatcontainspropertiesfortheHTTPmethodoption,theonSuccessoption,andtheonFailureoption.Then,youfinallymaketherequestforthesomeTextFile.txtfile,passingtheoptionsobjecttotheAjax.Request()constructor(don’tforgetthenewkeyword!).
Ifyouneedtosendparameterswithyourrequest,you’llhavetodoabitmorepreparationbeforecallingnewAjax.Request().LikejQuery,youcancreateanobjecttocontaintheparameternamesandvalues.Forexample,ifyouneedtosendaparametercalledusernamewithyourrequest,youcandosomethinglikethis:
varparms={
username:"jmcpeak"
};
options.parameters=parms;
WhenyousendtherequestbycreatinganewAjax.Requestobject,theparametersareaddedtotheURLbeforetherequestissenttotheserver.
AllcallbackfunctionsarepassedaparametercontaininganAjax.Responseobject,anobjectthatwrapsaroundthenativeXMLHttpRequestobject.Itcontainsavarietyofusefulpropertiesforworkingwiththeserver’sresponse.ItemulatesthebasicpropertiesofXMLHttpRequest,suchasreadyState,responseText,responseXML,andstatus.Butitalsoexposesafewconvenienceproperties,asoutlinedinthefollowingtable.
PROPERTYNAME
PURPOSE
request TheAjax.RequestobjectusedtomaketherequestresponseJSON AparsedJSONstructureiftheresponse’sContent-Typeheaderis
application/json
statusText TheHTTPstatustextsentbytheservertransport ThenativeXMLHttpRequestobjectusedtomaketherequest
Nowthatyou’vebeengivenacrashcourseinPrototype’sAjaxfunctionality,let’smodifytheAjaxFormValidator.
TRYITOUTRevisitingtheFormValidatorwithPrototypeOpenyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example4</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="prototype.1.7.2.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varoptions={
method:"get",
onSuccess:handleResponse,
parameters:{
username:userValue
}
};
newAjax.Request("ch14_formvalidator.php",options);
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varoptions={
method:"get",
onSuccess:handleResponse,
parameters:{
email:emailValue
}
};
newAjax.Request("ch14_formvalidator.php",options);
}
functionhandleResponse(transport){
varresponse=transport.responseJSON;
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
$("usernameAvailability").observe("click",checkUsername);
$("emailAvailability").observe("click",checkEmail);
</script>
</body>
</html>
Savethisasch17_example4.htmlinyourwebserver’srootdirectory,becausethisfilemustbehostedonawebservertoworkcorrectly.Pointyourbrowsertohttp://yourserver/ch17_example4.htmlandtestouttheform.
Thispageworksexactlylikethepreviousversions.Let’sstartexaminingthisversionwiththecheckUsername()function.Asyouknow,thisfunctionisresponsibleforgatheringtheuserinputandsendingittotheserver.
Togettheuser’sinput,youretrievetheappropriate<input/>elementandgetitsvalue:
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("username").value;
Youcouldusethenativedocument.getElementById()methodtoretrievethe<input/>element,butPrototype’s$()functionismucheasiertotype.ItreturnsanextendedElementobject,butyouusethestandardvaluepropertytoretrievetheelement’svalue.
Next,youchecktheuserinputtoensureyouhaveworkabledata:
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
Ifthefunctionmakesitpastthisifstatement,youneedtoassembletheoptionsobjectthatyoupasstotheAjax.Request()constructor:
varoptions={
method:"get",
onSuccess:handleResponse,
parameters:{
username:userValue
}
};
ThisoptionsobjecthastherequiredmethodandonSuccessproperties,andyoualsoincludetheparameters—settingusernametothevalueobtainedfromtheform.
Nowyou’rereadytosendtherequest.So,youcalltheAjax.Request()constructorandpassittheURLandoptionsobject.
Asthelaststepinthisfunction,youcalltheAjax.Request()constructor,prependedbythenewkeyword,andpasstheURLtoformvalidator.phpandtheoptionsobject:
newAjax.Request("ch14_formvalidator.php",options);
}
ThecheckEmail()functionisalmostidenticaltocheckUsername().First,youretrievethee-mailaddressfromtheformandvalidateit:
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
Next,youbuildtheoptionsobject:
varoptions={
method:"get",
onSuccess:handleResponse,
parameters:{
email:emailValue
}
};
Onceagain,youprovidetheobligatorymethodandonSuccessproperties,aswellastheparametersobject.Yousettheemailparameterpropertytothee-mailaddressfromtheform.
Then,youissuetherequestbycallingtheAjax.Request()constructor:
newAjax.Request("ch14_formvalidator.php",options);
}
ThehandleResponse()functionisnotleftuntouched,butthechangeissubtle:
functionhandleResponse(transport){
varresponse=transport.responseJSON;
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+"isnot
available.");
}
}
ThisnewversionusesPrototype’sresponseJSONpropertytogettheparsedJSON.Youcanusethispropertybecausech14_formvalidator.php’sContent-Typeheaderissettoapplication/json.Ifitwasanyothervalue,liketext/plain,thenresponseJSONwouldbenull,andyouwouldhavetouseresponseTextinconjunctionwithJSON.parse(),likethis:
varresponse=JSON.parse(transport.responseText);
Thefinaltwolinesofcodeinthisexampleregistertheclickeventlistenersonthetwo<a/>elements:
$("usernameAvailability").observe("click",checkUsername);
$("emailAvailability").observe("click",checkEmail);
YouretrievetheelementsusingPrototype’s$()function,andthenyouuseobserve()toregistertheeventlisteners.
PrototypeisapowerfulframeworkthatprovidesarichsetofutilitiestochangethewayyouwriteJavaScript.Butasimplesectionsuchasthisisfartoosmalltocovertheframeworkadequately.ForfurtherinformationonPrototypeandtheutilityitoffers,seetheAPIdocumentationathttp://api.prototypejs.org/andthetutorialsathttp://prototypejs.org/learn/.
DELVINGINTOMOOTOOLSAtfirstglance,MooToolslooksidenticaltoPrototype,andrightlyso.MooToolswasfirstdevelopedtoworkwithPrototype,soyoushouldn’tbesurprisedtoseesomestrikingsimilaritiesbetweenthetwo.
However,MooToolsismoreofacrossbetweenjQueryandPrototypeasfarasDOMmanipulationisconcerned.LikePrototype,MooTools’goalistoaugmentthewayyouwriteJavaScript,providingtoolstowriteclassesandinheritfromthem.AlsolikePrototype,MooToolsaddsinarichsetofextensionstomakeDOMmanipulationeasier,andyou’llfindthatselectingDOMobjectsinMooToolsisexactlythesameasPrototype.Butasyou’llseeinthefollowingsections,theextensionmethodnamesandthewayinwhichyouusethemisreminiscentofjQuery.
GettingMooToolsYoucandownloadMooToolsintwoways:Youcandownloadthecore,oryoucancustomizeyourownbuild.TheMooTools’corecontainseverythingyouneedtoperformcommonDOMandAjaxoperations,butifyoudon’tneedthefullpowerofcore,youcanpickandchoosewhichpiecesyouneedforyourpageorapplication.
Regardlessoftheversionyouwant,youcandownloadbothathttp://mootools.net/core/builder.Additionally,youcanchoosetodownloadthecompressedoruncompressedJavaScriptfile.Thecodedownloadincludesthecompressedcoreofversion1.5.1.
TestingYourMooTools’InstallationAswementionedearlier,manysimilaritiesexistbetweenMooToolsandPrototype;so,testingyourMooTools’installationwilllookverysimilartothePrototypetest.
MooToolshasa$()function,justlikePrototype’s:
varbuttonObj=$("theButton");
Itacceptseitherastringcontaininganelement’sidoraDOMelementandreturnstheDOMobjectwithanextendedsetofmethodsandproperties.OnesuchmethodistheaddEvent()methodwhich,asyouprobablydeduced,registersaneventlistener.
TheaddEvent()methodacceptstwoarguments:theeventnameandthefunction.So,youcanregisteraneventlistenerlikethis:
functionbuttonClick(){
alert("Youclickedthebutton!");
}
buttonObj.addEvent("click",buttonClick);
MooTools’extensionmethodsprovideavarietyofmethodsandpropertiesformanipulatingelementsinthepage.Mostofthemethodsarechainable,thereforeallowing
youtoperformmultipleoperationswithlesscode.Forexample:
functionbuttonClick(){
$(document.body).setProperty("bgColor","yellow")
.appendHTML("<h1>Hello,MooTools!</h1>");
}
buttonObj.addEvent("click",buttonClick);
Youcansetanelement’sattributeswiththesetProperty()method,asdemonstratedinthiscode.Thismethodreturnstheelementobject,soyoucanthenimmediatelyappendcontenttotheelementbycallingtheappendHTML()method.
UsethiscodetotestyourMooTools’installation.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example5</title>
</head>
<body>
<buttonid="theButton">ClickMe!</button>
<scriptsrc="mootools-core-1.5.1-compressed.js"></script>
<script>
varbuttonObj=$("theButton");
functionbuttonClick(){
$(document.body).setProperty("bgColor","yellow")
.appendHTML("<h1>Hello,MooTools!</h1>");
}
buttonObj.addEvent("click",buttonClick);
</script>
</body>
</html>
Savethisasch17_example5.htmlandloaditinyourbrowser.Whenyouclickthebutton,thebackgroundcolorshouldchangetoyellow,and“Hello,MooTools!”shoulddisplayinthepage.Ifnot,makesuretheMooTools’JavaScriptfileislocatedinthesamedirectoryasyourHTMLpage.
FindingElementsEarlier,wementionedthatMooTools’$()functionissimilartoPrototype’s.Well,let’sclearitupnow;theyareexactlythesame.TheyfindtheelementobjectintheDOMandextendit,albeitwithdifferentmethodsthatyou’llseeinthefollowingsections.Forexample,thefollowingcodefindsanelementwithanidofmyDiv,extendsitwithMooTools’methodsandproperties,andreturnsit:
varelement=$("myDiv");
Withthisobject,youcanuseMooTools’extensionmethodsaswellasthenativeDOMmethodsandproperties:
vartagName=element.tagName;//standardDOM
element.appendHTML("NewContent");//extension
Ifanelementwiththegiveniddoesnotexist,$()returnsnull.
YoucanalsopassaDOMobjecttothe$()functiontoextenditaswell:
varbody=$(document.body);
SelectingElementswithCSSSelectorsMooToolshasthe$$()functiontoselectelementswithCSSselectors,andyoucanpassmultipleCSSselectorstoretrieveawidevarietyofelements.LikePrototype,youpasseachselectorasanargumenttothefunction:
varclassOne=$$(".class-one");
varmultiple=$$("div",".class-one","p>div")
The$$()functionreturnsanarrayofextendedDOMelementobjects.ThisiswhereMooToolsandPrototypestarttodifferbecausewhilebothframeworksextendtheArrayobjectreturnedby$$(),MooToolsaddsextensionmethodsthatmanipulatetheelementswithinthearray.
PerformingOperationsonElementsMooTools’$$()isacrossbetweenjQuery’s$()andPrototype’s$$()inthatitreturnsanarrayofextendedelementobjects(likePrototype),butyoucanuseavarietyofmethodstoworkwiththoseelementswithouthavingtomanuallyiteratethearray.Forexample,youcanchangethestyleofallelementswithinanarraybycallingthesetStyle()method,likethis:
$$("div",".class-one").setStyle("color","red");
Thiscodeselectsmultipletypesofelementsandsetstheirtextcolortored.ContrastthatwithPrototype:
//Prototype
functionchangeColor(item){
varstyles{
color:"red"
};
item.setStyle(styles);
}
$$("div",".class-one").forEach(changeColor);
NotethatyoucouldusethistechniqueinMooTools.Infact,youwanttodosowhenperformingmultipleoperationstothesamesetofelements.RememberthatmethodslikeMooTools’setStyle()andjQuery’scss()areiterative;theyloopoverthearray.
Chainingiterativemethodstogethermeansyouareexecutingmultipleloops,whichisinefficient.
ChangingStyleThepreviousMooTools’codeexampleintroducedyoutothesetStyle()method.Itacceptstwoarguments:thefirstistheCSSproperty,andthesecondisitsvalue.LikejQuery,youcanusetheCSSpropertyusedinastylesheetorthecamel-caseversionusedinscript:
$("myDiv").setStyle("background-color","red");//valid
$("myDiv").setStyle("backgroundColor","red");//valid,too
Bothlinesofthiscodesettheelement’sbackgroundcolortored;soyoucanuseeitherpropertynametosetindividualstyleproperties.
MooToolsalsohasasetStyles()methodforchangingmultipleCSSproperties.Tousethismethod,passanobjectthatcontainstheCSSpropertiesandvalues,likethis:
$("myDiv").setStyles({
backgroundColor:"red",
color:"blue"
});
Thisis,ofcourse,nottheidealwaytochangeanelement’sstyle.So,MooToolsaddstheaddClass(),removeClass(),toggleClass(),andhasClass()extensionmethodstoDOMelementobjects.
TheaddClass()andremoveClass()methodsdojustwhattheirnamesimply.Theyaddorremovethespecifiedclasstoorfromtheelement:
vardiv=$("myDiv");
div.addClass("class-one");
div.removeClass("class-two");
ThetoggleClass()method,naturally,togglesaclass.
div.toggleClass("class-three");
Thiscodetogglestheclass-threeCSSclass.Iftheelementalreadyhastheclass,itisremovedfromtheelement.Otherwise,itisadded.
ThehasClass()methodreturnstrueorfalsedependingonwhetherornottheelementhastheCSSclass:
div.hasClass("class-four");
Thiscodereturnsfalsebecausetheclass-fourCSSclassisn’tappliedtotheelement.
Ofcourse,changinganelement’sstyleisn’ttheonlyDOM-relatedthingsMooToolscando;youcanalsocreate,insert,andremoveelementsfromtheDOM.
Creating,Inserting,andRemovingElementsLikePrototype,MooToolsletsyoucreateelementswiththeElementconstructor:
varattributes={
id:"myLink",
href:"mootools.net"
};
vara=newElement("a",attributes);
Whenyoucalltheconstructor,youpassthetagnameandanobjectcontainingyourdesiredattributes.Theprecedingcodecreatesanew<a/>elementandpopulatesitsidandhrefproperties.YoucanthensetitscontentwiththeappendText()orappendHTML()methods:
a.appendText("GotoMooTools'Website");
MooToolsalsoaddsaset()extensionmethodthatletsyousetthevalueofaproprietary“property.”ThesearenotpropertiesinthesenseofaJavaScriptpropertyusingobject.propertyNamesyntax;instead,they’remoreofavirtualproperty.Forexample,thereisanhtmlpropertythatsetstheHTMLofanelement,andyousetthispropertywiththeset()method,likethis:
a.set("html","GotoMooTool'sWebsite");
ThisisessentiallythesameasusingthenativeinnerHTMLproperty,andinmostcases,you’dwanttouseinnerHTML.
Whenyou’rereadytoaddtheelementtothepage,usetheadopt()method:
$(document.body).adopt(a);
Thiscodeappendsthenewlycreated<a/>elementtothepage’s<body/>elementwiththeadopt()method.Notethatthisdoesn’treplaceexistingcontent;itsimplyaddsnewcontenttothepage.Ifyouneedtoemptyanelementofitschildren,calltheempty()method:
$(document.body).empty();
Youcanalsoremoveanindividualelementwiththedispose()method:
a.dispose();
UsingEventsAsyouknow,the$()functionreturnsanextendedelementobject.OneoftheextensionmethodsistheaddEvent()method,whichregistersaneventlistener:
functiondivClick(e){
alert("Youclickedme!");
}
$("myDiv").addEvent("click",divClick);
TheaddEvent()methodacceptstwoarguments:theeventnameandthefunctiontoexecutewhentheeventfires.
YoucanalsoregistermultipleeventlistenerswiththeaddEvents()method.Insteadofpassingasingleeventnameandfunction,youpassanobjectthatcontainstheeventnamesaspropertiesandthefunctionsasvalues.Forexample,thefollowingcoderegisterseventhandlersforthemouseoverandmouseouteventsonanelement:
functioneventHandler(e){
//dosomethingwiththeeventhere
}
varhandlers={
mouseover:eventHandler,
mouseout:eventHandler
};
$("myDiv").addEvents(handlers);
Whenaneventfires,MooToolspassesitsowneventobject(oftypeDOMEvent)totheevent-handlingfunction.Thisobjecthasahybridsetofpropertiesandmethods:Someareproprietarybutmostarestandards-compliant.ThefollowingtablelistssomeofthepropertiesavailablewithMooTools’Eventobject.
PROPERTY DESCRIPTIONpage.x Thehorizontalpositionofthemouserelativetothebrowserwindowpage.y Theverticalpositionofthemouserelativetothebrowserwindowclient.x Thehorizontalpositionofthemouserelativetotheclientareaclient.y Theverticalpositionofthemouserelativetotheclientareatarget TheextendedeventtargetrelatedTarget Theextendedelementrelatedtotheeventtargettype Thetypeofeventthatcalledtheeventhandler
NOTEVisithttp://mootools.net/core/docs/1.5.1/Types/DOMEventforacompletelistofpropertiesofMooTools’DOMEventobject.
Forexample,thefollowingcoderegistersaclickeventlisteneronanelementwithanidofmyDiv:
functiondivClick(e){
vartarget=e.target.addClass("class-one");
alert("YouclickedatX:"+e.client.x+"Y:"+e.client.y);
}
$("myDiv").addEvent("click",divClick);
Whentheclickeventfires,MooToolspassesitsowneventobjecttodivClick().ThefirstlineofthefunctioncallstheaddClass()method,addingtheclass-oneCSSclasstotheelement.
TheaddClass()methodreturnsanextendedelementobject,lettingyoubothaddtheCSSclassandassignthetargetvariablewiththeextendedeventtarget.Youthenuseanalertboxtodisplaythemousepointer’scoordinatesbyusingtheclient.xandclient.yproperties.
RewritingtheTabStripwithMooToolsNowthatyou’vehadacrashcourseinMooTools,let’srewritethetabstrip!
TRYITOUTRevisitingtheToolbarwithMooToolsOpenyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example6</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="mootools-core-1.5.1-compressed.js"></script>
<script>
functionhandleEvent(e){
vartarget=e.target;
vartype=e.type;
if(type=="mouseover"||type=="mouseout"){
target.toggleClass("tabStrip-tab-hover");
}elseif(type=="click"){
target.addClass("tabStrip-tab-click");
varnum=target.getAttribute("data-tab-number");
showDescription(num);
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("descContainer").set("html",text);
}
$$(".tabStrip>div").addEvents({
mouseover:handleEvent,
mouseout:handleEvent,
click:handleEvent
});
</script>
</body>
</html>
Savethisfileasch17_example6.html,andopenitinyourbrowser(http://beginningjs.com/examples/ch17_example6.htmlisavailable,too).Noticethatthispageworksjustlikealltheotherversions.
Let’sjumprightintothecode,startingwiththehandleEvent()function:
functionhandleEvent(e){
vartarget=e.target;
vartype=e.type;
Everythingisstandards-compliantcodeuntilyougettotheifstatement;that’swhenyouuseMooTools’toggleClass()methodinthecaseofmouseoverandmouseoutevents:
if(type=="mouseover"||type=="mouseout"){
target.toggleClass("tabStrip-tab-hover");
Ifitisoneoftheseevents,youaddthetabStrip-tab-hoverCSSclasstotheeventtarget.Butiftheeventisaclickevent,youneedtodoafewthings.First,youaddthetabStrip-tab-clickCSSclasstotheelement.Then,yougetthevalueofthedata-tab-numberattributebecauseyou’llneedtopassthattotheshowDescription()function:
}elseif(type=="click"){
target.addClass("tabStrip-tab-click");
varnum=target.getAttribute("data-tab-number");
showDescription(num);
}
}
TheshowDescription()functionchangedveryslightly;infact,justonestatementneedsyourattention:
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("descContainer").set("html",text);
}
Youneedtochangethecontentofthedescriptioncontainerelement.Now,youcandothatinavarietyofways,andaswementionedearlier,thenativeinnerHTMLpropertywouldbeideal.However,forthesakeofthisexample,youuseMooTools’set()methodtosetthevirtualhtmlproperty.
Finally,youregisteryourlistenersforthemouseover,mouseout,andclickevents:
$$(".tabStrip>div").addEvents({
mouseover:handleEvent,
mouseout:handleEvent,
click:handleEvent
});
Here,youuseMooTools’$$()methodtoselectthe<div/>elementswithinthetabstrip.ThenyouusetheaddEvents()methodtoregisterthethreeeventlisteners.Asanalternative,youcouldusethetechniquedemonstratedinthePrototypeexample:
$$(".tabStrip>div").forEach(function(item){
item.addEvents({
mouseover:handleEvent,
mouseout:handleEvent,
click:handleEvent
});
});
However,there’snorealneedtodosointhisexample.Butthiswouldbethebestwayifyouneededtoperformotherprocessesoneachelement.Thatway,youiterateovertheelementsonceasopposedtomultipletimes.
AjaxSupportinMooToolsMooToolshasthreeobjectsformakingHTTPrequests,eachtargetingaspecificpurpose:
Request:Usedforgeneralrequests
Request.HTML:UsedspecificallyforreceivingHTML
Request.JSON:SpecificallyusedforreceivingJSON
EachoftheseobjectsissimilartoPrototype’sAjax.Request,inthatyoudirectlycreatethembycallingtheirconstructorfunctionswiththenewoperatorandpassinganobjectthatcontainsvariousoptions:
varrequest=newRequest({
method:"get",
url:"someFile.txt",
onSuccess:requestSuccess
});
ThiscodecreatesaRequestobjectthatmakesaGETrequestforsomeFile.txtandcallstherequestSuccess()functiononasuccessfulrequest.
Youcanpassmanymoreoptionstotheconstructor;thefollowingtablelistssomeofthem.
OPTION DESCRIPTIONasync DetermineswhetherornottheXMLHttpRequestobjectmakestherequestin
asynchronousmode.Thedefaultistrue.data Anobjectcontainingthekey/valuepairstosendwiththerequestmethod TheHTTPmethodusedfortherequest.Thedefaultis"post".onSuccess AcallbackfunctioninvokedwhentherequestcompletessuccessfullyonFailure Acallbackfunctioninvokedwhentherequestcompletes,butresultsinan
errorstatuscodeurl TheURLtosendtherequestto
NOTEVisithttp://mootools.net/core/docs/1.5.1/Request/Requestforacompletelistofoptionsandcallbackfunctions.
Unfortunately,creatingaRequestobjectdoesn’tautomaticallysendtherequest;youmustexplicitlysenditwiththesend()method:
request.send();
Buttosavesometyping,youcanchainthesend()methodtotheRequestconstructor,likethis:
varrequest=newRequest({
method:"get",
url:"someFile.txt",
onSuccess:requestSuccess
}).send();
Youcanalsouseoneofthemanyaliasesforsend().TheirnamesmirrorthoseofthedifferentHTTPmethods,andtheysendtherequestwiththegivenmethod.Forexample,theget()methodsendsaGETrequest,post()sendsPOST,put()isaPUTrequest,andsoon.Usinganaliaseliminatestheneedtospecifythemethodoption.Forexample:
varrequest=newRequest({
url:"someFile.txt",
onSuccess:requestSuccess
});
request.get();//sendstherequestasGET
request.post();//sendsasPOST
Youcansenddatawithyourrequestintwodifferentways.First,youcanmakeitpartoftheRequestobject.ThisisusefulifyouneedtosendthesamedatawitheveryrequestyoumakewithasingleRequestobject.Todothis,youaddadatapropertytotheoptionsobjectyoupasstotheconstructor.Anexampleofthisis:
varrequest=newRequest({
url:"ch14_formvalidator.php",
data:{
username:userValue//assuminguserValueisassignedavalue
},
onSuccess:requestSuccess
});
ThesecondapproachdecouplesthedatafromtheRequestobjectsothatyoucanreusethesameRequestobjectforsendingdifferentdata.Tousethisapproach,youpassthedatatothesend(),orotheralias,methodlikethis:
varrequest=newRequest({
url:"ch14_formvalidator.php",
onSuccess:requestSuccess
}).get({
data:{
username:userValue
}
});
TheonSuccesscallbackfunctionvariesbetweenthedifferenttypesofrequests.ForordinaryRequestobjects,theonSuccesscallbackfunctioniscalledwithtwoarguments—theresponseTextandresponseXML:
functionrequestSuccess(responseText,responseXML){
//dosomethingwitheithersuppliedvalue
}
TheresponseTextistheplaintextualrepresentationoftheserver’sresponse.IftheresponseisavalidXMLdocument,theresponseXMLparameterisaDOMtreecontainingtheparsedXML.
TheonSuccesscallbackisabitmorecomplicatedforRequest.HTMLobjects:
functionrequestHTMLSuccess(responseTree,responseElements,
responseHTML,responseJavaScript){
//dosomethingwiththedata
}
Thefourparametersare:
responseTree:Thenodelistoftheresponse
responseElements:Anarraycontainingtheelementsoftheresponse
responseHTML:Thestringcontentoftheresponse
responseJavaScript:TheJavaScriptoftheresponse
TheonSuccesscallbackforRequest.JSONobjectsismuchsimplerthanRequest.HTML’s:
functionrequestJSONSuccess(responseJSON,responseText){
//dosomethingwiththeprovideddata
}
TheresponseJSONparameterisanobject—theparsedJSONstructure.Soyouwon’tneedtocallJSON.parse().TheresponseTextparameteristheplaintextJSONstructure.Honestly,yourauthorsdon’tknowwhyyouwouldneedtheresponseTextwithRequest.JSON,butit’stherejustincaseyouneedit(wedon’tthinkyouwill).
Let’suseMooTools’Ajaxutilitiestomodifytheformvalidatorfromthepreviouschapteronelasttime!
TRYITOUTRevisitingtheFormValidatorwithMooToolsOpenyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Example7</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="mootools-core-1.5.1-compressed.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varoptions={
url:"ch14_formvalidator.php",
data:{
username:userValue
},
onSuccess:handleResponse
};
newRequest.JSON(options).get();
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varoptions={
url:"ch14_formvalidator.php",
data:{
email:emailValue
},
onSuccess:handleResponse
};
newRequest.JSON(options).get();
}
functionhandleResponse(data,json){
if(data.available){
alert(data.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+data.searchTerm+"isnot
available.");
}
}
$("usernameAvailability").addEvent("click",checkUsername);
$("emailAvailability").addEvent("click",checkEmail);
</script>
</body>
</html>
Savethisfileasch17_example7.html,andsaveitinyourwebserver’srootdirectory.Openandpointyourbrowsertohttp://yourserver/ch17_example7.htmlandtestit.You’llfindthatitbehavesjustasallthepreviousversionsdid.
ThisversionisverysimilartoExample4—thePrototypeversion.Infact,checkUsername()andcheckEmail()areidenticaltoExample4exceptfortherequestcode.Solet’sjustlookatthat,startingwithcheckUsername().
Afteryougetandvalidatetheuserinputfortheusername,youbuildyouroptionsobject:
varoptions={
url:"ch14_formvalidator.php",
data:{
username:userValue
},
onSuccess:handleResponse
};
Yousettheurl,data,andonSuccesspropertiesandpasstheobjecttotheRequest.JSON()constructor:
newRequest.JSON(options).get();
Andtosavesometyping,youchaintheget()calltotheRequest.JSONconstructor.
ThecodeinsidecheckEmail()isunsurprisinglysimilar(atthispoint,whatisaboutthisexample?).First,youbuildyouroptionsobject:
varoptions={
url:"ch14_formvalidator.php",
data:{
email:emailValue
},
onSuccess:handleResponse
};
Thenyousendtherequest:
newRequest.JSON(options).get();
ThehandleResponse()functionalsosawafewchanges.ThankstoMooTools’built-insupportforJSON,thefunctionhasbeensimplified:
functionhandleResponse(data,json){
if(data.available){
alert(data.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+data.searchTerm+"isnot
available.");
}
}
Thedatapassedtothefirstparameter,data,isalreadyparsedintoaJavaScriptobject.Soyousimplyuseittocheckiftheusernameore-mailisavailableanddisplaythecorrectinformationtotheuser.
Finally,youwireuptheevents:
$("usernameAvailability").addEvent("click",checkUsername);
$("emailAvailability").addEvent("click",checkEmail);
Youfindthe<a/>elementsinthedocumentandregistertheirclickeventlistenerswithMooTools’addEvent()method.
MooToolsisapopularframeworkbecauseitoffersyouutilitysimilartojQuerywhilemaintainingaspectsoftraditionalDOMprogramming.MooToolsalsohasananimation/effectscomponent,makingitawell-roundedframework.Thissectioncanhardlydotheframeworkjustice,somakesuretovisittheAPIdocumentationathttp://mootools.net/core/docs/.
SUMMARYThischapterintroducedyouintotheratherlargeworldofJavaScriptframeworksandlibraries.
Youlearnedthattwotypesoflibrariesandframeworksexist:generalandspecific.Youwerealsogivenashortlistofthepopularsolutionsavailabletoday.
YoulearnedwheretoobtainthefilesneededtouseModernizr,Prototype,andMooTools.
YoulearnedhowModernizrhelpsyouwritefeature-specificcode,andhowtoloadexternalresources,likepolyfills,forbrowsersthatdon’tsupportcertainfeatures.
YoulearnedthebasicsofthePrototypeframework—howtoretrieve,create,andmanipulateelements.YoualsolearnedhowtoregistereventlistenersandsendAjaxrequests.
YoulearnedhowtouseMooToolstocreate,select,andmodifyelements,aswellaswireupeventlistenersandmakeAjaxrequests.
EXERCISESYoucanfindsuggestedsolutionsforthesequestionsinAppendixA.
1. ModifytheanswertoChapter14’sQuestion2usingPrototype.AlsoadderrorreportingforwhenanerroroccurswiththeAjaxrequest.
2. Ifyouguessedthatthisquestionwouldbe:“ChangetheanswertoChapter14’sQuestion2usingMooTools,andadderrorreportingforwhenanerroroccurswiththeAjaxrequest”thenyouwon!!Yourprizeis…completingtheexercise.
18CommonMistakes,Debugging,andErrorHandlingWHATYOUWILLLEARNINTHISCHAPTER:
Spottingcommonmistakesthateveryonemakes—evenpros!
Handlingruntimeerrors,orexceptions,withthetry…catchstatement
DebuggingJavaScriptwiththedevelopmenttoolsofvariousbrowsers
WROX.COMCODEDOWNLOADSFORTHISCHAPTER
Youcanfindthewrox.comcodedownloadsforthischapterathttp://www.wiley.com/go/BeginningJavaScript5EontheDownloadCodetab.Youcanalsoviewalloftheexamplesandrelatedfilesathttp://beginningjs.com.
EvenaJavaScriptgurumakesmistakes,eveniftheyarejustannoyingtypos.Inparticular,whencodeexpandstohundredsorthousandsoflines,thechanceofsomethinggoingwrongbecomesmuchgreater.Inproportion,thedifficultyinfindingthesemistakes,orbugs,alsoincreases.Inthischapteryoulookatvarioustechniquesthatwillhelpyouminimizetheproblemsthatarisefromthissituation.
YoustartbytakingalookatthetopsevenJavaScriptcodingmistakes.Afteryouknowwhattheyare,you’llbeabletolookoutforthemwhenwritingcode,hopefully,sothatyouwon’tmakethemsooften!
Thenyoulookathowyoucancopewitherrorswhentheydohappen,sothatyoupreventusersfromseeingyourcodingmistakes.
Finally,youlookatthedebuggingtoolsinMicrosoft’sInternetExplorer(IE11),Firebug(anadd-onforFirefox),Chrome’sWebInspector,andOpera’sDragonfly.Youseehowyoucanusethesetoolstostepthroughyourcodeandcheckthecontentsofvariableswhilethecodeisrunning,aprocessthatenablesyoutohuntfordifficultbugs.YoualsotakeabrieferlookatthedebuggingtoolsavailableforFirefox.
D’OH!ICAN’TBELIEVEIJUSTDIDTHAT:SOMECOMMONMISTAKESSeveralcommonmistakesaremadebyprogrammers.Someoftheseyou’lllearntoavoidasyoubecomemoreexperienced,butothersmayhauntyouforever!
UndefinedVariablesJavaScriptisactuallyveryeasygoingwhenitcomestodefiningyourvariablesbeforeassigningvaluestothem.Forexample,thefollowingwillimplicitlycreatethenewglobalvariableabcandassignittothevalue23:
abc=23;
Althoughstrictlyspeaking,youshoulddefinethevariableexplicitlywiththevarkeywordlikethis:
varabc=23;
Yourchoiceofwhethertousethevarkeywordtodeclareavariablehasaconsequenceonthevariable’sscope;soitisalwaysbesttousethevarkeyword.Ifavariableisusedbeforeithasbeendefined,anerrorwillarise.Forexample,thefollowingcodewillcausetheerrorshowninFigure18.1inIE11ifthevariableabchasnotbeenpreviouslydefined(explicitlyorimplicitly):
Figure18.1
alert(abc);
Inotherbrowsers,you’llneedtolookintheJavaScriptconsole,whichyoucanviewby
pressingCtrl+Shift+Jonyourkeyboard.Youcanalsoviewtheconsolebynavigatingthroughthebrowser’smenu.Youlearnhowtodothislater.
Inaddition,youmustrememberthatfunctiondefinitionsalsohaveparameters,whichifnotdeclaredcorrectlycanleadtothesametypeoferror.
Takealookatthefollowingcode:
functionfoo(parametrOne){
alert(parameterOne);
}
Ifyoucallthisfunction,yougetanerrormessagesimilartotheoneshowninFigure18.2.
Figure18.2
Theerrorhereisactuallyasimpletypointhefunctiondefinition.Thefunction’sparametershouldreadparameterOne,notparametrOne.Whatcanbeconfusingwiththistypeoferroristhatalthoughthebrowsertellsustheerrorisononeline,thesourceoftheerrorisonanotherline.
CaseSensitivityThisisamajorsourceoferrors,particularlybecauseitcanbedifficulttospotattimes.
Forexample,spotthethreecaseerrorsinthefollowingcode:
varmyName="Jeremy";
If(myName=="jeremy"){
alert(myName.toUppercase());
}
Thefirsterroristheifkeyword;thecodeabovehasIfratherthanif.However,JavaScriptwon’ttellusthattheerrorisanincorrectuseofcase,butinsteadthebrowser
willtellusObjectexpectedorthatIfisnotdefined.Althougherrormessagesgiveussomeideaofwhat’sgonewrong,theyoftendosoinanobliqueway.InthiscasethebrowserthinksyouareeithertryingtouseanobjectcalledIforuseanundefinedfunctioncalledIf.
NOTEDifferentbrowsersusedifferentwordingwhendisplayingerrors.Theoverallmeaningisthesame,however,soyoucanidentifywhattheproblemis.
Okay,withthaterrorclearedup,youcometothenexterror,notoneofJavaScriptsyntax,butalogicerror.RememberthatJeremydoesnotequaljeremyinJavaScript,somyName=="jeremy"isfalse,eventhoughit’squitelikelythatyoudidn’tcarewhetherthewordisJeremyorjeremy.ThistypeoferrorwillresultinnoerrormessageatallbecauseitisvalidJavaScript;youronlyclueisthatyourcodewillnotexecuteasyou’dplanned.
ThethirdfaultiswiththetoUpperCase()methodoftheStringobject.ThepreviouscodeusestoUppercase,withtheCinlowercase.IEgivesusthemessageObjectdoesn'tsupportthispropertyormethodandFirefoxreportsthatmyName.toUppercaseisnotafunction.OnfirstglanceitwouldbeeasytomisssuchasmallmistakeandstartcheckingyourJavaScriptreferenceguideforthatmethod.Youmightwonderwhyit’sthere,butyourcodeisnotworking.Again,youalwaysneedtobeawareofcase,somethingthatevenexpertsgetwrongfromtimetotime.
IncorrectNumberofClosingBracesInthefollowingcode,youdefineafunctionandthencallit.However,there’sadeliberatemistake.Seeifyoucanspotwhereitis:
functionmyFunction()
{
varx=1;
vary=2;
if(x<=y)
{
if(x==y)
{
alert("xequalsy");
}
}
myFunction();
Thisiswhyformattingyourcodeisimportant—you’llhaveamucheasiertimespottingerrorssuchasthis:
functionmyFunction(){
varx=1;
vary=2;
if(x<=y){
if(x==y){
alert("xequalsy");
}
}
myFunction();
Nowyoucanseethattheendingcurlybraceofthefunctionismissing.Whenyouhavealotofif,for,ordowhilestatements,it’seasytohavetoomanyortoofewclosingbraces.Thistypeofproblemismucheasiertospotwithformattedcode.
IncorrectNumberofClosingParenthesesSimilarly,nothavingthecorrectnumberofclosingparenthesescanbeproblematic.Takealookatthefollowingcode:
if(myVariable+12)/myOtherVariable<myString.length)
Spotthemistake?Theproblemisthemissingparenthesisatthebeginningofthecondition.YouwantmyVariable+12tobecalculatedbeforethedivisionbymyOtherVariableiscalculated,soquiterightlyyouknowyouneedtoputitinparentheses:
(myVariable+12)/myOtherVariable
However,theifstatement’sconditionmustalsobeinparentheses.Notonlyistheinitialparenthesismissing,butthereisonemoreclosingparenthesisthanopeningparentheses.Likecurlybraces,eachopeningparenthesismusthaveaclosingparenthesis.Thefollowingcodeiscorrect:
if((myVariable+12)/myOtherVariable<myString.length)
It’sveryeasytomissaparenthesisorhaveonetoomanywhenyouhavemanyopeningandclosingparentheses.
UsingEquals(=)RatherthanEquality(==)Theequalityoperatorisacommonlyconfusedoperator.Considerthefollowingcode:
varmyNumber=99;
if(myNumber=101){
alert("myNumberis101");
}else{
alert("myNumberis"+myNumber);
}
Atfirstglance,you’dexpectthatthecodeinsidetheelsestatementwouldexecute,tellingusthatthenumberinmyNumberis99.Itwon’t.Thiscodemakestheclassicmistakeofusingtheassignmentoperator(=)insteadoftheequalityoperator(==).Hence,insteadofcomparingmyNumberwith101,thiscodesetsmyNumbertoequal101.
WhatmakesthingseventrickieristhatJavaScriptdoesnotreportthisasanerror;it’svalidJavaScript!Theonlyindicationthatsomethingisn’tcorrectisthatyourcodedoesn’twork.Assigningavariableavalueinanifstatementmaylooklikeanerror,butit’sperfectlylegal.
Whenembeddedinalargechunkofcode,amistakelikethisiseasilyoverlooked.Justrememberit’sworthcheckingforthiserrorthenexttimeyourprogramdoesn’tdowhatyouexpect.Debuggingyourcodecanhelpeasilyspotthistypeoferror.Youlearnhowtodebugyourcodelaterinthischapter.
UsingaMethodasaPropertyandViceVersaAnothercommonerroriswhereeitheryouforgettoputparenthesesafteramethodwithnoparameters,oryouuseapropertyanddoputparenthesesafterit.
Whencallingamethod,youmustalwayshaveparenthesesfollowingitsname;otherwise,JavaScriptthinksthatitmustbeapointertothemethodoraproperty.Forexample,examinethefollowingcode:
varnowDate=newDate();
alert(nowDate.getMonth);
ThefirstlinecreatesaDateobject,andthesecondlineusesitsgetMonthproperty.ButyouknowthatDateobjectsdonothaveagetMonthproperty;it’ssupposedtobeamethod.Now,thisisvalidJavaScriptbecauseyoucanpassafunctionpointer—whichiswhatnowDate.getMonthis—toanotherfunction,andassuch,thebrowserwillnothaveanyissuesexecutingthiscode.Andinmanycases,youwanttodothat(likewhenregisteringeventlisteners).ButchancesareverygoodthatweintendedtocallgetMonth().Therefore,thefollowingisthecorrectedcode:
varnowDate=newDate();
alert(nowDate.getMonth());
NOTEToperhapsconfusetheissue:technically,JavaScriptdoesn’thavemethods.Whatwethinkofasmethodsareactuallyfunctionsassignedtoanobject’sproperties.Butit’sgenerallyacceptedtousethetermmethodtodescribesuchproperties.
Similarly,anothercommonmistakeistotypeparenthesesafteraproperty,makingJavaScriptthinkthatyouaretryingtouseamethodofthatobject:
varmyString="Hello,World!";
alert(myString.length());
Thesecondlineusesthelengthpropertyasamethod,andJavaScriptwillattempttotreatitasone.Whenthiscodeexecutes,youwillseeanerrorbecauselengthcannotbecalledasamethod.Thiscodeshouldhavebeenwrittenlikethis:
varmyString=newString("Hello");
alert(myString.length);
MissingPlusSignsDuringConcatenationOrdinarily,stringconcatenationisastraightforwardprocess,butitcanbecomeconfusingwhenworkingwithmanyvariablesandvalues.Forexample,there’sadeliberate
concatenationmistakeinthefollowingcode.Spotit:
varmyName="Jeremy";
varmyString="Hello";
varmyOtherString="World";
myString=myName+"said"+myString+""myOtherString;
alert(myString);
Thereshouldbea+operatorbetween""andmyOtherStringinthefinallineofcode.
Althougheasytospotinjustafewlines,thiskindofmistakecanbemoredifficulttospotinlargechunksofcode.Also,theerrormessagethistypeofmistakecausescanbemisleading.Loadthiscodeintoabrowserandyouyou’llbetoldError:Expected';'byIE,Missing;beforestatementbyFirefox,andSyntaxError:UnexpectedidentifierinChrome.It’ssurprisinghowoftenthiserrorcropsup.
Thesemostcommonmistakesareerrorscausedbytheprogrammer.Othertypesoferrors,calledruntimeerrors,occurwhenyourcodeexecutesinthebrowser,andtheyaren’tnecessarilycausedbyatypooramissingcurlybraceorparenthesis.Runtimeerrorscanstillbeplannedfor,asyouseeinthenextsection.
ERRORHANDLINGWhenwritingyourprograms,youwanttobeinformedofeveryerror.However,thelastthingsyouwanttheusertoseeareerrormessageswhenyoufinallydeploythecodetoawebserverforthewholeworldtoaccess.Ofcourse,writingbug-freecodewouldbeagoodstart,butkeepthefollowingpointsinmind:
Conditionsbeyondyourcontrolcanleadtoerrors.AgoodexampleofthisiswhenyouarerelyingonAjaxtotalktothewebserver,andsomethinghappenstotheuser’snetworkconnection.
Murphy’sLawstatesthatanythingthatcangowrongwillgowrong!
PreventingErrorsThebestwaytohandleerrorsistostopthemfromoccurringinthefirstplace.Thatseemslikestatingtheobvious,butyoushoulddoanumberofthingsifyouwanterror-freepages:
Thoroughlycheckpagesinasmanybrowsersaspossible.Thisiseasiersaidthandoneonsomeoperatingsystems.Thealternativeisforyoutodecidewhichbrowsersyouwanttosupportforyourwebpage,andthenverifythatyourcodeworksinthem.
Validateyourdata.Ifuserscanenterduddatathatwillcauseyourprogramtofail,thentheywill.Makesurethatatextboxhasdataenteredintoitifyourcodefailswhenthetextboxisempty.Ifyouneedawholenumber,makesurethattheuserenteredone.Isthedatetheuserjustenteredvalid?Isthee-mailaddressmindyourownbusinesstheuserjustenteredlikelytobevalid?No,[email protected].
Okay,solet’ssayyoucarefullycheckedyourpagesandthereisnotasyntaxorlogicerrorinsight.Youaddeddatavalidationthatconfirmsthateverythingtheuserentersisinavalidformat.Thingscanstillgowrong,andproblemsmayarisethatyoucandonothingabout.Here’sareal-worldexampleofsomethingthatcanstillgowrong.
OneprofessionalcreatedanonlinemessageboardthatreliesonasmallJavaapplettoenablethetransferofdatatoandfromtheserverwithoutreloadingthepage(thiswasbeforeAjax).Hecheckedthecodeandeverythingwasfine,anditcontinuedtoworkfineafterlaunchingtheboard,exceptthatinaboutfivepercentofcasestheJavaappletinitializedbutthencausedanerrorduetotheuserbeingbehindaparticulartypeoffirewall(afirewallisameansofstoppingintrudersfromgettingintoalocalcomputernetwork,andmanyblockJavaappletsbecauseofJava’ssecurityissues).It’simpossibletodeterminewhetherauserisbehindacertaintypeoffirewall,sothereisnothingthatcanbedoneinthatsortofexceptionalcircumstance.Oristhere?
Infact,JavaScriptincludessomethingcalledthetry…catchstatement.Thisenablesyoutotrytorunyourcode;ifitfails,theerroriscaughtbythecatchclauseandcanbedealtwithasyouwish.Forthemessageboard,thisprofessionalusedatry…catchclausetocatchtheJavaapplet’sfailureandredirectedtheusertoamorebasicpagethatstill
displayedmessages,butwithoutusingtheapplet.
Thetry…catchStatementsThetry…catchstatementsworkasapair;youcan’thaveonewithouttheother.Youusethetrystatementtodefineablockofcodethatyouwanttotrytoexecute,andusethecatchstatementtodefineablockofcodethatexecuteswhenanexceptionoccursinthetrystatement.Thetermexceptioniskeyhere;itmeansacircumstancethatisextraordinaryandunpredictable.Comparethatwithanerror,whichissomethinginthecodethathasbeenwrittenincorrectly.Ifnoexceptionoccurs,thecodeinsidethecatchstatementneverexecutes.Thecatchstatementalsoenablesyoutogetthecontentsoftheexceptionmessagethatwouldhavebeenshowntotheuserhadyounotcaughtitfirst.
Let’screateasimpleexampleofatry…catchclause:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Example1</title>
</head>
<body>
<script>
try{
alert("Thisiscodeinsidethetryclause");
alert("NoErrorssocatchcodewillnotexecute");
}catch(exception){
alert("Theerroris"+exception.message);
}
</script>
</body>
</html>
Savethisasch18_example1a.htmlandopenitinyourbrowser.
Thiscodedefinesthetrystatement,andaswithallotherblocksofcode,youmarkoutthetryblockbyenclosingitincurlybraces.
Immediatelyfollowingthetryblockisthecatchstatement,andnoticethatitincludesexceptioninsideasetofparentheses.Thisexceptionissimplyavariablename,anditstoresanobjectthatcontainsinformationaboutanyexceptionthatmayoccurinsidethetrycodeblock.We’llcallthisobjecttheexceptionobject.Althoughthewordexceptionisusedhere,youcanuseanyvalidvariablename.Forexample,catch(ex)wouldbefine.
Theexceptionobjectcontainsseveralpropertiesthatprovideinformationabouttheexceptionthatoccurred,butthemostcommonlyusedpropertiesarenameandmessage.Theaptlynamednamepropertycontainsthenameoftheerrortype,andthemessagepropertycontainstheerrormessagetheuserwouldnormallysee.
Backtothecodeathand,withinthecatchblockisthecodethatexecuteswhenanexceptionoccurs.Inthiscase,thecodewithinthetryblockwillnotthrowanexception,andsothecodeinsidethecatchblockwillneverexecute.
Butlet’sinsertadeliberateerror.Changethehighlightedlineinthefollowingcode:
try{
alert("Thisiscodeinsidethetryclause");
ablert("NoErrorssocatchcodewillnotexecute");
}catch(exception){
alert("Theerroris"+exception.message);
}
Savethedocumentasch18_example1b.htmlandopenitinyourbrowser.
Thebrowserwillstartexecutingthiscodeasnormal.Itwillexecutethefirstcalltoalert()insidethetryblockanddisplaythemessagetotheuser.However,thecalltoablert()willcauseanexception.Thebrowserwillstopexecutingthetryblock,andinsteadwillstartexecutingthecatchblock.You’llseeamessagesimilarto“Theerrorisablertisnotdefined.”
Let’schangethiscodeonceagaintointroduceadifferenterror.Asbefore,modifythehighlightedlineinthefollowingcode:
try{
alert("Thisiscodeinsidethetryclause");
alert('Thiscodewon'twork');
}catch(exception){
alert("Theerroris"+exception.message);
}
Savethisasch18_example1c.htmlandopenitinyourbrowser.Youwillnotseeanyalertboxbecausethiscodecontainsasyntaxerror;thefunctionsandmethodsarevalid,butyouhaveaninvalidcharacter.Thesinglequoteinthewordwon'thasendedthestringvaluebeingpassedtoalert().
Beforeexecutinganycode,theJavaScriptenginegoesthroughallthecodeandchecksforsyntaxerrors,orcodethatbreachesJavaScript’srules.Iftheenginefindsasyntaxerror,thebrowserdealswithitasusual;yourtryclauseneverrunsandthereforecannothandlesyntaxerrors.
ThrowingErrorsYoucanusethethrowstatementtocreateyourownruntimeexceptions.Whycreateastatementtogenerateanexception,whenabitofbadcodingwilldothesame?
Throwingerrorscanbeveryusefulforindicatingproblemssuchasinvaliduserinput.Ratherthanusinglotsofif…elsestatements,youcancheckthevalidityofuserinput,thenusethrowtostopcodeexecutioninitstracksandcausetheerror-catchingcodeinthecatchblockofcodetotakeover.Inthecatchclause,youcandeterminewhethertheerrorisbasedonuserinput,inwhichcaseyoucannotifytheuserwhatwentwrongandhowtocorrectit.Alternatively,ifit’sanunexpectederror,youcanhandleitmoregracefullythanwithlotsofJavaScripterrors.
Youcanthrowanything;fromasimplestringornumbertoanobject.Inmostcases,however,you’llthrowanobject.Tousethrow,typethrowandincludetheobjectafterit.Forexample,ifyouarevalidatingasetofformfields,yourexceptionobjectcouldcontain
notonlythemessage,buttheidoftheelementthathasinvaliddata.Anexamplecouldlooklikethis:
throw{
message:"Pleasetypeavalidemailaddress",
elementId:"txtEmail"
};
Theobjectsyouthrowshouldincludeatleastamessageproperty;mosterror-handlingcodewillbelookingforit.
TRYITOUTtry…catchandThrowingErrorsInthisexampleyoumodifych16_example2.htmltousethetry…catchandthrowstatementstovalidatethee-mailandusernamefields.Feelfreetousech16_example2.htmlasabasisforthisnewfile.Foryourconvenience,thefollowingcodelistinghighlightsthekeychanges:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Example2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="jquery-2.1.1.min.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("#username").val();
try{
if(!userValue){
throw{
message:"Pleaseenterausernametocheck!"
};
}
varparms={
username:userValue
};
$.getJSON("ch14_formvalidator.php",
parms).done(handleResponse);
}catch(ex){
alert(ex.message);
}
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("#email").val();
try{
if(!emailValue){
throw{
message:"Pleaseenteranemailaddressto
check!"
};
}
varparms={
email:emailValue
};
$.getJSON("ch14_formvalidator.php",
parms).done(handleResponse);
}catch(ex){
alert(ex.message);
}
}
functionhandleResponse(response){
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
$("#usernameAvailability").on("click",checkUsername);
$("#emailAvailability").on("click",checkEmail);
</script>
</body>
</html>
RememberthatthisexamplereliesuponAjaxinordertowork;so,besuretosavethispageasch18_example2.htmlinyourwebserver’sroot.Incaseyouhaven’tsetupawebserveryet,seeChapter14formoreinformation.
Youknowhowthisexampleworks,sowe’llfocusonlyonthehighlightedcode.
Let’sfirstlookatthecheckUsername()function.Ithasbeenrewrittentousethetry…catchandthrowstatementsforvalidatingtheusername<input/>element,andthemajorityofthisfunction’scoderesideswithinthetryblock:
try{
if(!userValue){
throw{
message:"Pleaseenterausernametocheck!"
};
}
varparms={
username:userValue
};
$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);
}
BeforeyoumaketheAjaxrequest,youfirstensuretheuserprovidedavaluetotheusernamefield.IfuserValueisblank,youthrowanewobjectdetailingthecauseoftheexceptionwithitsmessageproperty.ThiscausestheJavaScriptenginetostopexecutingcodeinthistryblockandstartsexecutingthecatchblock:
catch(ex){
alert(ex.message);
}
Here,yousimplyalerttheexception’smessageproperty,displayingthe“Pleaseenterausernametocheck!”messagetotheuser.
Naturally,thechangesmadetothecheckEmail()functionarealmostidenticaltocheckUsername():
try{
if(!emailValue){
throw{
message:"Pleaseenteranemailaddresstocheck!"
};
}
varparms={
email:emailValue
};
$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);
}catch(ex){
alert(ex.message);
}
Onceagain,themajorityofthefunctioncoderesideswithinatrycodeblock.Ifthee-mailfieldvalidationfails,youthrowanobjectcontainingtheexceptionmessageanddisplaythatmessageinanalertbox—theresultofexecutingthecodeinthecatchblock.
Nestedtry…catchStatementsSofaryou’vebeenusingjustonetry…catchstatement,butit’spossibletoincludeatry…catchstatementinsideanothertrystatement.Indeed,youcangofurtherandhaveatry…catchinsidethetrystatementofthisinnertry…catch,orevenanotherinsidethat,thelimitbeingwhatit’sactuallysensibletodo.
Sowhywouldyouusenestedtry…catchstatements?Well,youcandealwithcertainerrorsinsidetheinnertry…catchstatement.If,however,you’redealingwithamoreseriouserror,theinnercatchclausecouldpassthaterrortotheoutercatchclausebythrowingtheerrortoit.
Here’sanexample:
try{
try{
ablurt("Thiscodehasanerror");
}catch(exception){
varname=exception.name;
if(name=="TypeError"||name=="ReferenceError"){
alert("Innertry…catchcandealwiththiserror");
}else{
throwexception;
}
}
}catch(exception){
alert("Theinnertry…catchcouldnothandletheexception.");
}
Inthiscodeyouhavetwotry…catchpairs,onenestedinsidetheother.
Theinnertrystatementcontainsalineofcodethatcontainsanerror.Thecatchstatementoftheinnertry…catchchecksthevalueoftheerror’sname.Iftheexception’snameiseitherTypeErrororReferenceError,theinnertry…catchdealswithitbywayofanalertbox(seeAppendixBforafulllistoferrortypesandtheirdescriptions).Unfortunately,andunsurprisingly,thetypeoferrorthrownbythebrowserdependsonthebrowseritself.Intheprecedingexample,IEreportstheerrorasaTypeErrorwhereastheotherbrowsersreportitasaReferenceError.
Iftheerrorcaughtbytheinnercatchstatementisanyothertypeoferror,itisthrownupintheairagainforthecatchstatementoftheoutertry…catchtodealwith.
finallyClausesThetry…catchstatementhasafinallyclausethatdefinesablockofcodethatalwaysexecutes—evenifanexceptionwasn’tthrown.Thefinallyclausecan’tappearonitsown;itmustbeafteratryblock,whichthefollowingcodedemonstrates:
try{
ablurt("Anexceptionwilloccur");
}catch(exception){
alert("Exceptionoccurred");
}finally{
alert("Thislinealwaysexecutes");
}
Thefinallypartisagoodplacetoputanycleanupcodethatneedstoexecuteregardlessofanyexceptionsthatpreviouslyoccurred.
You’veseenthetopmistakesmadebydevelopers,andyou’vealsoseenhowtohandle
errorsinyourcode.Unfortunately,errorswillstilloccurinyourcode,solet’stakealookatonewaytomakeremedyingthemeasierbyusingadebugger.
DEBUGGINGJavaScriptistraditionallylookeduponasadifficultlanguagetowriteanddebugduetothelackofdecentdevelopmenttools.This,however,isnolongerthecasethankstothetoolsmadeavailablethroughthebrowser:thedebuggingtoolsavailableforInternetExplorer,Firefox,Chrome,andOpera.Withthesetools,youcanhalttheexecutionofyourscriptwithbreakpointsandthenstepthroughcodelinebylinetoseeexactlywhatishappening.
Youcanalsofindoutwhatdataisbeingheldinvariablesandexecutestatementsonthefly.Withoutdebuggers,thebestyoucandoisusethealert()methodinyourcodetoshowthestateofvariablesatvariouspoints.
Debuggingisgenerallyuniversalacrossallbrowsers,andevenlanguages.Somedebuggingtoolsmayoffermorefeaturesthanothers,butforthemostpart,thefollowingconceptsapplytoanydebugger:
Breakpointstellthedebuggeritshouldbreak,orpausecodeexecution,atacertainpoint.YoucansetabreakpointanywhereinyourJavaScriptcode,andthedebuggerwillhaltcodeexecutionwhenitreachesthebreakpoint.
Watchesenableyoutospecifyvariablesthatyouwanttoinspectwhenyourcodepausesatabreakpoint.
Thecallstackisarecordofwhatfunctionsandmethodshavebeenexecutedtothebreakpoint.
TheconsoleenablesyoutoexecuteJavaScriptcommandsinthecontextofthepageandwithinthescopeofthebreakpoint.Inaddition,itcatalogsallJavaScripterrorsfoundinthepage.
Steppingisthemostcommonprocedureindebugging.Itenablesyoutoexecuteonelineofcodeatatime.Youcanstepthroughcodeinthreeways:
StepIntoexecutesthenextlineofcode.Ifthatlineisafunctioncall,thedebuggerexecutesthefunctionandhaltsatthefirstlineofthefunction.
StepOver,likeStepInto,executesthenextlineofcode.Ifthatlineisafunction,StepOverexecutestheentirefunctionandhaltsatthefirstlineoutsidethefunction.
StepOutreturnstothecallingfunctionwhenyouareinsideacalledfunction.StepOutresumestheexecutionofcodeuntilthefunctionreturns.Itthenbreaksatthereturnpointofthefunction.
Beforedelvingintothevariousdebuggers,let’screateapageyoucandebug:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Example3</title>
</head>
<body>
<script>
functionwriteTimesTable(timesTable){
varwriteString;
for(varcounter=1;counter<12;counter++){
writeString=counter+"*"+timesTable+"=";
writeString=writeString+(timesTable*counter);
writeString=writeString+"<br/>";
document.write(writeString);
}
}
writeTimesTable(2);
</script>
</body>
</html>
Savethisasch18_example3.html.Youwillneedtoopenthisfileineachbrowserinordertodebugit.
ThenextsectionwalksyouthroughthefeaturesandfunctionalityofChrome’sJavaScriptdebugger.Becauseoftheuniversalnatureofdebugginganddebuggers,thesectionsforInternetExplorer,Firefox,andSafariwillmerelyfamiliarizeyouwiththeUIforeachbrowser’sdebuggerandpointoutanydifferences.
DebugginginChrome(andOpera)ChromeandOperausethesamerenderingandJavaScriptengine,andassuch,theyalsosharethesamedevelopmenttools.Forthesakeofsimplicity,thissectionfocusesonChrome,butkeepinmindthatOperaisexactlythesame.
YoucanaccessChrome’sdevelopertoolsacoupleofways.Youcanclickthe“hamburgermenu”inthetopright-handcornerofthewindowandselectMoreTools➢Developerstools.YoucanalsoopenthembypressingtheF12key.
NOTEYou’llfindthatF12opensthedevelopertoolsinalmosteverybrowser.
Bydefault,theDevelopertoolsopensasapanelinChrome(seeFigure18.3).
Figure18.3
YoucanpopitouttoitsownwindowbyclickingtheiconnexttotheClosebutton.
Opench18_example3.html(eitherfromyourcomputerortheweb)inChromeandopenChrome’sdevelopertools.
TheJavaScriptdebuggeriscontainedintheSourcestab,anditismadeupofthreepanels(Figure18.4).Theleftpanelcontainsthelistofsourcestochoosefrom.You’llonlyseeonesourceavailableinthischapterbecausethereisonlyonefileloadedbythebrowser.ButifyouloadapagewithmultipleexternalJavaScriptfiles,you’llfindeachofthemlistedintheleftpanel.
Figure18.4
Thecenterpanelcontainsthesourcecodeoftheselectedfile,andit’sherethatyou’llsetbreakpointsandstepthroughcode.Thecodedisplayedinthispanelisread-only;ifyouwanttochangeit,youhavetoeditthefileinyourtexteditorandreloadthepage.
Therightpanelcontainsseveraldifferentsubpanels.Inthischapter,wefocusonBreakpoints,ScopeVariables,WatchExpressions,andCallStack:
Breakpoints:Listsallbreakpointsthatyou’vecreatedforthecodeinthecurrentpage
ScopeVariables:Liststhevariablesandtheirvaluesinscopeofthebreakpoint
WatchExpressions:Liststhe“watches”thatyouspecify.Thesearetypicallyvariablesand/orexpressionsthatyouwanttoinspectatabreakpoint.
CallStack:Displaysthecallstack
SettingBreakpointsAsmentionedearlier,breakpointstellthedebuggertopausecodeexecutionataspecificpointinyourcode.Thisisusefulwhenyouwanttoinspectyourcodewhileitexecutes.
Creatingbreakpointsisstraightforward.Simplyleft-clickthelinenumber,andChromehighlightsthelinenumberwithabluetagicon.ThishighlightdenotesabreakpointinChrome.
Youcanalsohard-codeabreakpointbyusingthedebuggerkeyworddirectlyinyourcode(we’llusethisabitlater).
Setabreakpointonline13:
writeString=writeString+(timesTable*counter);
Reloadthepage,andnoticeChromepausedcodeexecutionatthenewlycreatedbreakpoint.Chromehighlightsthecurrentlineofcodeinblue.Thislinehasn’tbeenexecutedyet.
LookattheBreakpointsintherightpanel;itshowsyouthelistofbreakpoints(onlyoneinthiscase).Eachentryinthelistconsistsofacheckboxtoenable/disablethebreakpoint,thefilenameandlinenumberofthesourcefile,andthesourcetextofthebreakpoint.
NowlookattheScopeVariables.
ScopeVariablesandWatchesTheScopeVariablespanedisplaysvariablesandtheirvaluescurrentlyinscopeatthecurrentline.Figure18.5showsthecontentsoftheScopeVariablespaneatthisbreakpoint.
Figure18.5
Noticethatthecounter,timesTable,andwriteStringvariablesarevisible(asisthis).
NowlookattheWatchExpressionspane.Therearecurrentlynowatchexpressions,butyoucanaddthembysimplyclickingtheaddicon(theplussign).Typethevariablenameorexpressionyouwanttowatch,andpresstheEnterkey.
Goaheadandcreateawatchexpressionforcounter==1.You’llseeyourexpressionfollowedbyacolonandthevalueoftheexpression.Atthispointintime,youshouldseethefollowingasshowninFigure18.6:
Figure18.6
counter==1:true
Ifthewatchisinscope,theexpression’svalueisdisplayed.Ifthevariableisoutofscope,
you’llsee“notavailable.”
Althoughthisinformationishelpfulwhenyouwanttoseewhatexactlyisgoingoninyourcode,it’snotveryhelpfulifyoucan’tcontrolcodeexecution.It’simpracticaltosetabreakpointandreloadthepagemultipletimesjusttoadvancetothenextline,soweuseaprocesscalledstepping.
SteppingthroughCodeCodesteppingiscontrolledbyfourbuttonsintheupper-rightofthedevelopertools(Figure18.7).
Continue(shortcutkeyisF8):Itsfunctionistocontinuecodeexecutionuntileitherthenextbreakpointortheendofallcodeisreached.
StepOver(F10):Thisexecutesthecurrentlineofcodeandmovestothenextstatement.However,ifthestatementisafunction,itexecutesthefunctionandstepstothenextlineafterthefunctioncall.
StepInto(shortcutkeyisF11):Executesthecurrentlineofcodeandmovestothenextstatement.Ifthecurrentlineisafunction,itstepstothefirstlineofthefunction.
StepOut(Shift-F11):Returnstothecallingfunction.
Figure18.7
Let’sdosomestepping;followthesesteps:
1. StepIntothecodebyclickingtheiconorpressingF11.Thedebuggerexecutesthecurrentlyhighlightedlineofcodeandmovestothenextline.
2. LookatthevalueofwriteStringintheScopeVariablespane;itis"1*2=2".Asyoucansee,thevaluesdisplayedintheWatchtabareupdatedinrealtime.
3. OnenicefeatureofChrome’sdevelopertoolsisthepageupdates,ifnecessary,asyoustepthroughcode.ClickStepIntotwomoretimestoseethisinaction.Figure18.8showsthepageupdatedwhilesteppingthroughcode.
Figure18.8
Youmayfindthatthefunctionyousteppedintoisnotthesourceofthebug,inwhichcaseyouwanttoexecutetheremaininglinesofcodeinthefunctionsothatyoucancontinuesteppingafterthefunction.DosobyclickingtheStepOuticontostepoutofthecode.However,ifyou’reinaloopandthebreakpointissetinsidetheloop,youwillnotstepoutofthefunctionuntilyouiteratethroughtheloop.
Theremayalsobetimeswhenyouhavesomebuggycodethatcallsanumberoffunctions.Ifyouknowthatsomeofthefunctionsarebug-free,youmaywanttojustexecutethosefunctionsinsteadofsteppingintothem.UseStepOverinthesesituationstoexecutethecodewithinafunctionbutwithoutgoingthroughitlinebyline.
Alteryourtimes-tablecodeinch18_example3.htmlasfollowssoyoucanuseitforthethreekindsofstepping:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Example4</title>
</head>
<body>
<script>
functionwriteTimesTable(timesTable){
varwriteString;
for(varcounter=1;counter<12;counter++){
writeString=counter+"*"+timesTable+"=";
writeString=writeString+(timesTable*counter);
writeString=writeString+"<br/>";
document.write(writeString);
}
}
for(vartimesTable=1;timesTable<=12;timesTable++){
document.write("<p>");
writeTimesTable(timesTable);
document.write("</p>");
}
</script>
</body>
</html>
Savethisasch18_example4.htmlandopenitinyourbrowser.Thefollowinginstructionswalkyouthroughtheprocessofsteppingthroughcode:
1. Setabreakpointinline19,theforloopinthebodyofthepage,andreloadthepage.
2. ClicktheStepIntoiconandcodeexecutionmovestothenextstatement.Nowthefirststatementinsidetheforloop,document.write("<p>"),isupforexecution.
3. WhenyouclicktheStepIntoiconagain,ittakesyoutothenextline(thefirstcallingofthewriteTimesTable()function).
4. Youwanttoseewhat’shappeninginsidethatfunction,soclickStepIntoagaintostepintothefunction.YourscreenshouldlooksimilartoFigure18.9.
5. ClicktheStepIntoiconafewtimestogetthegistoftheflowofexecutionofthefunction.Infact,steppingthroughcodelinebylinecangetalittletedious.Solet’simagineyou’rehappywiththisfunctionandwanttoruntherestofit.
6. UseStepOuttoruntherestofthefunction’scode.You’rebacktotheoriginalforloop,andthedebuggerispausedonline22,asyoucanseefromFigure18.10.
7. ClicktheStepIntoicontoexecutedocument.write()(itwon’tbevisiblebecauseit’saclosingtag).
8. ClickStepIntofourmoretimes.Executioncontinuesthroughtheconditionandincrementspartsoftheforloop,endingbackatthelinethatcallswriteTimesTable().
9. You’vealreadyseenthiscodeinaction,soyouwanttostepoverthisfunction.Well,noprizesforguessingthatStepOveriswhatyouneedtodo.ClicktheStepOvericon(orpresstheF10key)andthefunctionexecutes,butwithoutsteppingthroughitstatementbystatement.Youshouldfindyourselfbackatthedocument.write("</p>")line.
Figure18.9
Figure18.10
Ifyou’vefinisheddebugging,youcanruntherestofthecodewithoutsteppingthrougheachlinebyclickingtheContinueicon(orpressingF8)onthetoolbar.Youshouldseeapageoftimestablesfrom1*1=1to11*12=132inthebrowser.
TheConsoleWhileyou’resteppingthroughcodeandcheckingitsflowofexecution,itwouldbereally
usefultoevaluateconditionsandeventochangethingsonthefly.Youcandothesethingsusingtheconsole.Followthesesteps:
1. Removethepreviouslysetbreakpointbyclickingitandsetanewbreakpointatline15:
document.write(writeString);
2. Let’sseehowyoucanfindoutthevaluecurrentlycontainedinthevariablewriteString.Reloadthepage.Whenthedebuggerstopsatthebreakpoint,clicktheConsoletabandtypethenameofthevariableyouwanttoexamine,inthiscasewriteString.PresstheEnterkey.Thiscausesthevaluecontainedinthevariabletobeprintedbelowyourcommandinthecommandwindow,asshowninFigure18.11.
3. Ifyouwanttochangeavariable,youcanwritealineofJavaScriptintothecommandwindowandpressEnter.Tryitwiththefollowingcode:
writeString="ChangedontheFly<br/>";
4. ClicktheSourcestab,removethebreakpoint,andthenclicktheContinueicon.Youseetheresultsofyouractions:Wherethe1*1timestableresultshouldbe,thetextyouchangedontheflyhasbeeninserted.
Figure18.11
NOTEThisalterationdoesnotchangeyouractualHTMLsourcefile.
Theconsolecanalsoevaluateconditions.Setabreakpointonline20andreloadthepage.Leaveexecutionstoppedatthebreakpoint,andStepIntotheforloop’scondition.
GototheConsole,typethefollowing,andpressEnter:
timesTable<=12
Becausethisisthefirsttimetheloophasbeenrun,asshowninFigure18.12,timesTableisequalto1sotheconditiontimesTable<=12evaluatestotrue.
Figure18.12
YoucanalsousetheconsoletoaccesspropertiesoftheBOMandDOM.Forexample,ifyoutypelocation.hrefintotheconsoleandpressEnter,itwilltellyouthewebpage’sURL.
NOTEYoucanevaluateanyJavaScriptintheconsole,anditexecuteswithinthescopeofthepageand/orbreakpoint.Thismakestheconsoleanextremelypowerfultool.
CallStackWindowWhenyouaresingle-steppingthroughthecode,thecallstackwindowkeepsarunninglistofwhichfunctionshavebeencalledtogettothecurrentpointofexecutioninthecode.
Let’screateanexamplewebpagetodemonstratethecallstack.Openyourtexteditorandtypethefollowing:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Example5</title>
</head>
<body>
<inputtype="button"value="Button"name="button1"id="button1"/>
<script>
functionfirstCall(){
secondCall();
}
functionsecondCall(){
thirdCall();
}
functionthirdCall(){
//
}
functionbuttonClick(){
debugger;
firstCall();
}
document.getElementById("button1")
.addEventListener("click",buttonClick);
</script>
</body>
</html>
Savethisfileasch18_example5.htmlandopenitinChrome.You’llseeapagewithasimplebutton.Withthedevelopmenttoolsopen,clickthebuttonandexaminetheCallStackpane.YoushouldseesomethinglikeFigure18.13.
Figure18.13
Chromeaddsthefunctiontothetopofthecallstackforeveryfunctioncall.Itdisplaysthenameofthefunction,thefilethefunctionresidesin,andthelinenumberofthecurrentlyexecutingstatementwithinthefunction.YoucanalreadyseethatthefirstfunctioncalledwasbuttonClick(),itisinsidech18_example5.html,andtheexecutionisatline24.
NowStepIntotwice,andyou’llbetakeninsidethefirstCall()function.Onceagain,examinetheCallStackpane,andyou’llseesomethingsimilartoFigure18.14.
Figure18.14
YoucanclickeachentryintheCallStackpanetoexaminewheretheJavaScriptengineiscurrentlyexecutingineachofthefunctions.IfyouclickthebuttonClickentry,thedevelopertoolshighlightline25,thelineinsideofbuttonClick()thatiscurrentlyexecuting.
NowstepintosecondCall(),andanotherentryisaddedtothecallstack.OnemoresteptakesyouintothirdCall(),againwithitsnamebeingaddedtothetopofthecallstack.
StepIntoagain,andasyouleavethethirdCall()youwillseethatitscorrespondingentryisremovedfromthetopofthecallstack.YetanothersteptakesyououtofsecondCall().Eachadditionalsteptakesyououtofafunctionandremovesitsnamefromthecallstack,untileventuallyallthecodehasbeenexecuted.
Thisdemopagewasverysimpletofollow,butwithcomplexpages,thecallstackcanproveveryusefulfortrackingwhereyouare,whereyouhavebeen,andhowyougotthere.
Asmentionedearlier,mostotherdevelopertoolsforotherbrowsersaresimilartoChrome’sdevelopertoolsinfunctionality,butasyou’llsoonseewithIE11,thetoolscanlookabitdifferent.
DebugginginInternetExplorerBeforeversion8,developershadtodownloadandinstalltheMicrosoftScriptDebuggerforanytypeofscriptdebugging.Thankfully,MicrosoftbuiltadebuggerintoIE8,andeverysubsequentversionincludesasuiteoftoolstoeaseourlives.
Youcanaccessthedebuggerinacoupleofways,theeasiestbeingtopresstheF12key.However,youcanalsobringupthedevelopmenttoolsbyclickingthe“gear”menuandchoosingtheF12DeveloperToolsoption.
Bydefault,theF12DeveloperToolsopensasapanelwithinthebrowserwindow(Figure18.15),butaswithChrome’stools,youcanpopitoutwiththeiconnexttotheClosebutton.
Figure18.15
AsyoucantellfromFigure18.15,IE’stoolsarelaidoutmuchdifferentlythanChrome’s.Ontheleft-handside,youseealistoficons.Thetwoweareconcernedwitharethesecondandthirdicons:theconsole(Figure18.16)anddebugger(Figure18.17),respectively.
Figure18.16
Figure18.17
AsyoucanseeinFigure18.17,thedebuggerismadeupoftwopanels.Theleftdisplaysthesourcecodeofthefile,anditusesatabbedinterfacetodisplaythesourceofmultiplefiles.IfmultiplefilescontainJavaScript,youcanopentheminanewtabusingthefileselectionbutton.
Therightpanelcontainstwosubpaneltabs:
Watches:Liststhevariables/expressionsandtheirvaluesyouspecifytowatchatthebreakpoint.Thisalsodisplaysthevariablesinscope.
Breakpoints/CallStack:Listsallbreakpointsthatyou’vecreatedforthecodeinthecurrentpage.Youcanclick“CallStack”todisplaythecallstack.
Nowloadch18_example4.html,andyou’llseethetimestableinyourwebpage.
SettingBreakpointsCreatingabreakpointintheF12DeveloperToolsisassimpleandstraightforwardasitisinChrome,exceptthatinsteadofclickingthelinenumber,youwanttoclickthegrayareatotheleftofthelinenumber(thegutter).
Setabreakpointonline12.Breakpointsaredenotedbyaredcircleinthegutter,andnoticethatanentrywasaddedinthelistofbreakpointsinthebreakpointssubpanel(Figure18.18).Eachentryconsistsofacheckboxtoenable/disablethebreakpoint,thefilenameofthesourcefile,andthelinenumberthebreakpointison(italsodisplaysthecolumnofthatline).
Figure18.18
AddingWatchesTheWatchespanelliststhevariablesandexpressionsyouwanttowatch,aswellasthevariablesinscope.AddingawatchisverysimilartoChrome;simplyclickthenewwatchiconandtypethevariableorexpressionyouwanttowatch.Figure18.19showsawatchfortheexpressioncounter==1whenthedebuggerispausedonline12.
Figure18.19
SteppingthroughCodeAtthetopofthedebuggerwindowisasetofbuttonsthatcontrolcodeexecution(seeFigure18.20).
Figure18.20
TheContinueoption(shortcutkeyF5orF8)continuescodeexecutionuntileitherthenext
breakpointortheendofallcode.Thesecondoption,Break,letsyoupauseexecution.Thisisusefulifyoufindyourselfinaninfiniteloop.NextaretheStepInto(F11),StepOver(F10),andStepOut(Shift+11)buttons.
TheF12DeveloperToolsdebuggerdenotesthecurrentlinebyhighlightingthelineinyellowandaddsayellowarrowinthegutter.ButunlikeChrome,steppingthroughcodedoesnotupdatethewebpage.TheJavaScriptexecutes,butyouwillnotseetheresultsuntilallcodeisexecuted.
TheConsoleTheconsolelogsJavaScripterrorsandenablesyoutoexecutecodewithinthecontextofthelineatwhichthedebuggerisstopped.Figure18.21showsthe“ChangedontheFly”example.
Figure18.21
DebugginginFirefoxwithFirebugFirefox’sstoryisaninterestingonebecauseitstoolsetisrelativelynewtothebrowser.Formanyyears,Firefoxdidnothavenativedevelopertools.Instead,developersrelieduponaFirefoxextensioncalledFirebug,whichwasthefirstsuiteofbrowser-baseddevelopertools.ThetoolsweuseineverybrowsertodayaredirectlyinspiredbyFirebug.
EventhoughFirefoxhasitsownsetofbuilt-intools,theystilllackalotoffeaturesfoundinFirebug(andotherbrowsers’tools).Soforthissection,youneedtodownloadandinstalltheFirebugextension.
ToinstallFirebug,openFirefoxandgotohttp://www.getfirebug.com.ClicktheInstallbuttononthewebpageandfollowtheinstructions.Inmostcases,youwillnotneedto
restartFirefox.
YoucanaccessFirebugbyclickingtheFirebugiconinthetoolbar(Figure18.22).YoucanalsoaccessadropdownmenubyclickingthedownarrownexttotheFirebugicontorevealadditionalsettings.Manypanelsaredisabledbydefault,soclickingontheEnableAllPanelsoptionisveryuseful.
Figure18.22
TheJavaScriptdebuggeriscontainedintheScripttab,anditismadeupoftwopanels.Theleftpanelcontainsthesourcecode,andtherightpanelcontainsthreedifferentviewstochoosefrom:Watch,Stack,andBreakpoints.
SettingBreakpointsCreatingbreakpointsinFirebugiseasy;simplyleft-clickthelinenumberorthegutter.Breakpointsaredenotedbyaredcircleinthegutter.
TheBreakpointstabintherightpanedisplaysthelistofbreakpointsyouhavecreated,anditshowsalltheinformationyouexpect:thefilename,thecodeatthatbreakpoint,andthelinenumber.Figure18.23showsabreakpointonline12.
Figure18.23
NowclicktheWatchtab.
WatchesTheWatchtabdisplaysvariablesandtheirvaluescurrentlyinscopeatthecurrentline,andyoucanaddyourownwatchbyclicking“Newwatchexpression…,”typingthevariableorexpressionyouwanttowatch,andpressingtheEnterkey.Watchesthatyouaddhaveagraybackground,andmovingyourmouseoverthemrevealsaredDeletebutton(Figure18.24).
Figure18.24
SteppingthroughCodeAtthetopofthedebuggerwindowaretheiconsforsteppingthroughcode(seeFigure18.25).
Figure18.25
TheContinuebutton(F8)isfirst,followedbyStepInto(F11).NextaretheStepOver(F10)andStepOut(Shift+11)buttons.
Asyoustepthroughcode,youcantellthecurrentstatementbyitsyellowhighlight.Firebugalsousesayellowarrowintheguttertoindicatethecurrentline.LikeChrome,steppingthroughcodeupdatesthewebpage.
TheConsoleFirebugprovidesaconsolewindowwiththeConsoletab(Figure18.26),anditworksliketheconsolefoundinChromeandIE.Youcaninspectanyvariableorexpressionwithinthecontextofthescopeorpage,andyoucanuseittoexecuteJavaScript.
Figure18.26
DebugginginSafariSafari’sstoryissimilartoIE’s.Safari’srenderingengineiscalledWebkit,andthefolksthatwriteandmaintainWebkitbuiltaseparatetool,codenamedDrosera,thatcontainedthetoolssimilartotheotherbrowsers.Itwasaseparatedownload,anditrequiredyouto
attachittoaspecificSafari/Webkitwindow.Today,SafariincludesatoolcalledWebInspector,anditprovidesthefunctionalityyouwouldexpectfromabrowser-basedsuiteoftools.
Safari’sWebInspectorisdisabledbydefault.Toenableit,followthesesteps:
1. ClicktheSettingsmenubuttonandchoosethePreferencesoption(seeFigure18.27).
2. InthePreferenceswindow,clicktheAdvancedtabandselecttheShowDevelopMenuinMenuBaroption(seeFigure18.28).ClosethePreferenceswindow.
3. ClicktheSettingsmenubuttonandselecttheShowMenuBaroption.Thisdisplaysthetraditionalmenusatthetopofthewindow.
4. Toopenthedebugger,selectDevelop➢StartDebuggingJavaScriptfromthemenubar.
Figure18.27
Figure18.28
Let’slookatthewindowandidentifytheseparateparts.Figure18.29showstheJavaScriptdebuggerwhenitwasfirstopenedonthech18_example4.htmlfile.
Figure18.29
Safari’sWebInspectorlooksalotlikeChrome’s,doesn’tit?That’sbecauseChromeisbuiltusingaheavilymodifiedversionofWebKit.TheScriptstabismuchlikeChrome’sSourcestab;youcanseethecode,watchexpressions,callstack,scopevariables,andbreakpointsallatonetime.
SettingBreakpointsCreatingabreakpointfollowsthesameprocedureinWebInspectorasChrome:Clickthelinenumberatwhichyouwantthedebuggertobreak.BreakpointsinWebInspectorare
denotedbythesamebluetagusedinChrome.Createoneonline12.Thebreakpoints’subsectionliststhebreakpointsyoucreate,anditdisplaysthesameinformationyouexpectitto.
AddingWatchesInearlierversions,WebInspectordidnotallowyoutoaddwatches.ButinSafari5,youcancreatewatchestoinspectvariablesandexpressions.SimplyclicktheAddbuttontocreateyourwatch.Figure18.30showsthewatchcounter==1whenthedebuggerispausedonline12.
Figure18.30
Toremoveawatch,clicktheredXnexttoit.
SteppingthroughCodeThecode-steppingbuttonsareatthetopoftherightpanelandunderneaththesearchbox(seeFigure18.31).
Figure18.31
Thesebuttonsperformthesamefunctionsastheotherbrowsertools.Youhavethe
Continuebutton,followedbyStepOver,thenStepIn,andfinallyStepOut.
LikeChromeandFirebug,WebInspectorupdatesthepageasyoustepthroughcode.Soyoucanseetheresultsaseachlineexecutes.
TheConsoleTheconsoleservesthesamepurposeasitdoesintheprevioustools.YoucancheckthevalueofavariablebytypingthevariableandpressingtheEnterkey.Youcanalsoexecutecodeinthecontextofthecurrentlineofcode.Trythe“ChangedontheFly”exampletoseeitinaction.
SUMMARYInthischapteryoulookedatthelessexcitingpartofcoding,namelybugs.Inanidealworldyou’dgetthingsrightthefirsttime,everytime,butinrealityanycodemorethanafewlineslongislikelytosufferfrombugs.
Youfirstlookedatsomeofthemorecommonerrors,thosemadenotjustbyJavaScriptbeginners,butalsobyexpertswithlotsofexperience.
Someerrorsarenotnecessarilybugsinyourcode,butinfactexceptionstothenormalcircumstancesthatcauseyourcodetofail.Yousawthatthetry…catchstatementsaregoodfordealingwiththissortoferror,andthatyoucanusethecatchclausewiththethrowstatementtodealwithlikelyerrors,suchasthosecausedbyuserinput.Finally,yousawthatifyouwantablockofcodetoexecuteregardlessofanyerror,youcanusethefinallyclause.
YoulookedatthedebuggingtoolsfoundinChrome(andbyextensionOpera),InternetExplorer,FirebugforFirefox,andSafari.Withthesetoolsyoucananalyzecodeasitexecutes,whichenablesyoutoseeitsflowstepbystep,andtocheckvariablesandconditions.Andalthoughthesedebuggershavedifferentinterfaces,theirprinciplesareidentical.
EXERCISESYoucanfindsuggestedsolutionstothesequestionsinAppendixA.
1. Theexamplech18_example4.htmlhasadeliberatebug.Foreachtimestableitcreatesonlymultiplierswithvaluesfrom1to11.
Usethescriptdebuggertoworkoutwhythisishappening,andthencorrectthebug.
2. Thefollowingcodecontainsanumberofcommonerrors.Seeifyoucanspotthem:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Question2</title>
</head>
<body>
<formname="form1"action="">
<inputtype="text"id="text1"name="text1"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>
<br/>
<inputtype="text"id="text2"name="text2"/>
<p>
<inputtype="submit"value="Submit"id="submit1"name="submit1"
/>
</p>
</form>
<script>
functioncheckForm(e){
varelementCount=0;
vartheForm=document.form1;
while(elementCount=<=theForm.length){
if(theForm.elements[elementcount].type=="text"){
if(theForm.elements[elementCount].value()="")
alert("Pleasecompleteallformelements");
theForm.elements[elementCount].focus;
e.preventDefault();
break;
}
}
}
document.form1.addEventListener("submit",checkForm);
</script>
</body>
</html>
AAnswerstoExercisesThisappendixprovidestheanswerstothequestionsyoufindattheendofeachchapterinthisbook.
CHAPTER2
Exercise1QuestionWriteaJavaScriptprogramtoconvertdegreescentigradeintodegreesFahrenheit,andtowritetheresulttothepageinadescriptivesentence.TheJavaScriptequationforFahrenheittocentigradeisasfollows:
degFahren=9/5*degCent+32
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2:Question1</title>
</head>
<body>
<script>
vardegCent=prompt("Enterthedegreesincentigrade",0);
vardegFahren=9/5*degCent+32;
document.write(degCent+"degreescentigradeis"+degFahren+
"degreesFahrenheit");
</script>
</body>
</html>
Savethisasch2_question1.html.
Exercise2QuestionThefollowingcodeusestheprompt()functiontogettwonumbersfromtheuser.Itthenaddsthosetwonumbersandwritestheresulttothepage:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2,Question2</title>
</head>
<body>
<script>
varfirstNumber=prompt("Enterthefirstnumber","");
varsecondNumber=prompt("Enterthesecondnumber","");
vartheTotal=firstNumber+secondNumber;
document.write(firstNumber+"addedto"+secondNumber+
"equals"+theTotal);
</script>
</body>
</html>
However,ifyoutryoutthecode,you’lldiscoverthatitdoesn’twork.Whynot?Changethecodesothatitdoeswork.
Exercise2SolutionThedatathattheprompt()actuallyobtainsisastring.SobothfirstNumberandsecondNumbercontaintextthathappenstobenumbercharacters.Whenyouusethe+symboltoaddthetwovariablestogether,JavaScriptassumesthatbecauseit’sstringdata,youmustwanttoconcatenatethetwoandnotsumthem.
TomakeitexplicittoJavaScriptthatyouwanttoaddthenumbers,youneedtoconvertthedatatonumbersusingtheparseFloat()function:
varfirstNumber=parseFloat(prompt("Enterthefirstnumber",""));
varsecondNumber=parseFloat(prompt("Enterthesecondnumber",""));
vartheTotal=firstNumber+secondNumber;
document.write(firstNumber+"addedto"+secondNumber+"equals"+
theTotal);
Savethisasch2_question2.html.
Nowthedatareturnedbytheprompt()functionisconvertedtoafloating-pointnumberbeforebeingstoredinthefirstNumberandsecondNumbervariables.Then,whenyoudotheadditionthatisstoredintheTotal,JavaScriptmakesthecorrectassumptionthat,becauseboththevariablesarenumbers,youmustmeantoaddthemupandnotconcatenatethem.
Thegeneralruleisthatwhereyouhaveexpressionswithonlynumericaldata,the+operatormeans“doaddition.”Ifthereisanystringdata,the+meansconcatenate.
CHAPTER3
Exercise1QuestionAjuniorprogrammercomestoyouwithsomecodethatappearsnottowork.Canyouspotwherehewentwrong?Givehimahandandcorrectthemistakes.
varuserAge=prompt("Pleaseenteryourage");
if(userAge=0){;
alert("Soyou'reababy!");
}elseif(userAge<0|userAge>200)
alert("Ithinkyoumaybelyingaboutyourage");
else{
alert("That'sagoodage");
}
Exercise1SolutionOhdear,ourjuniorprogrammerishavingabadday!Therearetwomistakesontheline:
if(userAge=0){;
First,hehasonlyoneequalssigninsteadoftwointheif’scondition,whichmeansuserAgewillbeassignedthevalueof0ratherthanuserAgebeingcomparedto0.Thesecondfaultisthesemicolonattheendoftheline—statementssuchasifandloopssuchasforandwhiledon’trequiresemicolons.Thegeneralruleisthatifthestatementhasanassociatedblock(thatis,codeincurlybraces),nosemicolonisneeded.Sothelineshouldbe:
if(userAge==0){
Thenextfaultiswiththeselines:
elseif(userAge<0|userAge>200)
alert("Ithinkyoumaybelyingaboutyourage");
else{
Thejuniorprogrammer’sconditionisaskingifuserAgeislessthan0ORuserAgeisgreaterthan200.ThecorrectoperatorforabooleanORis││,buttheprogrammerhasonlyusedone|.
Exercise2QuestionUsingdocument.write(),writecodethatdisplaystheresultsofthe12timestable.Itsoutputshouldbetheresultsofthecalculations.
12*1=12
12*2=24
12*3=36…
12*11=132
12*12=144
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter3:Question2</title>
</head>
<body>
<script>
vartimesTable=12;
for(vartimesBy=1;timesBy<13;timesBy++){
document.write(timesTable+"*"+
timesBy+"="+
timesBy*timesTable+"<br/>");
}
</script>
</body>
</html>
Savethisasch3_question2.html.
Youuseaforlooptocalculatefrom1*12upto12*12.Theresultsarewrittentothepagewithdocument.write().What’simportanttonotehereistheeffectoftheorderofprecedence;theconcatenationoperator(the+)hasalowerorderofprecedencethanthemultiplicationoperator,*.ThismeansthatthetimesBy*timesTableisdonebeforetheconcatenation,whichistheresultyouwant.Ifthiswerenotthecase,you’dhavetoputthecalculationinparenthesestoraiseitsorderofprecedence.
CHAPTER4
Exercise1QuestionChangethecodeofQuestion2fromChapter3sothatit’safunctionthattakesasparametersthetimestablerequiredandthevaluesatwhichitshouldstartandend.Forexample,youmighttrythefourtimestabledisplayedstartingwith4*4andendingat4*9.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter4:Question1</title>
</head>
<body>
<script>
functionwriteTimesTable(timesTable,timesByStart,timesByEnd){
for(;timesByStart<=timesByEnd;timesByStart++){
document.write(timesTable+"*"+timesByStart+"="+
timesByStart*timesTable+"<br/>");
}
}
writeTimesTable(4,4,9);
</script>
</body>
</html>
Savethisasch4_question1.html.
You’vedeclaredyourfunction,callingitwriteTimesTable(),andgivenitthreeparameters.Thefirstisthetimestableyouwanttowrite,thesecondisthestartpoint,andthethirdisthenumberitshouldgoupto.
You’vemodifiedyourforloop.Firstyoudon’tneedtoinitializeanyvariables,sotheinitializationpartisleftblank—youstillneedtoputasemicolonin,butthere’snocodebeforeit.TheforloopcontinueswhilethetimesByStartparameterislessthanorequaltothetimesByEndparameter.Youcanseethat,aswithavariable,youcanmodifyparameters—inthiscase,timesByStartisincrementedbyoneforeachiterationthroughtheloop.
Thecodetodisplaythetimestableismuchthesame.Forthefunction’scodetobeexecuted,younowactuallyneedtocallit,whichyoudointheline:
writeTimesTable(4,4,9);
Thiswillwritethe4timestablestartingat4times4andendingat9times4.
Exercise2QuestionModifythecodeofQuestion1torequestthetimestabletobedisplayedfromtheuser;thecodeshouldcontinuetorequestanddisplaytimestablesuntiltheuserenters-1.Additionally,doachecktomakesurethattheuserisenteringavalidnumber;ifthenumberisnotvalid,asktheusertore-enterit.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter4:Question2</title>
</head>
<body>
<script>
functionwriteTimesTable(timesTable,timesByStart,timesByEnd){
for(;timesByStart<=timesByEnd;timesByStart++){
document.write(timesTable+"*"+timesByStart+"="+
timesByStart*timesTable+"<br/>");
}
}
vartimesTable;
while((timesTable=prompt("Enterthetimestable",-1))!=-1){
while(isNaN(timesTable)==true){
timesTable=prompt(timesTable+"isnota"+
"validnumber,pleaseretry",-1);
}
if(timesTable==-1){
break;
}
document.write("<br/>The"+timesTable+
"timestable<br/>");
writeTimesTable(timesTable,1,12);
}
</script>
</body>
</html>
Savethisasch4_question2.html.
Thefunctionremainsthesame,solet’slookatthenewcode.ThefirstchangefromQuestion1isthatyoudeclareavariable,timesTable,andtheninitializeitintheconditionofthefirstwhileloop.Thismayseemlikeastrangethingtodoatfirst,butitdoeswork.Thecodeinparenthesesinsidethewhileloop’scondition:
(timesTable=prompt("Enterthetimestable",-1))
isexecutedfirstbecauseitsorderofprecedencehasbeenraisedbytheparentheses.This
willreturnavalue,anditisthisvaluethatiscomparedto-1.Ifit’snot-1,thenthewhileconditionistrue,andthebodyoftheloopexecutes.Otherwiseit’sskippedover,andnothingelsehappensinthispage.
Inasecondwhileloopnestedinsidethefirst,youchecktoseethatthevaluetheuserhasenteredisactuallyanumberusingthefunctionisNaN().Ifit’snot,youprompttheusertotryagain,andthiswillcontinueuntilavalidnumberisentered.
Iftheuserhadenteredaninvalidvalueinitially,theninthesecondwhileloop,thatusermayhaveentered-1,sofollowingthewhileisanifstatementthatcheckstoseeif-1hasbeenentered.Ifithas,youbreakoutofthewhileloop;otherwisethewriteTimesTable()functioniscalled.
CHAPTER5
Exercise1QuestionUsingtheDatetype,calculatethedate12monthsfromnowandwritethisintoawebpage.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5:Question1</title>
</head>
<body>
<script>
varmonths=["Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec"];
varnowDate=newDate();
nowDate.setMonth(nowDate.getMonth()+12);
document.write("Date12monthsaheadis"+nowDate.getDate());
document.write(""+months[nowDate.getMonth()]);
document.write(""+nowDate.getFullYear());
</script>
</body>
</html>
Savethisasch5_question1.html.
BecausethegetMonth()methodreturnsanumberbetween0and11forthemonthratherthanitsname,anarraycalledmonthshasbeencreatedthatstoresthenameofeachmonth.YoucanusegetMonth()togetthearrayindexforthecorrectmonthname.
ThevariablenowDateisinitializedtoanewDateobject.Becausenoinitialvalueisspecified,thenewDateobjectwillcontaintoday’sdate.
Toadd12monthstothecurrentdateyousimplyusesetMonth().YougetthecurrentmonthvaluewithgetMonth(),andthenadd12toit.
Finallyyouwritetheresultouttothepage.
Exercise2QuestionObtainalistofnamesfromtheuser,storingeachnameenteredinanarray.Keepgettinganothernameuntiltheuserentersnothing.Sortthenamesinascendingorderandthenwritethemouttothepage,witheachnameonitsownline.
Exercise2Solution
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5:Question2</title>
</head>
<body>
<script>
varinputName="";
varnamesArray=[];
while((inputName=prompt("Enteraname",""))!=""){
namesArray[namesArray.length]=inputName;
}
namesArray.sort();
varnamesList=namesArray.join("<br/>");
document.write(namesList);
</script>
</body>
</html>
Savethisasch5_question2.html.
Firstyoudeclaretwovariables:inputName,whichholdsthenameenteredbytheuser,andnamesArray,whichholdsanArrayobjectthatstoreseachofthenamesentered.
Youuseawhilelooptokeepgettinganothernamefromtheuseraslongastheuserhasn’tleftthepromptboxblank.Notethattheuseofparenthesesinthewhileconditionisessential.Byplacingthefollowingcodeinsideparentheses,youensurethatthisisexecutedfirstandthatanameisobtainedfromtheuserandstoredintheinputNamevariable:
(inputName=prompt("Enteraname",""))
Thenyoucomparethevaluereturnedinsidetheparentheses—whateverwasenteredbytheuser—withanemptystring(denotedby"").Iftheyarenotequal—thatis,iftheuserdidenteravalue,youlooparoundagain.
Now,tosortthearrayintoorder,youusethesort()methodoftheArrayobject:
namesArray.sort();
Finally,tocreateastringcontainingallvaluescontainedinthearrayelementswitheachbeingonanewline,youusetheHTML<br/>elementandwritethefollowing:
varnamesList=namesArray.join("<br/>")
document.write(namesList);
ThecodenamesArray.join("<br/>")createsthestringwherea<br/>isbetweeneachelementinthearray.Finally,youwritethestringintothepagewithdocument.write().
Exercise3Question
Example8usesafunctiontocreateobjectsusingliteralnotation.ModifythisexampletousethePersondatatype.
Exercise3Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter5,Question3</title>
</head>
<body>
<script>
functionPerson(firstName,lastName){
this.firstName=firstName;
this.lastName=lastName;
}
Person.prototype.getFullName=function(){
returnthis.firstName+""+this.lastName;
};
Person.prototype.greet=function(person){
alert("Hello,"+person.getFullName()+
".I'm"+this.getFullName());
};
varjohnDoe=newPerson("John","Doe");
varjaneDoe=newPerson("Jane","Doe");
johnDoe.greet(janeDoe);
</script>
</body>
</html>
Savethisasch5_question3.html.
ThisisasimplematterofreplacingthecreatePerson()functionwiththePersonreferencetypeyoudefinedattheendofChapter5.
TocreateyourPersonobjects,youusethenewoperatorwhencallingthePersonconstructorfunction,passinginthefirstandlastnamesofthepeopleyouwanttorepresent.
CHAPTER6
Exercise1QuestionWhatproblemdoesthefollowingcodesolve?
varmyString="Thissentencehashasafaultandandweneedtofixit."
varmyRegExp=/(\b\w+\b)\1/g;
myString=myString.replace(myRegExp,"$1");
Nowimaginethatyouchangethatcode,sothatyoucreatetheRegExpobjectlikethis:
varmyRegExp=newRegExp("(\b\w+\b)\1");
Whywouldthisnotwork,andhowcouldyourectifytheproblem?
Exercise1SolutionTheproblemisthatthesentencehas“hashas”and“andand”insideit,clearlyamistake.Alotofwordprocessorshaveanautocorrectfeaturethatfixescommonmistakeslikethis,andwhatyourregularexpressiondoesismimicthisfeature.
SotheerroneousmyString:
“Thissentencehashasafaultandandweneedtofixit.”
willbecome:
“Thissentencehasafaultandweneedtofixit.”
Let’slookathowthecodeworks,startingwiththeregularexpression:
/(\b\w+\b)\1/g;
Byusingparentheses,youhavedefinedagroup,so(\b\w+\b)isgroup1.Thisgroupmatchesthepatternofawordboundaryfollowedbyoneormorealphanumericcharacters,thatis,a–z,A–Z,0–9,and_,followedbyawordboundary.Followingthegroupyouhaveaspacethen\1.What\1meansismatchexactlythesamecharactersaswerematchedinpatterngroup1.So,forexample,ifgroup1matched“has,”then\1willmatch“has”aswell.It’simportanttonotethat\1willmatchtheexactpreviousmatchbygroup1.Sowhengroup1thenmatchesthe“and,”the\1nowmatches“and”andnotthe“has”thatwaspreviouslymatched.
Youusethegroupagaininyourreplace()method;thistimethegroupisspecifiedusingthe$symbol,so$1matchesgroup1.It’sthisthatcausesthetwomatched“has”and“and”tobereplacedbyjustone.
Turningtothesecondpartofthequestion,howdoyouneedtochangethefollowingcodesothatitworks?
varmyRegExp=newRegExp("(\b\w+\b)\1");
Easy;nowyouareusingastringpassedtotheRegExpobject’sconstructor,andyouneedtousetwoslashes(\\)ratherthanonewhenyoumeanaregularexpressionsyntaxcharacter,likethis:
varmyRegExp=newRegExp("(\\b\\w+\\b)\\1","g");
Noticeyou’vealsopassedagtothesecondparametertomakeitaglobalmatch.
Exercise2QuestionWritearegularexpressionthatfindsalloftheoccurrencesoftheword“a”inthefollowingsentenceandreplacesthemwith“the”:
“adogwalkedinoffastreetandorderedafinestbeer”
Thesentenceshouldbecome:
“thedogwalkedinoffthestreetandorderedthefinestbeer”
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6:Question2</title>
</head>
<body>
<script>
varmyString="adogwalkedinoffastreetand"+
"orderedafinestbeer";
varmyRegExp=/\ba\b/gi;
myString=myString.replace(myRegExp,"the");
alert(myString);
</script>
</body>
</html>
Savethisasch6_question2.html.
Withregularexpressions,it’softennotjustwhatyouwanttomatch,butalsowhatyoudon’twanttomatchthatisaproblem.Hereyouwanttomatchthelettera,sowhynotjustwrite:
varmyRegExp=/a/gi;
Well,thatwouldwork,butitwouldalsoreplacethe“a”in“walked,”whichyoudon’twant.Youwanttoreplacetheletter“a”butonlywhereit’sawordonitsownandnotinsideanotherword.Sowhendoesaletterbecomeaword?Theansweriswhenit’sbetweentwowordboundaries.Thewordboundaryisrepresentedbytheregularexpressionspecialcharacter\bsotheregularexpressionbecomes:
varmyRegExp=/\ba\b/gi;
Thegiattheendensuresaglobal,case-insensitivesearch.
Nowwithyourregularexpressioncreated,youcanuseitinthereplace()method’sfirstparameter:
myString=myString.replace(myRegExp,"the");
Exercise3QuestionImagineyouhaveawebsitewithamessageboard.Writearegularexpressionthatwouldremovebarredwords.(Youcanmakeupyourownwords!)
Exercise3Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter6:Question3</title>
</head>
<body>
<script>
varmyRegExp=/(sugar)?candy|choc(olate|oholic)?/gi;
varmyString="Mmm,Ilovechocolate,I'machocoholic."+
"Ilovecandytoo,sweet,sugarcandy";
myString=myString.replace(myRegExp,"salad");
alert(myString);
</script>
</body>
</html>
Savethisasch6_question3.html.
Forthisexample,pretendyou’recreatingscriptforaboardonadietingsitewheretextrelatingtocandyisbarredandwillbereplacedwithamuchhealthieroption,salad.
Thebarredwordsare
chocolate
choc
chocoholic
sugarcandy
candy
Let’sexaminetheregularexpressiontoremovetheoffendingwords:
1. Startwiththetwobasicwords,sotomatch“choc”or“candy,”youuse:
candy|choc
2. Addthematchingfor“sugarcandy.”Becausethe“sugar”bitisoptional,yougroupit
byplacingitinparenthesesandaddingthe“?”afterit.Thismeansmatchthegroupzerotimesoronetime:
(sugar)?candy|choc
3. Youneedtoaddtheoptional“olate”and“oholic”endbits.Youaddtheseasagroupafterthe“choc”wordandagainmakethegroupoptional.Youcanmatcheitheroftheendingsinthegroupbyusingthe|character:
(sugar)?candy|choc(olate|oholic)?/gi
4. Youthendeclareitas:
varmyRegExp=/(sugar)?candy|choc(olate|oholic)?/gi
Thegiattheendmeanstheregularexpressionwillfindandreplacewordsonaglobal,case-insensitivebasis.
So,tosumup:
/(sugar)?candy|choc(olate|oholic)?/gi
readsas:
Eithermatchzerooroneoccurrencesof“sugar”followedby“candy.”Oralternativelymatch“choc”followedbyeitheroneorzerooccurrencesof“olate”ormatch“choc”followedbyzerooroneoccurrenceof“oholic.”
Finally,thefollowing:
myString=myString.replace(myRegExp,"salad");
replacestheoffendingwordswith“salad”andsetsmyStringtothenewcleanversion:
"Mmm,Ilovesalad,I'masalad.Ilovesaladtoo,sweet,salad."
CHAPTER7
Exercise1QuestionCreateapagethatgetstheuser’sdateofbirth.Then,usingthatinformation,tellheronwhatdayoftheweekshewasborn.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7:Question1</title>
</head>
<body>
<script>
vardays=["Sunday","Monday","Tuesday","Wednesday",
"Thursday","Friday","Saturday"];
varyear=prompt("Enterthefourdigityearyouwereborn.");
varmonth=prompt("Enteryourbirthmonth(1-12).");
vardate=prompt("Enterthedayyouwereborn.");
varbirthDate=newDate(year,month-1,date);
alert(days[birthDate.getDay()]);
</script>
</body>
</html>
Savethisasch7_question1.html.
Thesolutionisrathersimple.YoucreateanewDateobjectbasedontheyear,month,anddayenteredbytheuser.ThenyougetthedayoftheweekusingtheDateobject’sgetDay()method.Thisreturnsanumber,butbydefininganarrayofdaysoftheweektomatchthisnumber,youcanusethevalueofgetDay()astheindextoyourdaysarray.
Exercise2QuestionCreateawebpagesimilartoExample4,butmakeitdisplayonlythehour,minutes,andseconds.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter7,Question2</title>
</head>
<body>
<divid="output"></div>
<script>
functionupdateTime(){
vardate=newDate();
varvalue=date.getHours()+":"+
date.getMinutes()+":"+
date.getSeconds();
document.getElementById("output").innerHTML=value;
}
setInterval(updateTime,1000);
</script>
</body>
</html>
Savethisasch7_question2.html.
Displayingonlythehour,minutes,andsecondsisaneasytask;itjustrequiresalittleextracode.YoumodifytheupdateTime()functiontofirstcreateaDateobjecttogetthetimeinformationfrom.
vardate=newDate();
Thenyoubuildastringinhh:mm:ssformat:
varvalue=date.getHours()+":"+
date.getMinutes()+":"+
date.getSeconds();
Finally,yououtputthatstringtothepage:
document.getElementById("output").innerHTML=value;
CHAPTER8
Exercise1QuestionCreatetwopages,onecalledlegacy.htmlandtheothercalledmodern.html.Eachpageshouldhaveaheadingtellingyouwhatpageisloaded.Forexample:
<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>
Usingfeaturedetectionandthelocationobject,sendbrowsersthatdonotsupportgeolocationtolegacy.html;sendbrowsersthatdosupportgeolocationtomodern.html.
Exercise1SolutionThemodern.htmlpageisasfollows:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2:Question1</title>
</head>
<body>
<h2>WelcometotheModernpage!</h2>
<script>
if(!navigator.geolocation){
location.replace("legacy.html");
}
</script>
</body>
</html>
Thelegacy.htmlpageisverysimilar:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter2:Question1</title>
</head>
<body>
<h2>WelcometotheLegacypage.Youneedtoupgrade!</h2>
<script>
if(navigator.geolocation){
location.replace("modern.html");
}
</script>
</body>
</html>
Thesetwopagesareincrediblysimple.Startingwiththelegacy.htmlpage,youcheckifnavigator.geolocationisatruthyvalue:
if(navigator.geolocation){
location.replace("modern.html");
}
Ifitis,youredirecttheusertothemodern.htmlpage.Notethatyouusereplace()ratherthanhref,becauseyoudon’twanttheusertobeabletoclickthebrowser’sBackbutton.Thiswayit’slesseasytospotthatanewpageisbeingloaded.
Themodern.htmlpageisalmostidentical,exceptthatinyourifstatementyoucheckifnavigator.geolocationisfalsey:
if(!navigator.geolocation){
location.replace("legacy.html");
}
Ifso,youredirecttolegacy.html.
Exercise2QuestionModifyExample3todisplayoneofthefourimagesrandomly.Hint:refertoChapter5andtheMath.random()method.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter8,Question2</title>
</head>
<body>
<imgsrc=""width="200"height="150"alt="MyImage"/>
<script>
functiongetRandomNumber(min,max){
returnMath.floor(Math.random()*max)+min;
}
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
varrandom=getRandomNumber(0,myImages.length);
document.images[0].src=myImages[random];
</script>
</body>
</html>
Savethisasch8_question2.html.
Thekeytothissolutionisgettingarandomnumberbetween0andthelengthofthe
myImagesarray,andwritingafunctiontogeneratearandomnumberwouldgreatlyhelpwiththat.So,youwriteafunctioncalledgetRandomNumber():
functiongetRandomNumber(min,max){
returnMath.floor(Math.random()*max)+min;
}
Itgeneratesarandomnumberwithintherangeofminandmax.ThealgorithmwascopiedfromChapter5.
NowyoucanusegetRandomNumber()togenerateanumberforyou,passing0astheminandthelengthofthearrayasthemax:
varrandom=getRandomNumber(0,myImages.length);
Youthenusetherandomnumbertogettheimage:
document.images[0].src=myImages[random];
CHAPTER9
Exercise1QuestionHere’ssomeHTMLcodethatcreatesatable.Re-createthistableusingonlyJavaScriptandthecoreDOMobjectstogeneratetheHTML.Testyourcodeinallbrowsersavailabletoyoutomakesureitworksinthem.Hint:Commenteachlineasyouwriteittokeeptrackofwhereyouareinthetreestructure,andcreateanewvariableforeveryelementonthepage(forexample,notjustoneforeachoftheTDcellsbutninevariables).
<table>
<tr>
<td>Car</td>
<td>TopSpeed</td>
<td>Price</td>
</tr>
<tr>
<td>Chevrolet</td>
<td>120mph</td>
<td>$10,000</td>
</tr>
<tr>
<td>Pontiac</td>
<td>140mph</td>
<td>$20,000</td>
</tr>
</table>
Exercise1SolutionItseemsaratherdauntingexample,butratherthanbeingdifficult,itisjustaconjunctionoftwoareas,onebuildingatreestructureandtheothernavigatingthetreestructure.Youstartatthe<body/>elementandcreatea<table/>element.Nowyoucannavigatetothenew<table/>elementyou’vecreatedandcreateanew<tr/>elementandcarryonfromthere.It’salengthy,repetitious,andtediousprocess,sothat’swhyit’sagoodideatocommentyourcodetokeeptrackofwhereyouare.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9:Question1</title>
</head>
<body>
<script>
vartableElem=document.createElement("table");
vartrElem1=document.createElement("tr");
vartrElem2=document.createElement("tr");
vartrElem3=document.createElement("tr");
vartdElem1=document.createElement("td");
vartdElem2=document.createElement("td");
vartdElem3=document.createElement("td");
vartdElem4=document.createElement("td");
vartdElem5=document.createElement("td");
vartdElem6=document.createElement("td");
vartdElem7=document.createElement("td");
vartdElem8=document.createElement("td");
vartdElem9=document.createElement("td");
vartextNodeA1=document.createTextNode("Car");
vartextNodeA2=document.createTextNode("TopSpeed");
vartextNodeA3=document.createTextNode("Price");
vartextNodeB1=document.createTextNode("Chevrolet");
vartextNodeB2=document.createTextNode("120mph");
vartextNodeB3=document.createTextNode("$10,000");
vartextNodeC1=document.createTextNode("Pontiac");
vartextNodeC2=document.createTextNode("140mph");
vartextNodeC3=document.createTextNode("$14,000");
vardocNavigate=document.body;//Startswithbodyelement
docNavigate.appendChild(tableElem);//Addsthetableelement
docNavigate=docNavigate.lastChild;//Movestothetableelement
docNavigate.appendChild(trElem1);//AddstheTRelement
docNavigate=docNavigate.firstChild;//MovestheTRelement
docNavigate.appendChild(tdElem1);//AddsthefirstTDelementinthe
//heading
docNavigate.appendChild(tdElem2);//AddsthesecondTDelementin
the
//heading
docNavigate.appendChild(tdElem3);//AddsthethirdTDelementinthe
//heading
docNavigate=docNavigate.firstChild;//MovestothefirstTDelement
docNavigate.appendChild(textNodeA1);//Addsthesecondtextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeA2);//Addsthesecondtextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeA3);//Addsthethirdtextnode
docNavigate=docNavigate.parentNode;//MovesbacktotheTRelement
docNavigate=docNavigate.parentNode;//Movesbacktothetableelement
docNavigate.appendChild(trElem2);//AddsthesecondTRelement
docNavigate=docNavigate.lastChild;//MovestothesecondTRelement
docNavigate.appendChild(tdElem4);//AddstheTDelement
docNavigate.appendChild(tdElem5);//AddstheTDelement
docNavigate.appendChild(tdElem6);//AddstheTDelement
docNavigate=docNavigate.firstChild;//MovestothefirstTDelement
docNavigate.appendChild(textNodeB1);//Addsthefirsttextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeB2);//Addsthesecondtextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeB3);//Addsthethirdtextnode
docNavigate=docNavigate.parentNode;//MovesbacktotheTRelement
docNavigate=docNavigate.parentNode;//Movesbacktothetableelement
docNavigate.appendChild(trElem3);//AddstheTRelement
docNavigate=docNavigate.lastChild;//MovestotheTRelement
docNavigate.appendChild(tdElem7);//AddstheTDelement
docNavigate.appendChild(tdElem8);//AddstheTDelement
docNavigate.appendChild(tdElem9);//AddstheTDelement
docNavigate=docNavigate.firstChild;//MovestotheTDelement
docNavigate.appendChild(textNodeC1);//Addsthefirsttextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeC2);//Addsthesecondtextnode
docNavigate=docNavigate.nextSibling;//MovestothenextTDelement
docNavigate.appendChild(textNodeC3);//Addsthethirdtextnode
</script>
</body>
</html>
Savethisasch9_question1.html.
Exercise2QuestionModifyExample6sothattheamountofpixelsmovedineitherdirectioniscontrolledbyaglobalvariable.Callitdirection.RemovetheswitchDirectionvariable,andchangethecodetousethenewdirectionvariabletodeterminewhentheanimationshouldchangedirections.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter9,Question2</title>
<style>
#divAdvert{
position:absolute;
font:12pxArial;
top:4px;
left:0px;
}
</style>
</head>
<body>
<divid="divAdvert">
Hereisanadvertisement.
</div>
<script>
vardirection=2;
functiondoAnimation(){
vardivAdvert=document.getElementById("divAdvert");
varcurrentLeft=divAdvert.offsetLeft;
if(currentLeft>400||currentLeft<0){
direction=-direction;
}
varnewLocation=currentLeft+direction;
divAdvert.style.left=newLocation+"px";
}
setInterval(doAnimation,10);
</script>
</body>
</html>
Savethisasch9_question2.html.
Thismodificationsoundscomplexatfirst,butitactuallysimplifiesthedoAnimation()functionbecauseonevariableisresponsiblefor:
theamountofpixelsmoved
thedirectiontheelementismoved
First,youremovetheswitchDirectionvariableandcreateanewonecalleddirection,initializingitwiththevalueof2:
vardirection=2;
TheninsidethedoAnimation()function,youchangethevalueofdirectionwhenthe<div/>elementreachesoneofitsbounds(0pixelsor400pixels):
if(currentLeft>400||currentLeft<0){
direction=-direction;
}
Thenewdirectionvalueissimple;yousimplymakedirectionnegative.Soifdirectionispositive,itbecomesnegative.Ifdirectionisnegative,itbecomespositive(remember:anegativetimesanegativeisapositive).
Youthencalculatethenewleftpositionandchangetheelement’sstyle:
varnewLocation=currentLeft+direction;
divAdvert.style.left=newLocation+"px";
CHAPTER10
Exercise1QuestionAddamethodtotheeventutilityobjectcalledisOldIE()thatreturnsabooleanvalueindicatingwhetherornotthebrowserisold-IE.
Exercise1Solutionvarevt={
addListener:function(obj,type,fn){
if(typeofobj.addEventListener!="undefined"){
obj.addEventListener(type,fn);
}else{
obj.attachEvent("on"+type,fn);
}
},
removeListener:function(obj,type,fn){
if(typeofobj.removeEventListener!="undefined"){
obj.removeEventListener(type,fn);
}else{
obj.detachEvent("on"+type,fn);
}
},
getTarget:function(e){
if(e.target){
returne.target;
}
returne.srcElement;
},
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else{
e.returnValue=false;
}
},
isOldIE:function(){
returntypeofdocument.addEventListener=="undefined";
}
};
Savethisasch10_question1.html.
YouhavemanywaystodetermineifthebrowserisanolderversionofInternetExplorer.Yourauthorchosetocheckifdocument.addEventListener()isundefined.IE9+supportsthemethod,whereasIE8andbelowdonot.
Exercise2Question
Example15exhibitssomebehaviorinconsistenciesbetweenstandards-compliantbrowsersandold-IE.Rememberthattheeventhandlersexecuteinreverseorderinold-IE.ModifythisexampletousethenewisOldIE()methodsothatyoucanwritespecificcodeforold-IEandstandards-compliantbrowsers(hint:youwillcalltheaddListener()methodfourtimes).
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Question2</title>
</head>
<body>
<imgid="img0"src="usa.gif"/>
<divid="status"></div>
<scriptsrc="ch10_question1.js"></script>
<script>
varmyImages=[
"usa.gif",
"canada.gif",
"jamaica.gif",
"mexico.gif"
];
functionchangeImg(e){
varel=evt.getTarget(e);
varnewImgNumber=Math.round(Math.random()*3);
while(el.src.indexOf(myImages[newImgNumber])!=-1){
newImgNumber=Math.round(Math.random()*3);
}
el.src=myImages[newImgNumber];
}
functionupdateStatus(e){
varel=evt.getTarget(e);
varstatus=document.getElementById("status");
status.innerHTML="Theimagechangedto"+el.src;
if(el.src.indexOf("mexico")>-1){
evt.removeListener(el,"click",changeImg);
evt.removeListener(el,"click",updateStatus);
}
}
varimgObj=document.getElementById("img0");
if(evt.isOldIE()){
evt.addListener(imgObj,"click",updateStatus);
evt.addListener(imgObj,"click",changeImg);
}else{
evt.addListener(imgObj,"click",changeImg);
evt.addListener(imgObj,"click",updateStatus);
}
</script>
</body>
</html>
Savethisasch10_question2.html.
ThemajorityofthecodeisidenticaltoExample15.Theonlydifferenceishowyouregistertheeventlisteners.WithyournewisOldIE()method,youcanregistertheclickeventlistenersinthecorrectorder(forold-IE).Forstandards-compliantbrowsers,youregistertheeventlistenersinthesameorderasExample15.
Exercise3QuestionExample17hadyouwriteacross-browsertabscript,butasyouprobablynoticed,itbehavespeculiarly.Thebasicideaisthere,butthetabsremainactiveasyouclickanothertab.Modifythescriptsothatonlyonetabisactiveatatime.
Exercise3SolutionExample17isincompletebecausethescriptdoesn’tkeeptrackofwhichtabisactive.Probablythesimplestwaytoaddstaterecognitiontothescriptistoaddaglobalvariablethatkeepstrackofthetabthatwaslastclicked.Thisparticularsolutionusesthisidea.Changedlinesofcodearehighlighted.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter10:Question3</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="ch10_question1.js"></script>
<script>
varactiveTab=null;
functionhandleEvent(e){
vartarget=evt.getTarget(e);
switch(e.type){
case"mouseover":
if(target.className=="tabStrip-tab"){
target.className="tabStrip-tab-hover";
}
break;
case"mouseout":
if(target.className=="tabStrip-tab-hover"){
target.className="tabStrip-tab";
}
break;
case"click":
if(target.className=="tabStrip-tab-hover"){
if(activeTab){
activeTab.className="tabStrip-tab";
}
varnum=target.getAttribute("data-tab-number");
target.className="tabStrip-tab-click";
showDescription(num);
activeTab=target;
}
break;
}
}
functionshowDescription(num){
vardescContainer=document.getElementById("descContainer");
vartext="DescriptionforTab"+num;
descContainer.innerHTML=text;
}
evt.addListener(document,"mouseover",handleEvent);
evt.addListener(document,"mouseout",handleEvent);
evt.addListener(document,"click",handleEvent);
</script>
</body>
</html>
Savethisasch10_question3.html.
ThissolutionstartswithanewglobalvariablecalledactiveTab.Itspurposeistocontainareferencetothetabelementthatwaslastclicked,andyouinitializeitasnull.
Whenyouclickatabelement,youfirstneedtodeactivatethecurrentlyactivetab:
if(activeTab){
activeTab.className="tabStrip-tab";
}
Todothat,youfirstcheckifyouhaveanactivetab,andifso,yousetitsclassNamepropertybacktotheoriginaltabStrip-tab.Thenafteryouactivatethenewtab,youassignittotheactiveTabvariable:
activeTab=target;
Simple,buteffective.
CHAPTER11
Exercise1QuestionUsingthecodefromthetemperatureconverterexampleyousawinChapter2,createauserinterfaceforitandconnectittotheexistingcodesothattheusercanenteravalueindegreesFahrenheitandconvertittocentigrade.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Question1</title>
</head>
<body>
<formaction=""name="form1">
<p>
<inputtype="text"name="txtCalcBox"value="0.0"/>
</p>
<inputtype="button"value="Converttocentigrade"
id="btnToCent"name="btnToCent"/>
</form>
<script>
functionconvertToCentigrade(degFahren){
vardegCent=5/9*(degFahren-32);
returndegCent;
}
functionbtnToCentClick(){
varcalcBox=document.form1.txtCalcBox;
if(isNaN(calcBox.value)==true||calcBox.value==""){
calcBox.value="ErrorInvalidValue";
}else{
calcBox.value=convertToCentigrade(calcBox.value);
}
}
document.getElementById("btnToCent")
.addEventListener("click",btnToCentClick);
</script>
</body>
</html>
Savethisasch11_question1.html.
TheinterfacepartissimplyaformcontainingatextboxintowhichusersentertheFahrenheitvalueandabuttontheyclicktoconvertthatvaluetocentigrade.ThebuttonhasaclickeventlistenerthatexecutesbtnToCentClick()whentheeventfires.
ThefirstlineofbtnToCentClick()declaresavariableandsetsittoreferencetheobjectrepresentingthetextbox:
varcalcBox=document.form1.txtCalcBox;
Whydothis?Well,inyourcodewhenyouwanttousedocument.form1.txtCalcBox,youcannowjustusethemuchshortercalcBox;itsavestypingandkeepsyourcodeshorterandeasiertoread.
So:
alert(document.form1.txtCalcBox.value);
isthesameas:
alert(calcBox.value);
Intheremainingpartofthefunctionyoudoasanitycheck—ifwhattheuserhasenteredisanumber(thatis,itisnotNotANumber)andthetextboxdoescontainavalue,youusetheFahrenheit-to-centigradeconversionfunctionyousawinChapter2todotheconversion,theresultsofwhichareusedtosetthetextbox’svalue.
Exercise2QuestionCreateauserinterfacethatallowsuserstopickthecomputersystemoftheirdreams,similarinprincipletothee-commercesitessellingcomputersovertheInternet.Forexample,theycouldbegivenachoiceofprocessortype,speed,memory,andharddrivesize,andtheoptiontoaddadditionalcomponentslikeaDVD-ROMdrive,asoundcard,andsoon.Astheuserschangetheirselections,thepriceofthesystemshouldupdateautomaticallyandnotifythemofthecostofthesystemastheyspecifiedit,eitherbyusinganalertboxorbyupdatingthecontentsofatextbox.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter11:Question2</title>
</head>
<body>
<formaction=""name="form1">
<p>
Choosethecomponentsyouwantincludedonyourcomputer
</p>
<p>
<labelfor="cboProcessor">Processor</label>
<selectname="cboProcessor"id="cboProcessor">
<optionvalue="100">Dual-core2GHz</option>
<optionvalue="101">Quad-core2.4GHz</option>
<optionvalue="102">Eight-core3GHz</option>
</select>
</p>
<p>
<labelfor="cboSsd">Solid-stateDrive</label>
<selectname="cboSsd"id="cboSsd">
<optionvalue="200">250GB</option>
<optionvalue="201">512GB</option>
<optionvalue="202">1TB</option>
</select>
</p>
<p>
<labelfor="chkDVD">DVD-ROM</label>
<inputtype="checkbox"id="chkDVD"name="chkDVD"value="300"/>
</p>
<p>
<labelfor="chkBluRay">Blu-ray</label>
<inputtype="checkbox"id="chkBluRay"name="chkBluRay"
value="301"/>
</p>
<fieldset>
<legend>Case</legend>
<p>
<labelfor="desktop">Desktop</label>
<inputtype="radio"id="desktop"
name="radCase"checkedvalue="400"/>
</p>
<p>
<labelfor="minitower">Mini-tower</label>
<inputtype="radio"id="minitower"
name="radCase"value="401"/>
</p>
<p>
<labelfor="fulltower">Full-tower</label>
<inputtype="radio"id="fulltower"
name="radCase"value="402"/>
</p>
</fieldset>
<p>
<inputtype="button"value="Update"
id="btnUpdate"name="btnUpdate"/>
</p>
<p>
<labelfor="txtOrder">OrderSummary:</label>
</p>
<p>
<textarearows="20"cols="35"id="txtOrder"
name="txtOrder"></textarea>
</p>
</form>
<script>
varproductDb=[];
productDb[100]=150;
productDb[101]=350;
productDb[102]=700;
productDb[200]=100;
productDb[201]=200;
productDb[202]=500;
productDb[300]=50;
productDb[301]=75;
productDb[400]=75;
productDb[401]=50;
productDb[402]=100;
functiongetDropDownInfo(element){
varselected=element[element.selectedIndex];
return{
text:selected.text,
price:productDb[selected.value]
};
}
functiongetCheckboxInfo(element){
return{
checked:element.checked,
price:productDb[element.value]
};
}
functiongetRadioInfo(elements){
for(vari=0;i<elements.length;i++){
if(!elements[i].checked){
continue;
}
varselected=elements[i];
varlabel=document.querySelector(
"[for="+selected.id+"]");
return{
text:label.innerHTML,
price:productDb[selected.value]
};
}
}
functionbtnUpdateClick(){
vartotal=0;
varorderDetails="";
vartheForm=document.form1;
varselectedProcessor=getDropDownInfo(theForm.cboProcessor);
total=selectedProcessor.price;
orderDetails="Processor:"+selectedProcessor.text;
orderDetails=orderDetails+"$"+
selectedProcessor.price+"\n";
varselectedSsd=getDropDownInfo(theForm.cboSsd);
total=total+selectedSsd.price;
orderDetails=orderDetails+"Solid-stateDrive:"+
selectedSsd.text;
orderDetails=orderDetails+"$"+selectedSsd.price+"\n";
vardvdInfo=getCheckboxInfo(theForm.chkDVD);
if(dvdInfo.checked){
total=total+dvdInfo.price;
orderDetails=orderDetails+"DVD-ROM:$"+
dvdInfo.price+"\n";
}
varbluRayInfo=getCheckboxInfo(theForm.chkBluRay);
if(bluRayInfo.checked){
total=total+bluRayInfo.price;
orderDetails=orderDetails+"Blu-ray:$"+
bluRayInfo.price+"\n";
}
varcaseInfo=getRadioInfo(theForm.radCase);
total=total+caseInfo.price;
orderDetails=orderDetails+caseInfo.text+":$"+
caseInfo.price;
orderDetails=orderDetails+"\n\nTotalOrderCostis"+
"$"+total;
theForm.txtOrder.value=orderDetails;
}
document.getElementById("btnUpdate")
.addEventListener("click",btnUpdateClick);
</script>
</script>
</body>
</html>
Savethisasch11_question2.html.
Thisisjustoneofmanywaystotacklethisquestion—youmaywellhavethoughtofabetterway.
Hereyouaredisplayingtheresultsoftheuser’sselectionastextinatextareabox,witheachitemanditscostdisplayedonseparatelinesandafinaltotalattheend.
EachformelementhasavaluesettoholdastockIDnumber.Forexample,afulltowercaseisstockID402.TheactualcostoftheitemisheldinanarraycalledproductDb.Whynotjuststorethepriceinthevalueattributeofeachformelement?Well,thiswayismoreflexible.Currentlyyourarrayjustholdspricedetailsforeachitem,butyoucouldmodify
itthatsoitholdsmoredata—forexampleprice,description,numberinstock,andsoon.Also,ifthisformispostedtoaserverthevaluespassedwillbestockIDs,whichyoucouldthenuseforalookupinastockdatabase.Ifthevaluesweresettopricesandtheformwasposted,you’dhavenowayoftellingwhatthecustomerordered—allyou’dknowishowmuchitallcost.
ThissolutionincludesanUpdatebuttonwhich,whenclicked,updatestheorderdetailsinthetextareabox.However,youmaywanttoaddeventhandlerstoeachformelementandupdatewhenanythingchanges.
Turningtothefunctionthatactuallydisplaystheordersummary,btnUpdateClick(),youcanseethatthereisalotofcode,andalthoughitlookscomplex,it’sactuallyfairlysimple.Alotofitisrepeatedwithslightmodification.Italsoreliesuponseveralhelperfunctionstopullvariousinformationfromtheselectedformelements.
Tosaveontypingandmakethecodealittlemorereadable,thissolutiondeclaresthetheFormvariabletocontaintheFormobjectAfterthevariable’sdeclaration,youthenfindoutwhichprocessorhasbeenselectedandgetitscostandtextwiththegetDropDownInfo()function:
functiongetDropDownInfo(element){
varselected=element[element.selectedIndex];
return{
text:selected.text,
price:productDb[selected.value]
};
}
TheselectedIndexpropertytellsyouwhichOptionobjectinsidetheselectcontrolhasbeenselectedbytheuser.YoureturnanewobjectthatcontainstheselectedOption’stextandthepricefromtheproductdatabase.
Sotogettheprocessorinformation,youpasstheForm.cboProcessortogetDropDownInfo()andassigntheresultingobjecttoselectedProcessor.Youthencalculatethetotalandupdatetheorderdetails:
varselectedProcessor=getDropDownInfo(theForm.cboProcessor);
total=selectedProcessor.price;
orderDetails="Processor:"+selectedProcessor.text;
orderDetails=orderDetails+"$"+selectedProcessor.price+"\n";
Thesameprincipleapplieswhenyoufindtheselectedsolid-statedrive,solet’sturnnexttothecheckboxesfortheoptionalextraitems,lookingfirstattheDVD-ROMcheckbox:
vardvdInfo=getCheckboxInfo(theForm.chkDVD);
if(dvdInfo.checked){
total=total+dvdInfo.price;
orderDetails=orderDetails+"DVD-ROM:$"+
dvdInfo.price+"\n";
}
Again,youuseahelperfunction—thisone’scalledgetCheckboxInfo()—toretrievetheinformationaboutthegivencheckbox:
functiongetCheckboxInfo(element){
return{
checked:element.checked,
price:productDb[element.value]
};
}
Thisreturnsanewobjectthattellsyouthepriceofthecomponent,aswellasifthecheckboxischecked.
Ifthecheckboxischecked,youaddaDVD-ROMtotheorderdetailsandupdatetherunningtotal.ThesameprincipleappliesfortheBlu-raycheckbox.
Finally,youhavethecomputer’scase.Becauseonlyonecasetypeoutoftheoptionscanbeselected,youusedaradiobuttongroup.Unfortunately,thereisnoselectedIndexforradiobuttonsasthereisforcheckboxes,soyouhavetogothrougheachradiobuttoninturnandfindoutifithasbeenselected.ThegetRadioInfo()helperfunctiondoesjustthat:
functiongetRadioInfo(elements){
for(vari=0;i<elements.length;i++){
if(!elements[i].checked){
continue;
}
varselected=elements[i];
varlabel=document.querySelector("[for="+selected.id+"]");
return{
text:label.innerHTML,
price:productDb[selected.value]
};
}
}
Itloopsthroughtheradiobuttongroupandcheckseachradiobutton’scheckedproperty.Ifit’sfalse,theloopiterateswiththecontinueoperator.Butiftheradiobuttonischecked,youneedtogetthetextassociatedwiththelabelfortheselectedradiobuttonandthecomponent’spricefromtheproductDbarray.
So,insidethebtnUpdateClick()function,youcanusethishelperfunctiontogeteverythingyouneedtoaddtheselectedcomputercasetothetotalanddescription:
varcaseInfo=getRadioInfo(theForm.radCase);
total=total+caseInfo.price;
orderDetails=orderDetails+caseInfo.text+":$"+
caseInfo.price;
Finally,setthetextareatothedetailsofthesystemtheuserhasselected:
orderDetails=orderDetails+"\n\nTotalOrderCostis"+total;
CHAPTER12
Exercise1QuestionThecodeforalertingasinglemessageinExample1isn’tveryexciting.Modifythecodetodisplayarandommessagefromasetofthreepossiblemessages.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter12:Question1</title>
<style>
[data-drop-target]{
height:400px;
width:200px;
margin:2px;
background-color:gainsboro;
float:left;
}
.drag-enter{
border:2pxdashed#000;
}
.box{
width:200px;
height:200px;
}
.navy{
background-color:navy;
}
.red{
background-color:red;
}
</style>
</head>
<body>
<divdata-drop-target="true">
<divid="box1"draggable="true"class="boxnavy"></div>
<divid="box2"draggable="true"class="boxred"></div>
</div>
<divdata-drop-target="true"></div>
<script>
functiongetRandomMessage(){
varmessages=[
"Youmovedanelement!",
"Movedandelement,youhave!Mmmmmmm?",
"Elementoverboard!"
];
returnmessages[Math.floor((Math.random()*3)+0)];
}
functionhandleDragStart(e){
vardata={
elementId:this.id,
message:getRandomMessage()
};
e.dataTransfer.setData("text",JSON.stringify(data));
}
functionhandleDragEnterLeave(e){
if(e.type=="dragenter"){
this.className="drag-enter";
}else{
this.className="";
}
}
functionhandleOverDrop(e){
e.preventDefault();
if(e.type!="drop"){
return;
}
varjson=e.dataTransfer.getData("text");
vardata=JSON.parse(json);
vardraggedEl=document.getElementById(data.elementId);
if(draggedEl.parentNode==this){
this.className="";
return;
}
draggedEl.parentNode.removeChild(draggedEl);
this.appendChild(draggedEl);
this.className="";
alert(data.message);
}
vardraggable=document.querySelectorAll("[draggable]");
vartargets=document.querySelectorAll("[data-drop-target]");
for(vari=0;i<draggable.length;i++){
draggable[i].addEventListener("dragstart",handleDragStart);
}
for(i=0;i<targets.length;i++){
targets[i].addEventListener("dragover",handleOverDrop);
targets[i].addEventListener("drop",handleOverDrop);
targets[i].addEventListener("dragenter",handleDragEnterLeave);
targets[i].addEventListener("dragleave",handleDragEnterLeave);
}
</script>
</body>
</html>
Savethisasch12_question1.html.
Thissolutionisrathersimple.ItintroducesanewfunctioncalledgetRandomMessage(),whichreturnsoneofthreemessages:
functiongetRandomMessage(){
varmessages=[
"Youmovedanelement!",
"Movedandelement,youhave!Mmmmmmm?",
"Elementoverboard!"
];
returnmessages[Math.floor((Math.random()*3)+0)];
}
AndyouusethisfunctionwhenyouassignthemessagepropertytothedataobjectinhandleDragStart():
vardata={
elementId:this.id,
message:getRandomMessage()
};
Sadly,thissolutionstilldoesn’taddmuchexcitementtotheexample.Butsomeisbetterthannone,right?
CHAPTER13
Exercise1QuestionUsinglocalstorage,createapagethatkeepstrackofhowmanytimesthepagehasbeenvisitedbytheuserinthelastmonth.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Question1</title>
</head>
<body>
<script>
varpageViewCount=localStorage.getItem("pageViewCount");
varpageFirstVisited=localStorage.getItem("pageFirstVisited");
varnow=newDate();
if(pageViewCount==null){
pageViewCount=0;
pageFirstVisited=now.toUTCString();
}
varoneMonth=newDate(pageFirstVisited);
oneMonth.setMonth(oneMonth.getMonth()+1);
if(now>oneMonth){
pageViewCount=0;
pageFirstVisited=now.toUTCString();
}
pageViewCount=parseInt(pageViewCount,10)+1;
localStorage.setItem("pageViewCount",pageViewCount);
localStorage.setItem("pageFirstVisited",pageFirstVisited);
varoutput="You'vevisitedthispage"+pageViewCount+
"timessince"+pageFirstVisited;
document.write(output);
</script>
</body>
</html>
Savethisasch13_question1.html.
ThefirsttwolinesgettwovaluesfromlocalStorageandstoretheminvariables.Thefirstholdsthenumberofvisits,thesecondthedatethepagewasfirstvisited.Youalsocreateavariabletocontainthecurrentdate:
varpageViewCount=localStorage.getItem("pageViewCount");
varpageFirstVisited=localStorage.getItem("pageFirstVisited");
varnow=newDate();
IfthepageViewCountkeydoesnotexistinlocalStorage,thevariableofthesamenameisnull,andyou’llneedtoinitializethepageViewcountandpageFirstVisitedvariableswith0andthecurrentdate,respectively.RememberthatlocalStoragecontainsonlystringdata,soyouusetheDateobject’stoUTCString()methodtoconvertthedatetoastring:
if(pageViewCount==null){
pageViewCount=0;
pageFirstVisited=now.toUTCString();
}
You’reonlytrackingthenumberofvisitswithinamonth’stimespan.So,nextyouneedavariabletocontainaDateobjectonemonthfromthefirstvisit:
varoneMonth=newDate(pageFirstVisited);
oneMonth.setMonth(oneMonth.getMonth()+1);
IfthecurrentdateandtimeislaterthanoneMonth,it’stimetoresetthecounterandvisitedvariables:
if(now>oneMonth){
pageViewCount=0;
pageFirstVisited=now.toUTCString();
}
ThenyouincrementthecounterandstoreitandthefirstvisitvalueinlocalStorage:
pageViewCount=parseInt(pageViewCount,10)+1;
localStorage.setItem("pageViewCount",pageViewCount);
localStorage.setItem("pageFirstVisited",pageFirstVisited);
Finally,writeinformationtothepage:
varoutput="You'vevisitedthispage"+pageViewCount+
"timessince"+pageFirstVisited;
document.write(output);
Exercise2QuestionUsecookiestoloadadifferentadvertisementeverytimeauservisitsawebpage.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter13:Question2</title>
</head>
<body>
<script>
varads=[
"BuyProductA!Youwon'tbesorry!",
"YouneedProductB!Buybuybuy!",
"Don'tbuyProductAorB!ProductCistheonlyoptionfor
you!"
];
functiongetRandomNumber(min,max){
returnMath.floor((Math.random()*max)+min);
}
varlastAdNumber=localStorage.getItem("lastAdNumber");
varnextNumber=getRandomNumber(0,ads.length);
if(lastAdNumber==null){
lastAdNumber=nextNumber;
}else{
lastAdNumber=parseInt(lastAdNumber,10);
while(lastAdNumber==nextNumber){
nextNumber=getRandomNumber(0,ads.length);
}
}
localStorage.setItem("lastAdNumber",nextNumber);
document.write(ads[nextNumber]);
</script>
</body>
</html>
Savethisasch13_question2.html.
Thissolutionislooselybasedonsimilarquestionsinpreviouschapterswhereyouhavedisplayedrandomimagesormessages.Inthiscaseyoudisplayadifferentmessageinthepageeachtimetheuservisitsit;you’llneverseethesamemessagedisplayedtwotimesinarowinthesamebrowser.
YoustorethelastnumberofthepreviouslydisplayedadinlocalStoragewiththekeylastAdNumber.So,youretrievethatvalueandgeneratethenextnumberwithagetRandomNumber()helperfunction(youknowthisalgorithm):
varlastAdNumber=localStorage.getItem("lastAdNumber");
varnextNumber=getRandomNumber(0,ads.length);
IflastAdNumberisnull,youcanusethevalueinnextNumber:
if(lastAdNumber==null){
lastAdNumber=nextNumber;
}
ButiflastAdNumberisnotnull,youneedtogeneratearandomnumberthatisnotlastAdNumber.Sofirst,youconvertlastAdNumbertoanumberwiththeparseInt()
function:
else{
lastAdNumber=parseInt(lastAdNumber,10);
while(lastAdNumber==nextNumber){
nextNumber=getRandomNumber(0,ads.length);
}
}
Thenyouuseawhilelooptogenerateauniquerandomnumber.TheloopiteratesiflastAdNumberisequaltonextNumber,anditcontinuestodosountilthenextnumberisdifferentthanlastAdNumber.
Onceyouhaveauniquenextnumber,youstoreitinlocalStorageanddisplaytheadinthepage:
localStorage.setItem("lastAdNumber",nextNumber);
document.write(ads[nextNumber]);
CHAPTER14
Exercise1QuestionExtendtheHttpRequestmoduletoincludesynchronousrequestsinadditiontotheasynchronousrequeststhemodulealreadymakes.You’llhavetomakesomeadjustmentstoyourcodetoincorporatethisfunctionality.(Hint:Createanasyncpropertyforthemodule.)
Exercise1SolutionfunctionHttpRequest(url,callback){
this.url=url;
this.callBack=callback;
this.async=true;
this.request=newXMLHttpRequest();
};
HttpRequest.prototype.send=function(){
this.request.open("GET",this.url,this.async);
if(this.async){
vartempRequest=this.request;
varcallback=this.callBack;
functionrequestReadystatechange(){
if(tempRequest.readyState==4){
if(tempRequest.status==200){
callback(tempRequest.responseText);
}else{
alert("Anerroroccurredwhileattemptingto"+
"contacttheserver.");
}
}
}
this.request.onreadystatechange=requestReadystatechange;
}
this.request.send(null);
if(!this.async){
this.callBack(this.request.responseText);
}
};
It’spossibletoaddsynchronouscommunicationtoyourHttpRequestmoduleinavarietyofways.Theapproachinthissolutionrefactorsthecodetoaccommodateanewpropertycalledasync,whichcontainseithertrueorfalse.Ifitcontainstrue,theunderlyingXMLHttpRequestobjectusesasynchronouscommunicationtoretrievethefile.Iffalse,themoduleusessynchronouscommunication.
Thefirstchangemadetothemoduleisintheconstructoritself.TheoriginalconstructorinitializesandreadiestheXMLHttpRequestobjecttosenddata.Thiswillnotdoforthisnewversion,however.Instead,theconstructormerelyinitializesalltheproperties:
functionHttpRequest(url,callback){
this.url=url;
this.callBack=callback;
this.async=true;
this.request=newXMLHttpRequest();
};
Youhavethreenewpropertieshere.Thefirst,url,containstheURLthattheXMLHttpRequestobjectshouldattempttorequestfromtheserver.ThecallBackpropertycontainsareferencetothecallbackfunction,andtheasyncpropertydeterminesthetypeofcommunicationtheXMLHttpRequestobjectuses.Settingasynctotrueintheconstructorgivesthepropertyadefaultvalue.Therefore,youcansendtherequestinasynchronousmodewithoutsettingthepropertyexternally.
Thenewconstructorandpropertiesareactuallydesirable,becausetheyenableyoutoreusethesameHttpRequestobjectformultiplerequests.IfyouwantedtomakearequesttoadifferentURL,allyouwouldneedtodoisassigntheurlpropertyanewvalue.Thesamecanbesaidforthecallbackfunctionaswell.
Themajorityofchangestothemoduleareinthesend()method.Itisherethatthemoduledecideswhethertouseasynchronousorsynchronouscommunication.Bothtypesofcommunicationhaveverylittleincommonwhenitcomestomakingarequest;asynchronouscommunicationusestheonreadystatechangeeventhandler,andsynchronouscommunicationallowsaccesstotheXMLHttpRequestobject’spropertieswhentherequestiscomplete.Therefore,codebranchingisrequired:
HttpRequest.prototype.send=function(){
this.request.open("GET",this.url,this.async);
if(this.async){
//morecodehere
}
this.request.send(null);
if(!this.async){
//morecodehere
}
}
Thefirstlineofthismethodusestheopen()methodoftheXMLHttpRequestobject.Theasyncpropertyisusedasthefinalparameterofthemethod.ThisdetermineswhetherornottheXHRobjectusesasynchronouscommunication.Next,anifstatementteststoseeifthis.asyncistrue;ifitis,theasynchronouscodewillbeplacedinthisifblock.Next,theXMLHttpRequestobject’ssend()methodiscalled,sendingtherequesttotheserver.Thefinalifstatementcheckstoseewhetherthis.asyncisfalse.Ifitis,synchronouscodeisplacedwithinthecodeblocktoexecute.
HttpRequest.prototype.send=function(){
this.request.open("GET",this.url,this.async);
if(this.async){
vartempRequest=this.request;
varcallback=this.callBack;
functionrequestReadystatechange(){
if(tempRequest.readyState==4){
if(tempRequest.status==200){
callback(tempRequest.responseText);
}else{
alert("Anerroroccurredwhileattemptingto"+
"contacttheserver.");
}
}
}
this.request.onreadystatechange=requestReadystatechange;
}
this.request.send(null);
if(!this.async){
this.callBack(this.request.responseText);
}
};
Thisnewcodefinishesoffthemethod.Startingwiththefirstifblock,anewvariablecalledcallbackisassignedthevalueofthis.callBack.ThisisdoneforthesamereasonsaswiththetempRequestvariable—scopingissues—becausethispointstotherequestReadystatechange()functioninsteadoftheHttpRequestobject.Otherthanthischange,theasynchronouscoderemainsthesame.TherequestReadystatechange()functionhandlesthereadystatechangeeventandcallsthecallbackfunctionwhentherequestissuccessful.
Thesecondifblockismuchsimpler.Becausethiscodeexecutesonlyifsynchronouscommunicationisdesired,allyouhavetodoiscallthecallbackfunctionandpasstheXMLHttpRequestobject’sresponseTextproperty.
Usingthisnewlyrefactoredmoduleisquitesimple.Thefollowingcodemakesanasynchronousrequestforafictitioustextfilecalledtest.txt:
functionrequestCallback(responseText){
alert(responseText);
}
varhttp=newHttpRequest("test.txt",requestCallback);
http.send();
Nothinghasreallychangedforasynchronousrequests.Thisistheexactsamecodeusedearlierinthechapter.Ifyouwanttousesynchronouscommunication,simplysetasynctofalse,likethis:
functionrequestCallback(responseText){
alert(responseText);
}
varhttp=newHttpRequest("test.txt",requestCallback);
http.async=false;
http.send();
YounowhaveanAjaxmodulethatrequestsinformationinbothasynchronousandsynchronouscommunication!
Exercise2QuestionItwasmentionedearlierinthechapterthatyoucouldmodifythesmartformstonotusehyperlinks.ChangetheformthatusestheHttpRequestmodulesothattheUsernameandEmailfieldsarecheckedwhentheusersubmitstheform.Listenfortheform’ssubmiteventandcancelthesubmissionifausernameore-mailistaken.
Exercise2SolutionFirst,adisclaimer:Ideally,theserviceprovidedbych14_formvalidator.phpshouldallowyoutocheckboththeusernameande-mailaddresswithasinglerequest.Thatwouldgreatlysimplifythissolution.However,sometimesyouneedtomakemultiplerequests,andeachrequestissometimesdependentupontheoutcomeofapreviousrequest.Thisquestionandsolutionismeanttoemulatethat.
Additionally,issuingmultiple(andlinked)asynchronousoperationsisarathercomplexordeal—aconditionreferredto”callbackhell.”You’llgetatasteofthatinthissolution.
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter14:Question2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<formname="theForm">
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputid="btnSubmit"type="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="ch14_question1.js"></script>
<script>
functionbtnSubmitClick(e){
e.preventDefault();
checkUsername();
}
functioncheckUsername(){
varuserValue=document.getElementById("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varurl="ch14_formvalidator.php?username="+userValue;
varrequest=newHttpRequest(url,handleUsernameResponse);
request.send();
}
functioncheckEmail(){
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_formvalidator.php?email="+emailValue;
varrequest=newHttpRequest(url,handleEmailResponse);
request.send();
}
functionhandleUsernameResponse(responseText){
varresponse=JSON.parse(responseText);
if(!response.available){
alert("Theusername"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
checkEmail();
}
functionhandleEmailResponse(responseText){
varresponse=JSON.parse(responseText);
if(!response.available){
alert("Theemailaddress"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
document.theForm.submit();
}
document.getElementById("btnSubmit")
.addEventListener("click",btnSubmitClick);
</script>
</body>
</html>
Savethisasch14_question2.html.
IntheHTML,noticethatthelinksforcheckingtheusernameande-mailaddressaregone.Thereisnoneedforthem,becausethosevaluesarecheckedwhentheuserclickstheSubmitbutton.ThelaststatementoftheJavaScriptcoderegistersthateventlistener:
document.getElementById("btnSubmit")
.addEventListener("click",btnSubmitClick);
Thefunctionthathandlesthebutton’sclickeventiscalledbtnSubmitClick().It’sasimplefunctionthatkicksoffthewholeprocess:
functionbtnSubmitClick(e){
e.preventDefault();
checkUsername();
}
Itsfirststatementpreventstheformfromsubmitting.Thisisimportantbecause,duetothenatureofasynchronousprocesses,btnSubmitClick()cannotberesponsibleforsubmittingtheform.Therefore,anotherfunctionwillneedtosubmittheformifboththeusernameande-mailaddressvalidateandareavailable.
ThesecondstatementcallscheckUsername(),whichisleftmostlyunchanged:
functioncheckUsername(){
varuserValue=document.getElementById("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varurl="ch14_formvalidator.php?username="+userValue;
varrequest=newHttpRequest(url,handleUsernameResponse);
request.send();
}
Infact,theonlychangetothisfunctionisthecallbackpassedtotheHttpRequestconstructor.It’sanewcallbackfunctioncalledhandleUsernameResponse(),anditsomewhatresemblestheoriginalhandleResponse()function:
functionhandleUsernameResponse(responseText){
varresponse=JSON.parse(responseText);
if(!response.available){
alert("Theusername"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
checkEmail();
}
ThisfunctiontakestheresponseandparsesitintoaJavaScriptobject.Iftheusernameisnotavailable,itdisplaystheerrormessagetotheuserandreturns.Nothingelseisprocessedwhentheusernameisunavailable,butifitisavailable,itcallscheckEmail():
functioncheckEmail(){
varemailValue=document.getElementById("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varurl="ch14_formvalidator.php?email="+emailValue;
varrequest=newHttpRequest(url,handleEmailResponse);
request.send();
}
Thisfunctionisalsolargelythesame.TheonlydifferenceisthecallbackfunctionpassedtotheHttpRequestconstructor;it’scalledhandleEmailResponse().Itparsestherequest,anditisthelaststepintheprocess:
functionhandleEmailResponse(responseText){
varresponse=JSON.parse(responseText);
if(!response.available){
alert("Theemailaddress"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
document.theForm.submit();
}
Onceagain,ifthee-mailaddressisnotavailable,thisfunctiondisplaystheerrormessagetotheuserandreturns.Butifthee-mailaddressisavailable,theformisfinallysubmitted.
CHAPTER15
Exercise1QuestionBeingabletocontrolplaybackiscool,butyourcustomUIneedstoalsocontrolvolume.Addan<inputtype="range"/>elementtoExample3tocontrolthevolume.Rememberthattherangeofvolumesupportedbymediaelementsis0.0to1.0.LookbackatChapter11ifyouneedarefresheroftherangeinputtype.ThisunfortunatelywillnotworkinIE.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter15:Question1</title>
</head>
<body>
<div>
<buttonid="playbackController">Play</button>
<buttonid="muteController">Mute</button>
<inputtype="range"id="volumeController"
min="0"max="1"step=".1"value="1"/>
</div>
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
<script>
functionpauseHandler(e){
playButton.innerHTML="Resume";
}
functionplayingHandler(e){
playButton.innerHTML="Pause";
}
functionvolumechangeHandler(e){
muteButton.innerHTML=video.muted?"Unmute":"Mute";
}
functionplaybackClick(e){
video.paused?video.play():video.pause();
}
functionmuteClick(e){
video.muted=!video.muted;
}
functionvolumeInput(e){
video.volume=volumeSlider.value;
}
varvideo=document.getElementById("bbbVideo");
varplayButton=document.getElementById("playbackController");
varmuteButton=document.getElementById("muteController");
varvolumeSlider=document.getElementById("volumeController");
video.addEventListener("pause",pauseHandler);
video.addEventListener("playing",playingHandler);
video.addEventListener("volumechange",volumechangeHandler);
playButton.addEventListener("click",playbackClick);
muteButton.addEventListener("click",muteClick);
volumeSlider.addEventListener("input",volumeInput);
</script>
</body>
</html>
Savethisasch15_question1.html.
ThissolutionisbuiltonExample3.Theadditionsarehighlightedforyourconvenience.
Thevolumewillbecontrolledbyan<input/>element:
<inputtype="range"id="volumeController"
min="0"max="1"step=".1"value="1"/>
It’sarangecontrol,andit’ssettoaminimumvalueof0,amaximumvalueof1,andthestepis.1.Itsinitialvalueissetto1,meaningfullvolume.
IntheJavaScriptcode,youretrievethiselementandstoreitinthevolumeSlidervariable:
varvolumeSlider=document.getElementById("volumeController");
Andyouregisteraninputeventlistener:
volumeSlider.addEventListener("input",volumeInput);
ThevolumeInput()functionhandlesthisevent,anditisresponsibleforsettingthemedia’svolumetotheslider’scorrespondingvalue:
functionvolumeInput(e){
video.volume=volumeSlider.value;
}
Exercise2QuestionAddanotherrangeformcontroltoQuestion1’sanswer,andprogramittoseekthemedia.Itshouldalsoupdateasthemediaplays.Usethedurationchangeeventtosettheslider’smaxvalue,andthetimeupdateeventtoupdatetheslider’svalue.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter15:Question2</title>
</head>
<body>
<div>
<buttonid="playbackController">Play</button>
<buttonid="muteController">Mute</button>
<inputtype="range"id="volumeController"
min="0"max="1"step=".1"value="1"/>
</div>
<videoid="bbbVideo">
<sourcesrc="bbb.mp4"/>
<sourcesrc="bbb.webm"/>
</video>
<div>
<inputtype="range"id="seekController"
min="0"step="1"value="0"/>
</div>
<script>
functionpauseHandler(e){
playButton.innerHTML="Resume";
}
functionplayingHandler(e){
playButton.innerHTML="Pause";
}
functionvolumechangeHandler(e){
muteButton.innerHTML=video.muted?"Unmute":"Mute";
}
functiondurationchangeHandler(e){
seekSlider.max=video.duration;
}
functiontimeupdateHandler(e){
seekSlider.value=video.currentTime;
}
functionplaybackClick(e){
video.paused?video.play():video.pause();
}
functionmuteClick(e){
video.muted=!video.muted;
}
functionvolumeInput(e){
video.volume=volumeSlider.value;
}
functionseekInput(e){
video.currentTime=seekSlider.value;
}
varvideo=document.getElementById("bbbVideo");
varplayButton=document.getElementById("playbackController");
varmuteButton=document.getElementById("muteController");
varvolumeSlider=document.getElementById("volumeController");
varseekSlider=document.getElementById("seekController");
video.addEventListener("pause",pauseHandler);
video.addEventListener("playing",playingHandler);
video.addEventListener("volumechange",volumechangeHandler);
video.addEventListener("durationchange",durationchangeHandler);
video.addEventListener("timeupdate",timeupdateHandler);
playButton.addEventListener("click",playbackClick);
muteButton.addEventListener("click",muteClick);
volumeSlider.addEventListener("input",volumeInput);
seekSlider.addEventListener("input",seekInput);
</script>
</body>
</html>
Savethisasch15_question2.html.
Onceagain,thechangesarehighlighted.Youaddanotherrangecontroltothepage:
<div>
<inputtype="range"id="seekController"
min="0"step="1"value="0"/>
</div>
ThisoneiscalledseekController.Itissettoaminimumvalueof0,astepof1,andaninitialvalueof0.Amaximumvalueisnotsetbecauseyoudonotyetknowthedurationofthevideo.Youwill,however,whenthemedia’sdurationchangeeventfires.Youregisteralistenerforthisevent;itcallsthedurationchangeHandler()functionwhenitfires.
functiondurationchangeHandler(e){
seekSlider.max=video.duration;
}
Itsimplysetstheslider’smaxpropertytothemedia’sduration.
Youalsoregisteralistenerforthemedia’stimeupdateeventwiththetimeupdateHandler()function.Youusethistoupdatetheslider’svaluewhenthemedia’scurrenttimechanges:
functiontimeupdateHandler(e){
seekSlider.value=video.currentTime;
}
Butyoualsowanttocontrolthemedia’sseekwiththeslider,soyoulistenfortherangecontrol’sinputevent:
functionseekInput(e){
video.currentTime=seekSlider.value;
CHAPTER16
Exercise1QuestionExample1isbasedonChapter10’sExample17,andasyouprobablyremember,youmodifiedthatexampleinresponsetooneofChapter10’sexercisequestions.Modifythischapter’sExample1sothatonlyonetabisactiveatatime.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter16:Question1</title>
<style>
.tabStrip{
background-color:#E4E2D5;
padding:3px;
height:22px;
}
.tabStripdiv{
float:left;
font:14pxarial;
cursor:pointer;
}
.tabStrip-tab{
padding:3px;
}
.tabStrip-tab-hover{
border:1pxsolid#316AC5;
background-color:#C1D2EE;
padding:2px;
}
.tabStrip-tab-click{
border:1pxsolid#facc5a;
background-color:#f9e391;
padding:2px;
}
</style>
</head>
<body>
<divclass="tabStrip">
<divdata-tab-number="1"class="tabStrip-tab">Tab1</div>
<divdata-tab-number="2"class="tabStrip-tab">Tab2</div>
<divdata-tab-number="3"class="tabStrip-tab">Tab3</div>
</div>
<divid="descContainer"></div>
<scriptsrc="jquery-2.1.1.min.js"></script>
<script>
varactiveTab=null;
functionhandleEvent(e){
vartarget=$(e.target);
vartype=e.type;
if(type=="mouseover"||type=="mouseout"){
target.toggleClass("tabStrip-tab-hover");
}elseif(type=="click"){
if(activeTab){
activeTab.removeClass("tabStrip-tab-click");
}
target.addClass("tabStrip-tab-click");
varnum=target.attr("data-tab-number");
showDescription(num);
activeTab=target;
}
}
functionshowDescription(num){
vartext="DescriptionforTab"+num;
$("#descContainer").text(text);
}
$(".tabStrip>div").on("mouseovermouseoutclick",handleEvent);
</script>
</body>
</html>
Savethisasch16_question1.html.
TheoveralllogicofthissolutionisidenticaltoChapter10’sSolution3.Youdefineavariabletotracktheactivetab:
varactiveTab=null;
Thenwhentheuserclicksoneofthetabs,youremovethetabStrip-tab-clickCSSclassfromtheactivetab(ifoneexists):
if(activeTab){
activeTab.removeClass("tabStrip-tab-click");
}
Andthenyousetthecurrenttabastheactivetab:
activeTab=target;
Exercise2QuestionThereissomerepetitivecodeinExample2.Refactorthecodetoreducetheduplication.Additionally,addafunctiontohandleanyerrorsthatmayoccurwiththerequest.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter16:Question2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<form>
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td>
<aid="usernameAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td>
<aid="emailAvailability"href="#">Check
Availability</a>
</td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputtype="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="jquery-2.1.1.min.js"></script>
<script>
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("#username").val();
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
makeRequest({
username:userValue
});
}
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("#email").val();
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
makeRequest({
email:emailValue
});
}
functionmakeRequest(parameters){
$.getJSON("ch14_formvalidator.php",parameters)
.done(handleResponse)
.fail(handleError);
}
functionhandleError(){
alert("Anetworkerroroccurred.Pleasetryagain"+
"inafewmoments.");
}
functionhandleResponse(response){
if(response.available){
alert(response.searchTerm+"isavailable!");
}else{
alert("We'resorry,but"+response.searchTerm+
"isnotavailable.");
}
}
$("#usernameAvailability").on("click",checkUsername);
$("#emailAvailability").on("click",checkEmail);
</script>
</body>
</html>
Savethisasch16_question2.html.
Themainsourceofduplicationisthecodethatmakestheactualrequest:
$.getJSON("ch14_formvalidator.php",parms).done(handleResponse);
Althoughit’sasinglelineofcode,itcanbemovedintoaseparatefunctiontomakeiteasiertomaintain.Plus,whenyouaddafunctionforhandlingAjaxerrors,youhavetovisitonlyonefunctionasopposedtotwo.
FirstwriteafunctionthatdisplaysamessagetotheuserwhentheAjaxrequestfails.CallithandleError():
functionhandleError(){
alert("Anetworkerroroccurred.Pleasetryagain"+
"inafewmoments.");
}
NowwriteafunctionthatperformstheAjaxrequest,andchainafail()calltodone():
functionmakeRequest(parameters){
$.getJSON("ch14_formvalidator.php",parameters)
.done(handleResponse)
.fail(handleError);
}
YoucannowusethismakeRequest()functioninsidethecheckUsername()function:
functioncheckUsername(e){
e.preventDefault();
varuserValue=$("#username").val();
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
makeRequest({
username:userValue
});
}
AndthecheckEmail()function:
functioncheckEmail(e){
e.preventDefault();
varemailValue=$("#email").val();
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
makeRequest({
email:emailValue
});
}
Youcanalsoeliminatetheparmsvariableinbothofthefunctions,asshowninthissolution.JustpasstheobjectliteraldirectlytomakeRequest()tomakeyourcodemoreconcise.
CHAPTER17
Exercise1QuestionModifytheanswertoChapter14’sQuestion2usingPrototype.AlsoadderrorreportingforwhenanerroroccurswiththeAjaxrequest.
Exercise1Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Question1</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<formname="theForm">
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td></td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td></td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputid="btnSubmit"type="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="prototype.1.7.2.js"></script>
<script>
functionbtnSubmitClick(e){
e.preventDefault();
checkUsername();
}
functioncheckUsername(){
varuserValue=$("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varoptions={
method:"get",
onSuccess:handleUsernameResponse,
onFailure:handleError,
parameters:{
username:userValue
}
};
newAjax.Request("ch14_formvalidator.php",options);
}
functioncheckEmail(){
varemailValue=$("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varoptions={
method:"get",
onSuccess:handleEmailResponse,
onFailure:handleError,
parameters:{
email:emailValue
}
};
newAjax.Request("ch14_formvalidator.php",options);
}
functionhandleUsernameResponse(transport){
varresponse=transport.responseJSON;
if(!response.available){
alert("Theusername"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
checkEmail();
}
functionhandleEmailResponse(transport){
varresponse=transport.responseJSON;
if(!response.available){
alert("Theemailaddress"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
document.theForm.submit();
}
functionhandleError(){
alert("Anetworkerroroccurred.Pleasetryagain"+
"inafewmoments.");
}
$("btnSubmit").observe("click",btnSubmitClick);
</script>
</body>
</html>
Savethisasch17_question1.html.
ThissolutionisbasedonChapter14’sSolution2,butthecodehaschangedtousePrototype’sAPI.There’salsoanewfunctioncalledhandleError()forhandlingerrors:
functionhandleError(){
alert("Anetworkerroroccurred.Pleasetry"+
"againinafewmoments.");
}
ThisfunctioniscalledhandleError(),anditsimplydisplaysamessagetotheuser.You’llassignthisfunctiontotheonFailureoptionwhenyoumakeyourAjaxrequests.
MakingarequestismanymorelinesofcodeduetoPrototype’sAjaxAPI:
varoptions={
method:"get",
onSuccess:handleEmailResponse,
onFailure:handleError,
parameters:{
email:emailValue
}
};
newAjax.Request("ch14_formvalidator.php",options);
ThisexcerptistakenfromcheckUsername().Youcreateyouroptionsobjectcontainingthemethod,onSuccess,onFailure,andparametersproperties,andthenyouissuetherequest.
Onasuccessfulrequest,thehandleUsernameResponse()andhandleEmailResponse()functionsexecute.TheynolongermanuallyparsetheJSONdataintoaJavaScriptobject;instead,theyusetheresponseJSONproperty:
varresponse=transport.responseJSON;
Andfinally,youregisterthebutton’sclickeventlistenerusingtheobserve()method:
$("btnSubmit").observe("click",btnSubmitClick);
Exercise2QuestionIfyouguessedthatthisquestionwouldbe:“ChangetheanswertoChapter14’sQuestion2usingMooTools,andadderrorreportingforwhenanerroroccurswiththeAjaxrequest”thenyouwon!!Yourprizeis…completingtheexercise.
Exercise2Solution<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter17:Question2</title>
<style>
.fieldname{
text-align:right;
}
.submit{
text-align:right;
}
</style>
</head>
<body>
<formname="theForm">
<table>
<tr>
<tdclass="fieldname">
Username:
</td>
<td>
<inputtype="text"id="username"/>
</td>
<td></td>
</tr>
<tr>
<tdclass="fieldname">
Email:
</td>
<td>
<inputtype="text"id="email"/>
</td>
<td></td>
</tr>
<tr>
<tdclass="fieldname">
Password:
</td>
<td>
<inputtype="text"id="password"/>
</td>
<td/>
</tr>
<tr>
<tdclass="fieldname">
VerifyPassword:
</td>
<td>
<inputtype="text"id="password2"/>
</td>
<td/>
</tr>
<tr>
<tdcolspan="2"class="submit">
<inputid="btnSubmit"type="submit"value="Submit"/>
</td>
<td/>
</tr>
</table>
</form>
<scriptsrc="mootools-core-1.5.1-compressed.js"></script>
<script>
functionbtnSubmitClick(e){
e.preventDefault();
checkUsername();
}
functioncheckUsername(){
varuserValue=$("username").value;
if(!userValue){
alert("Pleaseenterausernametocheck!");
return;
}
varoptions={
url:"ch14_formvalidator.php",
data:{
username:userValue
},
onSuccess:handleUsernameResponse,
onFailure:handleError
};
newRequest.JSON(options).get();
}
functioncheckEmail(){
varemailValue=$("email").value;
if(!emailValue){
alert("Pleaseenteranemailaddresstocheck!");
return;
}
varoptions={
url:"ch14_formvalidator.php",
data:{
email:emailValue
},
onSuccess:handleEmailResponse,
onFailure:handleError
};
newRequest.JSON(options).get();
}
functionhandleUsernameResponse(response){
if(!response.available){
alert("Theusername"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
checkEmail();
}
functionhandleEmailResponse(response){
if(!response.available){
alert("Theemailaddress"+response.searchTerm+
"isunavailable.Tryanother.");
return;
}
document.theForm.submit();
}
functionhandleError(){
alert("Anetworkerroroccurred.Pleasetryagain"+
"inafewmoments.");
}
$("btnSubmit").addEvent("click",btnSubmitClick);
</script>
</body>
</html>
CHAPTER18
Exercise1QuestionTheexamplech18_example4.htmlhasadeliberatebug.Foreachtimestableitcreatesonlymultiplierswithvaluesfrom1to11.
Usethescriptdebuggertoworkoutwhythisishappening,andthencorrectthebug.
Exercise1SolutionTheproblemiswiththecode’slogicratherthanitssyntax.Logicerrorsaremuchhardertospotanddealwithbecause,unlikewithsyntaxerrors,thebrowserwon’tinformyouthatthere’ssuchandsucherroratlinesoandsobutinsteadjustfailstoworkasexpected.Theerroriswiththisline:
for(varcounter=1;counter<12;counter++)
Youwantthelooptogofrom1to12inclusive.Yourcounter<12statementwillbetrueuptoandincluding11butwillbefalsewhenthecounterreaches12;hence12getsleftoff.Tocorrectthis,youcouldchangethecodetothefollowing:
for(varcounter=1;counter<=12;counter++)
Exercise2QuestionThefollowingcodecontainsanumberofcommonerrors.Seeifyoucanspotthem:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Question2</title>
</head>
<body>
<formname="form1"action="">
<inputtype="text"id="text1"name="text1"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>
<br/>
<inputtype="text"id="text2"name="text2"/>
<p>
<inputtype="submit"value="Submit"id="submit1"
name="submit1"/>
</p>
</form>
<script>
functioncheckForm(e){
varelementCount=0;
vartheForm=document.form1;
while(elementCount=<=theForm.length){
if(theForm.elements[elementcount].type=="text"){
if(theForm.elements[elementCount].value()="")
alert("Pleasecompleteallformelements");
theForm.elements[elementCount].focus;
e.preventDefault();
break;
}
}
}
document.form1.addEventListener("submit",checkForm);
</script>
</body>
</html>
Exercise2SolutionThebug-freeversionlookslikethis:
<!DOCTYPEhtml>
<htmllang="en">
<head>
<title>Chapter18:Question2</title>
</head>
<body>
<formname="form1"action="">
<inputtype="text"id="text1"name="text1"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox2"name="checkbox2"/>
<br/>
CheckBox1<inputtype="checkbox"id="checkbox1"name="checkbox1"/>
<br/>
<inputtype="text"id="text2"name="text2"/>
<p>
<inputtype="submit"value="Submit"id="submit1"
name="submit1"/>
</p>
</form>
<script>
functioncheckForm(e){
varelementCount=0;
vartheForm=document.form1;
while(elementCount<theForm.length){
if(theForm.elements[elementCount].type=="text"){
if(theForm.elements[elementCount].value==""){
alert("Pleasecompleteallformelements");
theForm.elements[elementCount].focus();
e.preventDefault();
break;
}
}
elementCount++;
}
}
document.form1.addEventListener("submit",checkForm);
</script>
</body>
</html>
Let’slookateacherrorinturn.Thefirsterrorisalogicerror:
while(elementCount=<theForm.length)
Arraysstartat0sothefirstelementobjectisatindexarray0,thesecondat1,andsoon.Thelastobjecthasanindexvalueof4.However,theForm.lengthwillreturn5becausetherearefiveelementsintheform.SothewhileloopwillcontinueuntilelementCountislessthanorequalto5,butbecausethelastelementhasanindexof4,thisisonepastthelimit.Youshouldwriteeitherthis:
while(elementCount<theForm.length)
orthis:
while(elementCount<=theForm.length-1)
Eitherisfine,thoughthefirstisshorter.
Youcometoyourseconderrorinthefollowingline:
if(theForm.elements[elementcount].type=="text")
Onaquickglanceitlooksfine,butit’sJavaScript’sstrictnessoncasesensitivitythathascausedthedownfall.ThevariablenameiselementCount,notelementcountwithalowercasec.Sothislineshouldreadasfollows:
if(theForm.elements[elementCount].type=="text")
Thenextlinewithanerroristhis:
if(theForm.elements[elementCount].value()="")
Thishastwoerrors.First,valueisapropertyandnotamethod,sothereisnoneedforparenthesesafterit.Second,youhavetheall-timeclassicerrorofoneequalssigninsteadoftwo.Rememberthatoneequalssignmeans“Makeitequalto,”andtwoequalssignsmean“Checkifitisequalto.”Sowiththechanges,thelineis:
if(theForm.elements[elementCount].value=="")
Thenexterroristhefailuretoputyourblockofifcodeincurlybraces.EventhoughJavaScriptwon’tthrowanerrorbecausethesyntaxisfine,thelogicisnotsofine,andyou
won’tgettheresultsyouexpect.Withthebraces,theifstatementshouldbeasfollows:
if(theForm.elements[elementCount].value==""){
alert("Pleasecompleteallformelements")
theForm.elements[elementCount].focus;
formValid=false;
break;
}
Thepenultimateerrorisinthisline:
theForm.elements[elementCount].focus;
Thistimeyouhaveamethodbutwithnoparenthesesafterit.Evenmethodsthathavenoparametersmusthavetheemptyparenthesesafterthemifyouintendtoexecutethatmethod.So,corrected,thelineisasfollows:
theForm.elements[elementCount].focus();
Nowyou’realmostdone;thereisjustonemoreerror.Thistimeit’snotsomethingwrongwithwhat’sthere,butrathersomethingveryimportantthatshouldbetherebutismissing.Whatisit?It’sthis:
elementCount++;
Thislineshouldbeinyourwhileloop,otherwiseelementCountwillnevergoabove0andthewhileloop’sconditionwillalwaysbetrue,resultingintheloopcontinuingforever:aclassicinfiniteloop.
BJavaScriptCoreReferenceThisappendixoutlinesthesyntaxofalltheJavaScriptcorelanguagefunctionsandobjectswiththeirpropertiesandmethods.Ifchangeshaveoccurredbetweenversions,theyhavebeennoted.
BROWSERREFERENCEThefollowingtableoutlineswhichJavaScriptversionisinuseandinwhichbrowseritisused.NotethatearlierversionsofInternetExplorerimplementedJscript,Microsoft’sversionofJavaScript.However,Jscript’sfeaturesarerelativelythesameasJavaScript.
JAVASCRIPTVERSION
MOZILLAFIREFOX
INTERNETEXPLORER
CHROME SAFARI OPERA
1.0 3.01.11.21.3 4.01.41.5 1.0 5.5,6,7,8 1–10 3-5 6,7,8,91.6 1.51.7 2.0 281.8 3.0 11.51.8.1 3.51.8.2 3.61.8.5 4 9 32 6 11.6
RESERVEDWORDSVariouswordsandsymbolsarereservedbyJavaScript.Thesewordscannotbeusedasvariablenames,norcanthesymbolsbeusedwithinthem.Theyarelistedinthefollowingtable.
abstract boolean break
byte case catch
char class const
continue debugger default
delete do double
else enum export
extends false final
finally float for
function goto if
implements import in
instanceof int interface
let long native
new null package
private protected public
return short static
super switch synchronized
this throw throws
transient true try
typeof var void
volatile while with
- ! ~
% / *
> < =
& ^ |
+ ?
OtherIdentifierstoAvoidItisbesttoavoidtheuseofthefollowingidentifiersasvariablenames.
JavaScript1.0absacosanchorasinatanatan2bigblinkboldceilcharAtcommentcosDate
EescapeevalexpfixedfloorfontcolorfontsizegetDategetDaygetHours
getMinutesgetMonthgetSecondsgetTimegetTimezoneOffsetgetYearindexOf
isNaNitalicslastIndexOflinklogLOG10ELOG2ELN10LN2Mathmaxmin
ObjectparseparseFloatparseIntPIpowrandomround,setDatesetHours
setMinutessetMonthsetSecondssetTimesetYearsinslicesmallsqrtSQRT1_2
SQRT2strikeStringsubsubstrsubstringsuptantoGMTStringtoLocaleString
toLowerCasetoUpperCaseunescapeUTC
JavaScript1.1callerclassNameconstructorjavaJavaArrayJavaClassJavaObject
JavaPackagejoinlengthMAX_VALUEMIN_VALUENaNNEGATIVE_INFINITYnetscape
NumberPOSITIVE_INFINITYprototypereversesortsplitsuntoStringvalueOf
JavaScript1.2aritycalleecharCodeAtcompileconcatexecfromCharCodeglobalignoreCase
indexinputlabellastIndexlastMatchlastParenleftContextmatchmultiline
NumberPackagespoppushRegExpreplacerightContextsearchshiftslice
splicesourceStringtestunshiftunwatchwatch
JavaScript1.3applycallgetFullYeargetMillisecondsgetUTCDategetUTCDaygetUTCFullYear
getUTCHoursgetUTCMillisecondsgetUTCMinutesgetUTCMonthgetUTCSeconds
InfinityisFiniteNaNsetFullYearsetMillisecondssetUTCDatesetUTCFullYear
setUTCHourssetUTCMillisecondssetUTCMinutessetUTCMonthsetUTCSeconds
toSourcetoUTCStringundefined
JAVASCRIPTOPERATORSThefollowingsectionslistthevariousoperatorsavailabletoyouinJavaScript.
AssignmentOperatorsAssignmentoperatorsallowyoutoassignavaluetoavariable.Thefollowingtableliststhedifferentassignmentoperatorsyoucanuse.
NAME INTRODUCED MEANINGAssignment JavaScript1.0 Setsvariablev1tothe
valueofvariablev2.varv1=v2;
ShorthandadditionorShorthandconcatenationsameasv1=v1+v2
JavaScript1.0 v1+=v2
Shorthandsubtractionsameasv1=v1−v2
JavaScript1.0 v1−=v2
Shorthandmultiplicationsameasv1=v1*v2
JavaScript1.0 v1*=v2
Shorthanddivisionsameasv1=v1/v2 JavaScript1.0 v1/=v2
Shorthandmodulussameasv1=v1%v2 JavaScript1.0 v1%=v2
Shorthandleft-shiftsameasv1=v1<<v2
JavaScript1.0 v1<<=v2
Shorthandright-shiftsameasv1=v1>>v2
JavaScript1.0 v1>>=v2
Shorthandzero-fillright-shiftsameasv1=v1>>>v2
JavaScript1.0 v1>>>=v2
ShorthandANDsameasv1=v1&v2 JavaScript1.0 v1&=v2
ShorthandXORsameasv1=v1^v2 JavaScript1.0 v1^=v2
ShorthandORsameasv1=v1|v2 JavaScript1.0 v1|=v2
ComparisonOperatorsComparisonoperatorsallowyoutocompareonevariableorvaluewithanother.Anycomparisonstatementreturnsabooleanvalue.
NAME INTRODUCED MEANING
Equal JavaScript1.0 v1==v2
Trueiftwooperandsarestrictlyequalorequaloncecasttothesametype.
Notequal JavaScript1.0 v1!=v2
Trueiftwooperandsarenotstrictlyequalornotequaloncecasttothesametype.
Greaterthan JavaScript1.0 v1>v2
Trueifleft-handside(LHS)operandisgreaterthanright-handside(RHS)operand.
Greaterthanorequalto
JavaScript1.0 v1>=v2
TrueifLHSoperandisgreaterthanorequaltoRHSoperand.
Lessthan JavaScript1.0 v1<v2
TrueifLHSoperandislessthanRHSoperand.
Lessthanorequalto
JavaScript1.0 v1<=v2
TrueifLHSoperandislessthanorequaltoRHSoperand.
Strictlyequal JavaScript1.3 v1===v2
Trueifoperandsareequalandofthesametype.
Notstrictlyequal
JavaScript1.3 v1!==v2
Trueifoperandsarenotstrictlyequal.
ArithmeticOperatorsArithmeticoperatorsallowyoutoperformarithmeticoperationsbetweenvariablesorvalues.
NAME INTRODUCED MEANING
Addition JavaScript1.0 v1+v2
Sumofv1andv2.(Concatenationofv1andv2,ifeitheroperandisastring.)
Subtraction JavaScript1.0 v1−v2
Differencebetweenv1andv2.
Multiplication JavaScript1.0 v1*v2
Productofv1andv2.
Division JavaScript1.0 v1/v2
Quotientofv2intov1.
Modulus JavaScript1.0 v1%v2
Integerremainderofdividingv1byv2
.
Prefixincrement
JavaScript1.0 ++v1*v2(v1+1)*v2
Note:v1willbeleftasv1+1.
Postfixincrement
JavaScript1.0 v1++*v2(v1*v2)
v1isthenincrementedby1.
Prefixdecrement
JavaScript1.0 --v1*v2(v1–1)*v2Note:v1isleftasv1-1.
Postfixdecrement
JavaScript1.0 v1—*v2(v1*v2)
v1isthendecrementedby1.
BitwiseOperatorsBitwiseoperatorsworkbyconvertingvaluesinv1andv2to32-bitbinarynumbersandthencomparingtheindividualbitsofthesetwobinarynumbers.Theresultisreturnedasanormaldecimalnumber.
NAME INTRODUCED MEANING
BitwiseAND
JavaScript1.0 v1&v2
ThebitwiseANDlinesupthebitsineachoperandandperformsanANDoperationbetweenthetwobitsinthesameposition.Ifbothbitsare1,theresultingbitinthispositionofthereturnednumberis1.Ifeitherbitis0,theresultingbitinthispositionofthereturnednumberis0.
BitwiseOR
JavaScript1.0 v1|v2
ThebitwiseORlinesupthebitsineachoperandandperformsanORoperationbetweenthetwobitsinthesameposition.Ifeitherbitis1,theresultingbitinthispositionofthereturnednumberis1.Ifbothbitsare0,theresultingbitinthispositionofthereturnednumberis0.
BitwiseXOR
JavaScript1.0 v1^v2
ThebitwiseXORlinesupthebitsineachoperandandperformsanXORoperationbetweenthetwobitsinthesameposition.Theresultingbitinthispositionis1onlyifonebitfrombothoperandsis1.Otherwise,theresultingbitinthispositionofthereturnednumberis0.
BitwiseNOT
JavaScript1.0 v1~v2
Invertsallthebitsinthenumber.
BitwiseShiftOperatorsTheseworkbyconvertingvaluesinv1to32-bitbinarynumbersandthenmovingthebitsinthenumbertotheleftortherightbythespecifiednumberofplaces.
NAME INTRODUCED MEANING
Left-shift JavaScript1.0 v1<<v2
Shiftsv1totheleftbyv2places,fillingthenewgapsinwithzeros.
Sign-propagatingright-shift
JavaScript1.4 v1>>v2
Shiftsv1totherightbyv2places,ignoringthebitsshiftedoffthenumber.
Zero-fillright-shift
JavaScript1.0 v1>>>v2
Shiftsv1totherightbyv2places,ignoringthebitsshiftedoffthenumberandaddingv2zerostotheleftofthenumber.
LogicalOperatorsTheseshouldreturnoneofthebooleanliterals,trueorfalse.However,thismaynothappenifv1orv2isneitherabooleanvaluenoravaluethateasilyconvertstoabooleanvalue,suchas0,1,null,theemptystring,orundefined.
NAME INTRODUCED MEANING
LogicalAND
JavaScript1.0 v1&&v2
Returnstrueifbothv1andv2aretrue,orfalseotherwise.Willnotevaluatev2ifv1isfalse.
LogicalOR
JavaScript1.0 v1││v2
Returnsfalseifbothv1andv2arefalse,ortrueifoneoperandistrue.Willnotevaluatev2ifv1istrue.
LogicalNOT
JavaScript1.0 !v1
Returnsfalseifv1istrue,ortrueotherwise.
ObjectOperators
JavaScriptprovidesanumberofoperatorstoworkwithobjects.Thefollowingtableliststhem.
NAME INTRODUCED MEANING
delete JavaScript1.2 deleteobj
Deletesanobject,oneofitsproperties,ortheelementofanarrayatthespecifiedindex.Alsodeletesvariablesnotdeclaredwiththevarkeyword.
in JavaScript1.4 for(propinsomObj)
ReturnstrueifsomeObjhasthenamedproperty.
instanceof JavaScript1.4 someObjinstanceofObjType
ReturnstrueifsomeObjisoftypeObjType;otherwise,returnsfalse.
new JavaScript1.0 newObjType()
CreatesanewinstanceofanobjectwithtypeObjType.
this JavaScript1.0 this.property
Referstothecurrentobject.
MiscellaneousOperatorsThefollowingtablelistsmiscellaneousoperators.
NAME INTRODUCED MEANING
Conditionaloperator
JavaScript1.0 (evalquery)?v1:v2
Ifevalqueryistrue,theoperatorreturnsv1;otherwiseitreturnsv2.
Commaoperator
JavaScript1.0 varv3=(v1+2,v2*2)
Evaluatesbothoperandswhiletreatingthetwoasoneexpression.Returnsthevalueofthesecondoperand.Inthisexample,v3holdstheresultingvalueofv2*2.
typeof JavaScript1.1 typeofv1
Returnsastringholdingthetypeofv1,whichisnotevaluated.
void JavaScript1.1 void(eva1)
Evaluateseval1butdoesnotreturnavalue.
OperatorPrecedenceDoes1+2*3=1+(2*3)=7ordoesitequal(1+2)*3=9?
Operatorprecedencedeterminestheorderinwhichoperatorsareevaluated.Forexample,themultiplicativeoperator(*)hasahigherprecedencethantheadditiveoperator(+).Therefore,thecorrectanswertothepreviousquestionis:
1+(2*3)
ThefollowingtableliststheoperatorprecedenceinJavaScriptfromhighesttolowest.Thethirdcolumnexplainswhethertoread1+2+3+4as((1+2)+3)+4(lefttoright)or1+(2+(3+(4)))(righttoleft).
OPERATORTYPE
OPERATORS EVALUATIONORDERFORLIKEELEMENTS
Member .or[] LefttorightCreateinstance
new Righttoleft
Functioncall () LefttorightIncrement ++ N/aDecrement -- N/aLogicalnot ! RighttoleftBitwisenot ~ RighttoleftUnary+ + RighttoleftUnary– – RighttoleftTypeof typeof RighttoleftVoid void RighttoleftDelete delete RighttoleftMultiplication * LefttorightDivision / LefttorightModulus % LefttorightAddition + LefttorightSubtraction − LefttorightBitwiseshift <<,>>,>>> LefttorightRelational <,<=,>,>= LefttorightIn in LefttorightInstanceof instanceof LefttorightEquality ==,!=,===,!=== LefttorightBitwiseAND & LefttorightBitwiseXOR ^ LefttorightBitwiseOR | LefttorightLogicalAND && LefttorightLogicalOR ││ LefttorightConditional ?: RighttoleftAssignment =,+=,-=,*=,/=,%=,<<=,>>=,
>>>=,&=,^=,|=
Righttoleft
Comma , Lefttoright
JAVASCRIPTSTATEMENTSThefollowingtablesdescribecoreJavaScriptstatements.
BlockJavaScriptblocksstartwithanopeningcurlybrace({)andendwithaclosingcurlybrace(}).Blockstatementsaremeanttomakethecontainedsinglestatementsexecutetogether,suchasthebodyofafunctionoracondition.
STATEMENT INTRODUCED DESCRIPTION{} JavaScript1.5 Usedtogroupstatementsasdelimitedbythecurly
brackets.
ConditionalThefollowingtablelistsconditionalstatementsforJavaScriptaswellastheversioninwhichtheywereintroduced.
STATEMENT INTRODUCED DESCRIPTIONif JavaScript1.2 Executesablockofcodeifaspecifiedconditionis
true.else JavaScript1.2 Thesecondhalfofanifstatement.Executesablock
ofcodeiftheresultoftheifstatementisfalse.switch JavaScript1.2 Specifiesvariousblocksofstatementstobeexecuted
dependingonthevalueoftheexpressionpassedinastheargument.
DeclarationsThesekeywordsdeclarevariablesorfunctionsinJavaScriptcode.
STATEMENT INTRODUCED DESCRIPTIONvar JavaScript1.0 Usedtodeclareavariable.Initializingittoavalueis
optionalatthetimeofdeclaration.function JavaScript1.0 Usedtodeclareafunctionwiththespecified
parameters,whichcanbestrings,numbers,orobjects.Toreturnavalue,thefunctionmustusethereturnstatement.
LoopLoopsexecuteablockofcodewhileaspecifiedconditionistrue.
STATEMENT INTRODUCED DESCRIPTIONdo…while JavaScript1.2 Executesthestatementsspecifieduntilthetest
conditionafterthewhileevaluatestofalse.Thestatementsareexecutedatleastoncebecausethetestconditionisevaluatedlast.
for JavaScript1.0 Createsaloopcontrolledaccordingtothethreeoptionalexpressionsenclosedintheparenthesesaftertheforandseparatedbysemicolons.Thefirstofthesethreeexpressionsistheinitial-expression,thesecondisthetestcondition,andthethirdistheincrement-expression.
for…in JavaScript1.0 Usedtoiterateoverallthepropertiesofanobjectusingavariable.Foreachpropertythespecifiedstatementswithintheloopareexecuted.
while JavaScript1.0 Executesablockofstatementsifatestconditionevaluatestotrue.Theloopthenrepeats,testingtheconditionwitheachrepeat,ceasingiftheconditionevaluatestofalse.
break JavaScript1.0 Usedwithinawhileorforlooptoterminatetheloopandtransferprogramcontroltothestatementfollowingtheloop.Canalsobeusedwithalabeltobreaktoaparticularprogrampositionoutsideoftheloop.
label JavaScript1.2 Anidentifierthatcanbeusedwithbreakorcontinuestatementstoindicatewheretheprogramshouldcontinueexecutionaftertheloopexecutionisstopped.
ExecutionControlStatementsCodeexecutioniscontrolledinavarietyofways.Inadditiontotheconditionalandloopstatements,thefollowingstatementsalsocontributetoexecutioncontrol.
STATEMENT INTRODUCED DESCRIPTIONcontinue JavaScript1.0 Usedtostopexecutionoftheblockofstatementsinthe
currentiterationofawhileorforloop;executionoftheloopcontinueswiththenextiteration.
return JavaScript1.0 Usedtospecifythevaluetobereturnedbyafunction.with JavaScript1.0 Specifiesthedefaultobjectforablockofcode.
ExceptionHandlingStatementsErrorsareanaturalpartofprogramming,andJavaScriptprovidesyouwiththemeanstocatcherrorsandhandlethemgracefully.
STATEMENT INTRODUCED DESCRIPTIONThrow JavaScript1.4 Throwsacustomexceptiondefinedbytheuser.try…catch…
finally
JavaScript1.4 Executesthestatementsinthetryblock;ifanyexceptionsoccur,thesearehandledinthecatchblock.Thefinallyblockallowsyoutostipulatestatementsthatwillbeexecutedafterboththetryandcatchstatements.
OtherStatementsThefollowingtablelistsotherJavaScriptstatementsandwhentheywereintroduced.
STATEMENT INTRODUCED DESCRIPTION//singleline
comment
JavaScript1.0 Singlelinesofnotesthatareignoredbythescriptengineandthatcanbeusedtoexplainthecode.
/*multi-line
comment*/
JavaScript1.0 Multiplelinesofnotesthatareignoredbythescriptengineandthatcanbeusedtoexplainthecode.
TOP-LEVELPROPERTIESANDFUNCTIONSThesearecorepropertiesandfunctions,whicharenotassociatedwithanylower-levelobject,althoughintheterminologyusedbyECMAScriptandbyJscript,theyaredescribedaspropertiesandmethodsoftheglobalobject.
Thetop-levelpropertieswereintroducedinJavaScript1.3,butinpreviousversions,InfinityandNaNexistedaspropertiesoftheNumberobject.
Top-LevelProperties
PROPERTY INTRODUCED DESCRIPTIONInfinity JavaScript1.3 Returnsinfinity.NaN JavaScript1.3 Returnsavaluethatisnotanumber.undefined JavaScript1.3 Indicatesthatavaluehasnotbeenassignedtoavariable.
Top-LevelFunctions
FUNCTION INTRODUCED DESCRIPTIONdecodeURI() JavaScript1.5 UsedtodecodeaURIencodedwith
encodeURI().decodeURIcomponent() JavaScript1.5 UsedtodecodeaURIencodedwith
encodeURIComponent().encodeURI() JavaScript1.5 Usedtocomposeanewversionofacomplete
URI,replacingeachinstanceofcertaincharacters.ItisbasedontheUTF-8encodingofthecharacters.
encodeURIComponent() JavaScript1.5 UsedtocomposeanewversionofacompleteURIbyreplacingeachinstanceofthespecifiedcharacterwithescapesequences.RepresentationisviatheUTFencodingofthecharacters.
escape() JavaScript1.0 UsedtoencodeastringintheISOLatin-1characterset;forexample,toaddtoaURL.
eval() JavaScript1.0 ReturnstheresultoftheJavaScriptcode,whichispassedinasastringparameter.
isFinite() JavaScript1.3 Indicateswhethertheargumentisafinitenumber.
isNaN() JavaScript1.1 Indicatesiftheargumentisnotanumber.Number() JavaScript1.2 Convertsanobjecttoanumber.parseFloat() JavaScript1.0 Parsesastringandreturnsitasafloating-
pointnumber.parseInt() JavaScript1.0 Parsesastringandreturnsitasaninteger.An
optionalsecondparameterspecifiesthebaseofthenumbertobeconverted.
String() JavaScript1.2 Convertsanobjecttoastring.unescape() JavaScript1.0 ReturnstheASCIIstringforthespecified
hexadecimalencodingvalue.
JAVASCRIPTCOREOBJECTSThissectiondescribestheobjectsavailableintheJavaScriptcorelanguageandtheirmethodsandproperties.
ArrayTheArrayobjectrepresentsanarrayofvariables.ItwasintroducedinJavaScript1.1.AnArrayobjectcanbecreatedwiththeArrayconstructor:
varobjArray=newArray(10);//anarrayof11elements
varobjArray=newArray("1","2","4");//anarrayof3elements
Arrayscanalsobecreatedusingarrayliteralsyntax:
varobjArray=[];
Literalsyntaxisthepreferredmethodofcreatinganarray.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.length JavaScript1.1 Returnsthenumberofelementsinthearray.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.
NOTESquarebrackets([])surroundingaparametermeansthatparameterisoptional.
Methods
METHOD INTRODUCED DESCRIPTIONconcat(value1[,
value2,...])
JavaScript1.2 Concatenatestwoarraysandreturnsthenewarraythusformed.
every(testFn(element,
index,array))
JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.Returnstrueifalliterationsreturntrue.Otherwise,itreturnsfalse.
filter(testFn(element,
index,array))
JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.ReturnsanewarrayofelementsthatpasstestFn().
foreach(fn(element,
index,array))
JavaScript1.6 Iteratesoverthearray,executingfn()oneveryelement.
indexOf(element[,
startIndex])JavaScript1.6 Returnsanindexofthespecifiedelementif
found,or-1ifnotfound.StartsatstartIndexifspecified.
join([separator]) JavaScript1.1 Joinsalltheelementsofanarrayintoasinglestringdelimitedbyaseparatorifspecified.
lastIndexOf(element[,
startIndex])
JavaScript1.6 Searchesanarraystartingatthelastelementandmovesbackwards.Returnsanindexofthespecifiedelementiffound,or–1ifnotfound.StartsatstartIndexifspecified.
map(fn(element,index,
array))
JavaScript1.6 Iteratesoverthearray,executingfn()oneveryelement.Returnsanewarraybasedontheoutcomeoffn().
pop() JavaScript1.2 Popsthelastelementfromtheendofthearrayandreturnsthatelement.
push(value1[,value2,
...])
JavaScript1.2 Pushesoneormoreelementsontotheendofthearrayandreturnsthenewlengthofthearray.Thearray’snewlengthisreturned.
reverse() JavaScript1.1 Reversestheorderoftheelementsinthearray,sothefirstelementbecomesthelastandthelastbecomesthefirst.
shift() JavaScript1.2 Removesthefirstelementfromthebeginningofthearrayandreturnsthatelement.
slice(startIndex[,
endIndex])
JavaScript1.2 Returnsasliceofthearraystartingatthestartindexandendingattheelementbeforetheendindex.
some(testFn(element,
index,array))
JavaScript1.6 Iteratesoverthearray,executingtestFn()oneveryelement.ReturnstrueifatleastoneresultoftestFn()istrue.
sort([sortFn(a,b)]) JavaScript1.1 Sortstheelementsofthearray.ExecutessortFn()forsortingifitisprovided.
splice(startIndex[,
length,value1,...)
JavaScript1.2 RemovestheamountofelementsdenotedbylengthstartingatstartIndex.Providedvaluesreplacethedeletedelements.Returnsthedeletedelements.
toString() JavaScript1.1 ConvertstheArrayobjectintoastring.unshift(value1[,
value2,...])
JavaScript1.2 Addselementstothebeginningofthearrayandreturnsthenewlength.
valueOf() JavaScript1.1 Returnstheprimitivevalueofthearray.
BooleanTheBooleanobjectisusedasawrapperforabooleanvalue.ItwasintroducedinJavaScript1.1.ItiscreatedwiththeBooleanconstructor,whichtakesasaparametertheinitialvaluefortheobject(ifthisisnotabooleanvalue,itwillbeconvertedintoone).
Falseyvaluesarenull,undefined,"",and0.Allothervaluesareconsideredtruthy.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Specifiesthefunctionthatcreatesanobject’sprototype.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONtoString() JavaScript1.1 ConvertstheBooleanobjectintoastring.valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheBooleanobject.
DateTheDateobjectisusedtorepresentagivendate-time.ItwasintroducedinJavaScript1.0.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONgetDate() JavaScript1.0 Retrievesthedateinthemonth
fromtheDateobject.getDay() JavaScript1.0 Retrievesthedayoftheweek
fromtheDateobject.getFullYear() JavaScript1.3 Retrievesthefullyearfromthe
Dateobject.getHours() JavaScript1.0 Retrievesthehouroftheday
fromtheDateobject.getMilliseconds() JavaScript1.3 Retrievesthenumberof
millisecondsfromtheDateobject.
getMinutes() JavaScript1.0 RetrievesthenumberofminutesfromtheDateobject.
getMonth() JavaScript1.0 RetrievesthemonthfromtheDateobject.
getSeconds() JavaScript1.0 RetrievesthenumberofsecondsfromtheDateobject.
getTime() JavaScript1.0 RetrievesthenumberofmillisecondssinceJanuary1,197000:00:00fromtheDateobject.
getTimezoneOffset() JavaScript1.0 Retrievesthedifferenceinminutesbetweenthelocaltimezoneanduniversaltime(UTC).
getUTCDate() JavaScript1.3 RetrievesthedateinthemonthfromtheDateobjectadjustedtouniversaltime.
getUTCDay() JavaScript1.3 RetrievesthedayoftheweekfromtheDateobjectadjustedtouniversaltime.
getUTCFullYear() JavaScript1.3 RetrievestheyearfromtheDateobjectadjustedtouniversaltime.
getUTCHours() JavaScript1.3 RetrievesthehourofthedayfromtheDateobjectadjustedtouniversaltime.
getUTCMilliseconds() JavaScript1.3 RetrievesthenumberofmillisecondsfromtheDateobjectadjustedtouniversaltime.
getUTCMinutes() JavaScript1.3 RetrievesthenumberofminutesfromtheDateobjectadjustedtouniversaltime.
getUTCMonth() JavaScript1.3 RetrievesthemonthfromtheDateobjectadjustedtouniversaltime.
getUTCSeconds() JavaScript1.3 RetrievesthenumberofsecondsfromtheDateobjectadjustedtouniversaltime.
getYear() JavaScript1.0 RetrievestheyearfromtheDateobject.
parse(dateString) JavaScript1.0 Retrievesthenumberofmillisecondsinadatesince
January1,197000:00:00,localtime.
setDate(dayOfMonth) JavaScript1.0 SetsthedateinthemonthfortheDateobject.
setFullYear(year[,month,day]) JavaScript1.3 SetsthefullyearfortheDateobject.
setHours(hours[,minutes,
seconds,milliseconds])
JavaScript1.0 SetsthehourofthedayfortheDateobject.
setMilliseconds(milliseconds) JavaScript1.3 SetsthenumberofmillisecondsfortheDateobject.
setMinutes(minutes[,seconds,
milliseconds])
JavaScript1.0 SetsthenumberofminutesfortheDateobject.
setMonth(month[,day]) JavaScript1.0 SetsthemonthfortheDateobject.
setSeconds(seconds[,
milliseconds])
JavaScript1.0 SetsthenumberofsecondsfortheDateobject.
setTime(milliseconds) JavaScript1.0 SetsthetimefortheDateobjectaccordingtothenumberofmillisecondssinceJanuary1,197000:00:00.
setUTCDate(dayOfMonth) JavaScript1.3 SetsthedateinthemonthfortheDateobjectaccordingtouniversaltime.
setUTCFullYear(year[,month,
day])
JavaScript1.3 SetsthefullyearfortheDateobjectaccordingtouniversaltime.
setUTCHours(hours[,minutes,
seconds,milliseconds])
JavaScript1.3 SetsthehourofthedayfortheDateobjectaccordingtouniversaltime.
setUTCMilliseconds(milliseconds) JavaScript1.3 SetsthenumberofmillisecondsfortheDateobjectaccordingtouniversaltime.
setUTCMinutes(mintes[,seconds,
milliseconds])
JavaScript1.3 SetsthenumberofminutesfortheDateobjectaccordingtouniversaltime.
setUTCMonth(month[,day]) JavaScript1.3 SetsthemonthfortheDateobjectaccordingtouniversaltime.
setUTCSeconds() JavaScript1.3 SetsthenumberofsecondsfortheDateobjectaccordingtouniversaltime.
setYear(year) JavaScript1.0 SetstheyearfortheDateobject.DeprecatedinfavorofsetFullYear().
toGMTString() JavaScript1.0 ConvertstheDateobjecttoastringaccordingtoGreenwichMeanTime.ReplacedbytoUTCString.
toLocaleString() JavaScript1.0 ConvertstheDateobjecttoastringaccordingtothelocaltimezone.
toString() JavaScript1.1 ConvertstheDateobjectintoastring.
toUTCString() JavaScript1.3 ConvertstheDateobjecttoastringaccordingtouniversaltime.
UTC(year,month[,day,hours,
minutes,seconds,milliseconds])
JavaScript1.0 RetrievesthenumberofmillisecondsinadatesinceJanuary1,197000:00:00,universaltime.
valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheDateobject.
FunctionIntroducedinJavaScript1.1,aFunctionobjectiscreatedwiththeFunctionconstructor.
Functionscanbedefinedinavarietyofways.Youcancreateafunctionusingthefollowingstandardfunctionstatement:
functionfunctionName(){
//codehere
}
Youcanalsocreateananonymousfunctionandassignittoavariable.Thefollowingcodedemonstratesthisapproach:
varfunctionName=function(){
//codehere
};
Thetrailingsemicolonisnotatypobecausethisstatementisanassignmentoperation,andallassignmentoperationsshouldendwithasemicolon.
Functionsareobjects,andthustheyhaveaconstructor.It’spossibletocreateafunctionusingtheFunctionobject’sconstructorasshowninthefollowingcode:
varfunctionName=newFunction("arg1","arg2","returnarg1+arg2");
Thefirstargumentstotheconstructorarethenamesofthefunction’sparameters—youcanaddasmanyparametersasyouneed.Thelastparameteryoupasstotheconstructoristhefunction’sbody.Thepreviouscodecreatesafunctionthatacceptstwoargumentsandreturnstheirsum.
ThereareveryfewinstanceswhereyouwillusetheFunctionconstructor.Itispreferredtodefineafunctionusingthestandardfunctionstatementorbycreatingananonymousfunctionandassigningittoavariable.
Properties
PROPERTY INTRODUCED DESCRIPTIONarguments JavaScript1.1 Anarraycontainingtheparameterspassedintothe
function.arguments.length JavaScript1.1 Returnsthenumberofparameterspassedintothe
function.constructor JavaScript1.1 Usedtoreferencetheconstructorfunctionforthe
object.length JavaScript1.1 Returnsthenumberofparametersexpectedbythe
function.Thisdiffersfromarguments.length,whichreturnsthenumberofparametersactuallypassedintothefunction.
prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeusedtoextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONapply(thisObj,
arguments)
JavaScript1.3 CallsafunctionormethodasifitbelongedtothisObjandpassesargumentstothefunctionormethod.argumentsmustbeanarray.
call(thisObj,
arg1,...)
JavaScript1.3 Identicaltoapply(),exceptargumentsarepassedindividuallyinsteadofinanarray.
toString() JavaScript1.1 ConvertstheFunctionobjectintoastring.valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheFunctionobject.
JSONTheJSONobjectcontainsmethodsforparsingJavaScriptObjectNotation(JSON)intoobjectsandserializingJavaScriptobjectsintoJSON.IntroducedinJavaScript1.8.5,theJSONobjectisatop-levelobject,whichcanbeaccessedwithoutaconstructor.
Methods
METHOD INTRODUCED DESCRIPTIONparse(json) JavaScript1.8.5 TransformsJSONintoaJavaScriptobjectorvalue.stringify(obj) JavaScript1.8.5 TransformsaJavaScriptobjectorvalueintoJSON.
MathTheMathobjectprovidesmethodsandpropertiesusedformathematicalcalculations.IntroducedinJavaScript1.0,theMathobjectisatop-levelobject,whichcanbeaccessedwithoutaconstructor.
Properties
PROPERTY INTRODUCED DESCRIPTIONE JavaScript1.0 ReturnsEuler’sconstant(thebaseofnaturallogarithms;
approximately2.718).LN10 JavaScript1.0 Returnsthenaturallogarithmof10(approximately
2.302).LN2 JavaScript1.0 Returnsthenaturallogarithmof2(approximately
0.693).LOG10E JavaScript1.0 ReturnstheBase10logarithmofE(approximately
0.434).LOG2E JavaScript1.0 ReturnstheBase2logarithmofE(approximately
1.442).PI JavaScript1.0 Returnspi,theratioofthecircumferenceofacircleto
itsdiameter(approximately3.142).SQRT1_2 JavaScript1.0 Returnsthesquarerootof1/2(approximately0.707).SQRT2 JavaScript1.0 Returnsthesquarerootof2(approximately1.414).
Methods
METHOD INTRODUCED DESCRIPTIONabs(x) JavaScript1.0 Returnstheabsolute(positive)valueofanumber.acos(x) JavaScript1.0 Returnsthearccosineofanumber(inradians).asin(x) JavaScript1.0 Returnsthearcsineofanumber(inradians).atan(x) JavaScript1.0 Returnsthearctangentofanumber(inradians).atan2(y,
x)
JavaScript1.0 Returnstheangle(inradians)betweenthex-axisandthepositionrepresentedbytheyandxcoordinatespassedinasparameters.
ceil(x) JavaScript1.0 Returnsthevalueofanumberroundeduptothenearestinteger.
cos(x) JavaScript1.0 Returnsthecosineofanumber.exp(x) JavaScript1.0 ReturnsEtothepoweroftheargumentpassedin.floor(x) JavaScript1.0 Returnsthevalueofanumberroundeddowntothenearest
integer.log(x) JavaScript1.0 Returnsthenaturallogarithm(baseE)ofanumber.max(a,b) JavaScript1.0 Returnsthegreateroftwonumberspassedinas
parameters.min(a,b) JavaScript1.0 Returnsthelesseroftwonumberspassedinasparameters.pow(x,y) JavaScript1.0 Returnsthefirstparameterraisedtothepowerofthe
second.random() JavaScript1.1 Returnsapseudo-randomnumberbetween0and1.round(x) JavaScript1.0 Returnsthevalueofanumberroundedupordowntothe
nearestinteger.sin(x) JavaScript1.0 Returnsthesineofanumber.sqrt(x) JavaScript1.0 Returnsthesquarerootofanumber.tan(x) JavaScript1.0 Returnsthetangentofanumber.
NumberTheNumberobjectactsasawrapperforprimitivenumericvalues.IntroducedinJavaScript1.1,aNumberobjectiscreatedusingtheNumberconstructorwiththeinitialvalueforthenumberpassedinasaparameter.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionforthe
object.MAX_VALUE JavaScript1.1 Returnsthelargestnumberthatcanbe
representedinJavaScript(approximately1.79E+308).
MIN_VALUE JavaScript1.1 ReturnsthesmallestnumberthatcanberepresentedinJavaScript(5E–324).
NaN JavaScript1.1 Returnsavaluethatis“notanumber.”NEGATIVE_INFINITY JavaScript1.1 Returnsavaluerepresentingnegativeinfinity.POSITIVE_INFINITY JavaScript1.1 Returnsavaluerepresenting(positive)infinity.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbe
usedtoextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONtoExponential(fractionDigits) JavaScript1.5 Returnsastringcontainingthe
exponentnotationofanumber.Theparametershouldbebetween0and20anddeterminesthenumberofdigitsafterthedecimal.
toFixed([digits]) JavaScript1.5 Theformatnumberfordigitsnumberofdigits.Thenumberisroundedup,and0sareaddedafterthedecimalpointtoachievethedesireddecimallength.
toPrecision([precision]) JavaScript1.5 ReturnsastringrepresentingtheNumberobjecttothespecifiedprecision.
toString() JavaScript1.1 ConvertstheNumberobjectintoastring.
valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheNumberobject.
ObjectObjectistheprimitivetypeforJavaScriptobjects,fromwhichallotherobjectsaredescended(thatis,allotherobjectsinheritthemethodsandpropertiesoftheObjectobject).IntroducedinJavaScript1.0,youcancreateanObjectobjectusingtheObjectconstructorasfollows:
varobj=newObject();
Youcanalsocreateanobjectusingobjectliteralnotationlikethis:
varobj={};
Literalnotationisthepreferredmethodofcreatinganobject.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONhasOwnProperty(propertyName) JavaScript1.5 Checkswhetherthespecified
propertyisinherited.Returnstrueifnotinherited;falseifinherited.
isPrototypeOf(obj) JavaScript1.5 Determinesifthespecifiedobjectistheprototypeofanotherobject.
propertyIsEnumerable(propertyName) JavaScript1.5 Determinesifthespecifiedpropertycanbeseenbyaforinloop.
toString() JavaScript1.0 ConvertstheObjectobjectintoastring.
valueOf() JavaScript1.1 ReturnstheprimitivevalueoftheObjectobject.
RegExpTheRegExpobjectisusedtofindpatternswithinstringvalues.RegExpobjectscanbecreatedintwoways:usingtheRegExpconstructororatextliteral.ItwasintroducedinJavaScript1.2.
Someofthepropertiesinthefollowingtablehavebothlongandshortnames.TheshortnamesarederivedfromthePerlprogramminglanguage.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.2 Usedtoreferencetheconstructorfunctionfortheobject.global JavaScript1.2 Indicateswhetherallpossiblematchesinthestringareto
bemade,oronlythefirst.Correspondstothegflag.ignoreCase JavaScript1.2 Indicateswhetherthematchistobecase-insensitive.
Correspondstotheiflag.input JavaScript1.2 Thestringagainstwhichtheregularexpressionis
matched.lastIndex JavaScript1.2 Thepositioninthestringfromwhichthenextmatchis
tobestarted.multiline JavaScript1.2 Indicateswhetherstringsaretobesearchedacross
multiplelines.Correspondswiththemflag.prototype JavaScript1.2 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.source JavaScript1.2 Thetextofthepatternfortheregularexpression.
Methods
METHOD INTRODUCED DESCRIPTIONexec(stringToSearch) JavaScript1.2 Executesasearchforamatchinthestring
parameterpassedin.test(stringToMatch) JavaScript1.2 Testsforamatchinthestringparameter
passedin.toString() JavaScript1.2 ConvertstheRegExpobjectintoastring.valueOf() JavaScript1.2 ReturnstheprimitivevalueoftheRegExp
object.
SpecialCharactersUsedinRegularExpressions
CHARACTER EXAMPLES FUNCTION\ /n/matchesn;/\n/
matchesalinefeedcharacter;/^/matchesthestartofaline;and/\^/matches^.
Forcharactersthatarebydefaulttreatedasnormalcharacters,thebackslashindicatesthatthenextcharacteristobeinterpretedwithaspecialvalue.Forcharactersthatareusuallytreatedasspecialcharacters,thebackslashindicatesthatthenextcharacteristobeinterpretedasanormalcharacter.
^ /^A/matchesthefirstbutnotthesecondAin“AmancalledAdam.”
Matchesthestartofalineoroftheinput.
$ /r$/matchesonlythelastrin“horror.”
Matchestheendofalineoroftheinput.
* /ro*/matchesrin“right,”roin“wrong,”and“roo”in“room.”
Matchestheprecedingcharacterzeroormoretimes.
+ /l+/matcheslin“life,”llin“still,”andlllin“stilllife.”
Matchestheprecedingcharacteroneormoretimes.Forexample,/a+/matchestheain“candy”andalltheasin“caaaaaaandy.”
? /Smythe?/matches“Smyth”and“Smythe.”
Matchestheprecedingcharacteronceorzerotimes.
. /.b/matchesthesecondbutnotthefirstobin“blob.”
Matchesanycharacterapartfromthenewlinecharacter.
(x) /(Smythe?)/matches“Smyth”and“Smythe”in“JohnSmythandRobSmythe”andallowsthesubstringstoberetrievedasRegExp.$1andRegExp.$2,respectively.
Matchesxandremembersthematch.Thematchedsubstringcanberetrievedfromtheelementsofthearraythatresultsfromthematch,orfromtheRegExpobject’sproperties$1,$2…$9,orlastParen.
x|y /Smith|Smythe/
matches“Smith”and“Smythe.”
Matcheseitherxory(wherexandyareblocksofcharacters).
{n} /l{2}/matchesllin“still”andthefirsttwolsin“stilllife.”
Matchesexactlyninstancesoftheprecedingcharacter(wherenisapositiveinteger).
{n,} /l{2,}/matchesllin“still”andlllin“stilllife.”
Matchesnormoreinstancesoftheprecedingcharacter(wherenisapositiveinteger).
{n,m} /l{1,2}/matcheslin“life,”llin“still,”andthefirsttwolsin“stilllife.”
Matchesbetweennandminstancesoftheprecedingcharacter(wherenandmarepositiveintegers).
[xyz] [ab]matchesaandb;[a-c]matchesa,bandc.
Matchesanyoneofthecharactersinthesquarebrackets.Arangeofcharactersinthealphabetcanbematchedusingahyphen.
[^xyz] [^aeiouy]matchessin“easy”;[^a-y]matcheszin“lazy.”
Matchesanycharacterexceptthoseenclosedinthesquarebrackets.Arangeofcharactersinthealphabetcanbespecifiedusingahyphen.
[\b] Matchesabackspace.\b /t\b/matchesthefirstt
in“abouttime.”Matchesawordboundary(forexample,aspaceortheendofaline).
\B /t\Bi/matchestiin Matcheswhenthereisnowordboundaryin
“itistime.” thisposition.\cX /\cA/matchesCtrl+A. Matchesacontrolcharacter.\d /IE\d/matchesIE4,
IE5,etc.Matchesadigitcharacter.Thisisidenticalto[0-9].
\D /\D/matchesthedecimalpointin“3.142.”
Matchesanycharacterthatisnotadigit.Thisisidenticalto[^0-9].
\f Matchesaform-feedcharacter.\n Matchesaline-feedcharacter.\r Matchesacarriagereturncharacter.\s /\s/matchesthespace
in“notnow.”Matchesanywhitespacecharacter,includingspace,tab,line-feed,etc.Thisisidenticalto[\f\n\r\t\v].
\S /\S/matchesain“a.” Matchesanycharacterotherthanawhitespacecharacter.Thisisidenticalto[^\f\n\r\t\v].
\t Matchesatabcharacter.\v Matchesaverticaltabcharacter.\w /\w/matchesOin“O?!”
and1in“$1.”Matchesanyalphanumericcharacterortheunderscore.Thisisidenticalto[A-Za-z0-9_].
\W /\W/matches$in“$10million”and@in“j_smith@wrox.”
Matchesanynon-alphanumericcharacter(excludingtheunderscore).Thisisidenticalto[^A-Za-z0-9_].
()\n /(Joh?n)and\1/matchesJohnandJohnin“JohnandJohn'sfriend”butdoesnotmatch“JohnandJon.”
Matchesthelastsubstringthatmatchedthenthmatchplacedinparenthesesandremembered(wherenisapositiveinteger).
\octal\xhex /\x25/matches%. Matchesthecharactercorrespondingtothespecifiedoctalorhexadecimalescapevalue.
StringTheStringobjectisusedtocontainastringofcharacters.ItwasintroducedinJavaScript1.0.Thismustbedistinguishedfromastringliteral,butthemethodsandpropertiesoftheStringobjectcanalsobeaccessedbyastringliteral,becauseatemporaryobjectwillbecreatedwhentheyarecalled.
TheHTMLmethodsinthelasttablearenotpartofanyECMAScriptstandard,buttheyhavebeenpartoftheJavaScriptlanguagesinceversion1.0.TheycanbeusefulbecausetheydynamicallygenerateHTML.
Properties
PROPERTY INTRODUCED DESCRIPTIONconstructor JavaScript1.1 Usedtoreferencetheconstructorfunctionfortheobject.length JavaScript1.0 Returnsthenumberofcharactersinthestring.prototype JavaScript1.1 Returnstheprototypefortheobject,whichcanbeused
toextendtheobject’sinterface.
Methods
METHOD INTRODUCED DESCRIPTIONcharAt(index) JavaScript1.0 Returnsthecharacteratthespecifiedposition
inthestring.charCodeAt(index) JavaScript1.2 ReturnstheUnicodevalueofthecharacterat
thespecifiedpositioninthestring.concat(value1,
value2,...)
JavaScript1.2 Concatenatesthestringssuppliedasargumentsandreturnsthestringthusformed.
fromCharCode(value1,
value2,...)
JavaScript1.2 ReturnsthestringformedfromtheconcatenationofthecharactersrepresentedbythesuppliedUnicodevalues.
indexOf(substr[,
startIndex])
JavaScript1.0 ReturnsthepositionwithintheStringobjectofthefirstmatchforthesuppliedsubstring.Returns-1ifthesubstringisnotfound.StartsthesearchatstartIndexifspecified.
lastIndexOf(substr
[,startIndex])
JavaScript1.0 ReturnsthepositionwithintheStringobjectofthelastmatchforthesuppliedsubstring.Returns-1ifthesubstringisnotfound.StartsthesearchatstartIndexifspecified.
match(regexp) JavaScript1.2 Searchesthestringforamatchtothesuppliedpattern.Returnsanarrayornullifnotfound.
replace(regexp,
newValue)
JavaScript1.2 Usedtoreplaceasubstringthatmatchesaregularexpressionwithanewvalue.
search(regexp) JavaScript1.2 Searchesforamatchbetweenaregularexpressionandthestring.Returnstheindexofthematch,or-1ifnotfound.
slice(startIndex[,
endIndex])
JavaScript1.0 ReturnsasubstringoftheStringobject.
split(delimiter) JavaScript1.1 SplitsaStringobjectintoanarrayofstringsbyseparatingthestringintosubstrings.
substr(startIndex[,
length])
JavaScript1.0 Returnsasubstringofthecharactersfromthegivenstartingpositionandcontainingthespecifiednumberofcharacters.
substring(startIndex
[,endIndex])
JavaScript1.0 Returnsasubstringofthecharactersbetweentwopositionsinthestring.ThecharacteratendIndexisnotincludedinthesubstring.
toLowerCase() JavaScript1.0 Returnsthestringconvertedtolowercase.toUpperCase() JavaScript1.0 Returnsthestringconvertedtouppercase.
HTMLMethods
METHOD INTRODUCED DESCRIPTIONanchor(name) JavaScript1.0 Returnsthestringsurroundedby<a>...</a>tags
withthenameattributeassignedthepassedparameter.
big() JavaScript1.0 Enclosesthestringin<big>…</big>tags.blink() JavaScript1.0 Enclosesthestringin<blink>…</blink>tags.bold() JavaScript1.0 Enclosesthestringin<b>…</b>tags.fixed() JavaScript1.0 Enclosesthestringin<tt>…</tt>tags.fontcolor(color) JavaScript1.0 Enclosesthestringin<font>…</font>tagswith
thecolorattributeassignedaparametervalue.fontsize(size) JavaScript1.0 Enclosesthestringin<font>…</font>tagswith
thesizeattributeassignedaparametervalue.italics() JavaScript1.0 Enclosesthestringin<i>…</i>tags.link(url) JavaScript1.0 Enclosesthestringin<a>…</a>tagswiththe
hrefattributeassignedaparametervalue.small() JavaScript1.0 Enclosesthestringin<small>…</small>tags.strike() JavaScript1.0 Enclosesthestringin<strike>…</strike>tags.sub() JavaScript1.0 Enclosesthestringin<sub>…</sub>tags.sup() JavaScript1.0 Enclosesthestringin<sup>…</sup>tagsand
causesastringtobedisplayedassuperscript.
CW3CDOMReferenceBecauseJavaScriptisprimarilyusedtoprogramthebrowserandaddbehaviortowebpages,it’sonlynaturaltoincludeareferencetotheW3CDOM.
ThefollowingpageslisttheobjectsmadeavailablebytheW3CDOM.
DOMCOREOBJECTSThissectiondescribesandlistsobjectsdefinedbytheDOMstandards—startingwiththelowestlevelofDOMobjects.Allobjectsareinalphabeticalorder.
Low-LevelDOMObjectsTheDOMspecificationdescribestheNode,NodeList,andNamedNodeMapobjects.Thesearethelowest-levelobjectsintheDOM,andaretheprimarybuildingblocksofhigher-levelobjects.
NodeDefinedinDOMLevel1,theNodeobjectistheprimarydatatypefortheentireDOM.AllobjectsintheDOMinheritfromNode.Thereare12differenttypesofNodeobjects;eachtypehasanassociatedintegervalue.ThefollowingtableslisttheNodeobject’stypevalues,properties,andmethods.
NodeTypes
TYPENAME INTEGERVALUE
INTRODUCED ASSOCIATEDDATATYPE
ELEMENT_NODE 1 Level1 Element
ATTRIBUTE_NODE 2 Level1 Attr
TEXT_NODE 3 Level1 Text
CDATA_SECTION_NODE 4 Level1 CDATASection
ENTITY_REFERENCE_NODE 5 Level1 EntityReference
ENTITY_NODE 6 Level1 Entity
PROCESSING_INSTRUCTION_NODE 7 Level1 ProcessingInstruction
COMMENT_NODE 8 Level1 Comment
DOCUMENT_NODE 9 Level1 Document
DOCUMENT_TYPE_NODE 10 Level1 DocumentType
DOCUMENT_FRAGMENT_NODE 11 Level1 DocumentFragment
NOTATION_NODE 12 Level1 Notation
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
attributes ANamedNodeMapcontainingtheattributesofthisnodeifitisanElement,ornullotherwise.
Level1
childNodes ANodeListcontainingallchildrenofthisnode. Level1firstChild Getsthefirstchildofthisnode.Returnsnullifno
childexists.Level1
lastChild Getsthelastchildofthisnode.Returnsnullifnochildexists.
Level1
localName Returnsthelocalpartofthenode’squalifiedname(thepartafterthecolonofthequalifiednamewhennamespacesareused).UsedprimarilyinXMLDOMs.
Level2
namespaceURI ThenamespaceURIofthenode,ornullifnotspecified.
Level2
nextSibling Getsthenodeimmediatelyfollowingthisnode.Returnsnullifnofollowingsiblingexists.
Level1
nodeName Getsthenameofthisnode. Level1nodeType Anintegerrepresentingthetypeofthisnode.See
previoustable.Level1
nodeValue Getsthevalueofthisnode,dependingonthetype. Level1ownerDocument GetstheDocumentobjectthisnodeiscontainedin.
IfthisnodeisaDocumentnode,itreturnsnull.Level1
parentNode Getstheparentnodeofthisnode.ReturnsnullfornodesthatarecurrentlynotintheDOMtree.
Level1
prefix Returnsthenamespaceprefixofthisnode,ornullifnotspecified.
Level2
previousSibling Getsthenodeimmediatelybeforethisnode.Returnsnullifnoprevioussibling.
Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDappendChild(newChild) AddsthenewChildtotheendofthelistof
children.Level1
cloneNode(deep) Returnsaduplicateofthenode.Thereturnednodehasnoparent.Ifdeepistrue,thisclonesallnodescontainedwithinthenode.
Level1
hasAttributes() Returnsabooleanvaluebasedonifthenodehasanyattributes(ifthenodeisanelement).
Level2
hasChildNodes() Returnsabooleanvaluebasedonwhetherthenodehasanychildnodes.
Level1
insertBefore(newChild,
refChild)
InsertsthenewChildnodebeforetheexistingchildreferencedbyrefChild.IfrefChildisnull,newChildisaddedattheendofthelistofchildren.
Level1
removeChild(oldChild) Removesthespecifiedchildnodeandreturnsit.
Level1
replaceChild(newChild,
oldChild)
ReplacesoldChildwithnewChildandreturnsoldChild.
Level1
NodeListTheNodeListobjectisanorderedcollectionofnodes.TheitemscontainedintheNodeListareaccessibleviaanindexstartingfrom0.
ANodeListisalivesnapshotofnodes.AnychangesmadetothenodeswithintheDOMareimmediatelyreflectedineveryreferenceoftheNodeList.
Properties
PROPERTYNAME DESCRIPTION INTRODUCEDlength Thenumberofnodesinthelist. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
item(index) Returnstheitematthespecifiedindex.Returnsnulliftheindexisgreaterthanorequaltothelist’slength.
Level1
NamedNodeMapObjectsreferredtoasNamedNodeMapsrepresentcollectionsofnodesthatcanbeaccessedbyname.ThisobjectdoesnotinheritfromNodeList.Anelement’sattributelistisanexampleofaNamedNodeMap.
Properties
PROPERTYNAME DESCRIPTION INTRODUCEDlength Thenumberofnodesinthemap. Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDgetNamedItem(name) Retrievesanodebythespecifiedname. Level1removeNamedItem(name) Removesanitembythespecifiedname. Level1setNamedItem(node) AddsanodetothelistbyusingitsnodeName
propertyasitskey.Level1
High-LevelDOMObjectsTheseobjectsinheritNodeandarethebasisforevenhigher-levelDOMobjectsasspecifiedbytheHTMLDOM.Theseobjectsmirrorthedifferentnodetypes.
Thefollowingobjectsarelistedinalphabeticalorder.TheCDATASection,Comment,DocumentType,Entity,EntityReference,Notation,andProcessingInstructionobjectsarepurposefullyomittedfromthissection.
AttrTheAttrobjectrepresentsanElementobject’sattribute.EventhoughAttrobjectsinheritfromNode,theyarenotconsideredchildrenoftheelementtheydescribe,andthusarenotpartoftheDOMtree.TheNodepropertiesofparentNode,previousSibling,andnextSiblingreturnnullforAttrobjects.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
ownerElement ReturnstheElementobjecttheattributeisattachedto.
Level2
name Returnsthenameoftheattribute. Level1value Returnsthevalueoftheattribute. Level1
DocumentTheDocumentobjectrepresentstheentireHTMLorXMLdocument.Itistherootofthedocumenttree.TheDocumentisthecontainerforallnodeswithinthedocument,andeachNodeobject’sownerDocumentpropertypointstotheDocument.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
docType TheDocTypeobjectassociatedwiththisdocument.ReturnsnullforHTMLandXMLdocumentswithoutadocumenttypedeclaration.
Level1
documentElement Returnstherootelementofthedocument.ForHTMLdocuments,thedocumentElementisthe<html/>element.
Level1
implementation TheDOMImplementationobjectassociatedwiththeDocument.
Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDcreateAttribute(name) ReturnsanewAttrobject
withthespecifiedname.Level1
createAttributeNS(namespaceURI,
qualifiedName)
ReturnsanattributewiththegivenqualifiednameandnamespaceURI.NotforHTMLDOMs.
Level2
createComment(data) ReturnsanewCommentobjectwiththespecifieddata.
Level1
createCDATASection(data) ReturnsanewCDATASectionobjectwhosevalueisthespecifieddata.
Level1
createDocumentFragment() ReturnsanemptyDocumentFragmentobject.
Level1
createElement(tagName) ReturnsanewElementobjectwiththespecifiedtagname.
Level1
createElementNS(namespaceURI,
qualifiedName)
ReturnsanelementofthespecifiedqualifiednameandnamespaceURI.NotforHTMLDOMs.
Level2
createTextNode(text) ReturnsanewTextobjectcontainingthespecifiedtext.
Level1
getElementById(elementId) ReturnstheElementwiththespecifiedIDvalue.Returnsnulliftheelementdoesnotexist.
Level2
getElementsByTagName(tagName) ReturnsaNodeListofallElementobjectswiththespecifiedtagnameintheorderinwhichtheyappearintheDOMtree.
Level1
getElementsByTagNameNS(namespaceURI,
localName)
ReturnsaNodeListofallelementswiththespecifiedlocalnameandnamespaceURI.ElementsreturnedareintheordertheyappearintheDOM.
Level2
importNode(importedNode,deep) Importsanodefromanotherdocument.Thesourcenodeisnotalteredorremovedfromitsdocument.Acopyofthesourceiscreated.Ifdeepistrue,allchildnodesoftheimportednodeareimported.Iffalse,onlythenodeisimported.
Level2
DocumentFragmentTheDocumentFragmentobjectisalightweightDocumentobject.Itsprimarypurposeisefficiency.MakingmanychangestotheDOMtree,suchasappendingseveralnodesindividually,isanexpensiveprocess.ItispossibletoappendNodeobjectstoaDocumentFragmentobject,whichallowsyoutoeasilyandefficientlyinsertallnodescontainedwithintheDocumentFragmentintotheDOMtree.
ThefollowingcodeshowstheuseofaDocumentFragment:
vardocumentFragment=document.createDocumentFragment();
for(vari=0;i<1000;i++){
varelement=document.createElement(“div”);
vartext=document.createTextNode(“Hereistestfordiv#”+i);
element.setAttribute(“id”,i);
documentFragment.appendChild(element);
}
document.body.appendChild(documentFragment);
WithouttheDocumentFragmentobject,thiscodewouldupdatetheDOMtree1,000times,thusdegradingperformance.WiththeDocumentFragmentobject,theDOMtreeisupdatedonlyonce.
TheDocumentFragmentobjectinheritstheNodeobject,andassuchhasNode’sproperties
andmethods.Itdoesnothaveanyotherpropertiesormethods.
ElementElementsarethemajorityofobjects,otherthantext,thatyouwillencounterintheDOM.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
tagName Returnsthenameoftheelement.ThesameasNode.nodeNameforthisnodetype.
Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDgetAttribute(name) Retrievestheattribute’s
valuebythespecifiedname.
Level1
getAttributeNS(namespaceURI,
localName)
ReturnstheAttrobjectbylocalnameandnamespaceURI.NotforHTMLDOMs.
Level2
getAttributeNode(name) ReturnstheAttrobjectassociatedwiththespecifiedname.Returnsnullifnoattributebythatnameexists.
Level1
getElementsByTagName(tagName) ReturnsaNodeListofalldescendantelementswiththespecifiedtagNameintheorderinwhichtheyappearinthetree.
Level1
getElementsByTagNameNS(namespaceURI,
localName)
ReturnsaNodeListofallthedescendantElementobjectswiththespecifiedlocalnameandnamespaceURI.NotforHTMLDOMs.
Level2
hasAttribute(name) Returnsabooleanvaluebasedonwhetherornottheelementhasanattributewiththespecifiedname.
Level2
hasAttributeNS(namespaceURI,
localName)
Returnsabooleanvaluebasedonwhetherthe
Level2
ElementhasanattributewiththegivenlocalnameandnamespaceURI.NotforHTMLDOMs.
querySelector(selector) Retrievesthefirstchildelementthatmatchesthespecifiedselector.
Level3
querySelectorAll(selector) Retrievesallchildelementsthatmatchthespecifiedselector.
Level3
removeAttribute(name) Removestheattributewiththespecifiedname.
Level1
removeAttributeNS(namespaceURI,
localName)
RemovesanattributespecifiedbythelocalnameandnamespaceURI.NotforHTMLDOMs.
Level2
removeAttributeNode(oldAttr) Removesandreturnsthespecifiedattribute.
Level1
setAttribute(name,value) Createsandaddsanewattribute,orchangesthevalueofanexistingattribute.Thevalueisasimplestring.
Level1
setAttributeNS(namespaceURI,
qualifiedName,value)
CreatesandaddsanewattributewiththespecifiednamespaceURI,qualifiedname,andvalue.
Level2
setAttributeNode(newAttr) Addsthespecifiedattributetotheelement.Replacestheexistingattributewiththesamenameifitexists.
Level1
setAttributeNodeNS(newAttr) Addsthespecifiedattributetotheelement.
Level2
TextTheTextobjectrepresentstextcontentofanElementorAttrobject.
Methods
METHODNAME DESCRIPTION INTRODUCEDsplitText(indexOffset) BreakstheTextnodeintotwonodesatthe
specifiedoffset.ThenewnodesstayintheDOMtreeassiblings.
Level1
HTMLDOMOBJECTSInordertoadequatelyinterfacewiththeDOM,theW3CextendstheDOMLevel1and2specificationstodescribeobjects,properties,andmethods,specifictoHTMLdocuments.
Mostoftheobjectsyou’llinterfacewithasafront-enddeveloperarecontainedinthissection.
MiscellaneousObjects:TheHTMLCollectionTheHTMLCollectionobjectisalistofnodes,muchlikeNodeList.ItdoesnotinheritfromNodeList,butHTMLCollectionsareconsideredlive,likeNodeLists,andareautomaticallyupdatedwhenchangesaremadetothedocument.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
length Returnsthenumberofelementsinthecollection.
Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
item(index) Returnstheelementatthespecifiedindex.Returnsnullifindexislargerthanthecollection’slength.
Level1
namedItem(name) Returnstheelementusinganame.Itfirstsearchesforanelementwithamatchingidattributevalue.Ifnonearefound,itsearchesforelementswithamatchingnameattributevalue.
Level1
HTMLDocumentObjects:TheHTMLDocumentTheHTMLDocumentobjectistherootofHTMLdocumentsandcontainstheentirecontent.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
anchors ReturnsanHTMLCollectionofall<a/>elementsinthedocumentthathaveavalueassignedtotheirnameattribute.
Level1
applets ReturnsanHTMLCollectionofall<applet/>elementsand<object/>elementsthatincludeappletsinthedocument.
Level1
body Returnstheelementthatcontainsthedocument’scontent.Returnsthe<body/>element,ortheoutermost<frameset/>elementdependingonthedocument.
Level1
cookie Returnsthecookiesassociatedwiththedocument.Returnsanemptystringifnone.
Level1
domain Returnsthedomainnameoftheserverthatservedthedocument.Returnsnullifthedomainnamecannotbeidentified.
Level1
forms ReturnsanHTMLCollectionofall<form/>elementsinthedocument.
Level1
images ReturnsanHTMLCollectionobjectcontainingall<img/>elementsinthedocument.
Level1
links ReturnsanHTMLCollectionofall<area/>and<a/>elements(withanhrefvalue)inthedocument.
Level1
referrer ReturnstheURLofthepagethatlinkedtothepage.Returnsanemptystringiftheusernavigateddirectlytothepage.
Level1
title Thetitleofthedocumentasspecifiedbythe<title/>elementinthedocument’s<head/>element.
Level1
URL ThecompleteURLofthedocument. Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDclose() Closesadocument. Level1getElementById(elementId) Returnstheelementwiththegiven
elementIdornullifnoelementcouldbefound.RemovedinDOMLevel2andaddedtotheDocumentobject.
Level1
getElementsByName(name) ReturnsanHTMLCollectionofelementswiththespecifiednameattributevalue.
Level1
open() Opensadocumentforwriting. Level1write() Writesastringoftexttothedocument. Level1writeln() Writesastringoftexttothedocument
followedbyanewline.Level1
HTMLElementObjectsHTMLelementattributesareexposedaspropertiesofthevariousHTMLelementobjects.Theirdatatypeisdeterminedbytheattribute’stypeintheHTML4.0specification.
OtherthanHTMLElement,allHTMLelementobjectsaredescribedhereinalphabeticalorder.ThefollowingpagesdonotcontainacompletelistofHTMLelementobjecttypes.Instead,onlythefollowingelementobjecttypesarelisted:
HTMLAnchorElement
HTMLBodyElement
HTMLButtonElement
HTMLDivElement
HTMLFormElement
HTMLFrameElement
HTMLFrameSetElement
HTMLIFrameElement
HTMLImageElement
HTMLInputElement
HTMLOptionElement
HTMLParagraphElement
HTMLSelectElement
HTMLTableCellElement
HTMLTableElement
HTMLTableRowElement
HTMLTableSectionElement
HTMLTextAreaElement
HTMLElementHTMLElementisthebaseobjectforallHTMLelements,muchlikehowNodeisthebaseobjectforallDOMnodes.Therefore,allHTMLelementshavethefollowingproperties.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
className Getsorsetsthevalueoftheelement’sclassattribute.
Level1
id Getsorsetsthevalueoftheelement’sidattribute. Level1
HTMLAnchorElementRepresentstheHTML<a/>element.
Properties
PROPERTYNAME DESCRIPTION INTRODUCEDaccessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1href Getsorsetsthevalueofthehrefattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1target Getsorsetthevalueofthetargetattribute. Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDblur() Removesthekeyboardfocusfromtheelement. Level1focus() Giveskeyboardfocustotheelement. Level1
HTMLBodyElementRepresentsthe<body/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
aLink Deprecated.Getsorsetsthevalueofthealinkattribute.
Level1
background Deprecated.Getsorsetsthevalueofthebackgroundattribute.
Level1
bgColor Deprecated.GetsorsetsthevalueofthebgColorattribute.
Level1
link Deprecated.Getsorsetsthevalueofthelinkattribute.
Level1
text Deprecated.Getsorsetsthevalueofthetextattribute.
Level1
vLink Deprecated.Getsorsetsthevalueofthevlinkattribute.
Level1
HTMLButtonElementRepresents<button/>elements.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthebutton.
Returnsnullifthebuttonisnotinsideaform.Level1
name Getsorsetsthevalueofthenameattribute. Level1type Getsthevalueofthetypeattribute. Level1value Getsorsetsthevalueofthevalueattribute. Level1
HTMLDivElementRepresentsthe<div/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
HTMLFormElementRepresentsthe<form/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
action Getsorsetsthevalueoftheactionattribute. Level1elements ReturnsanHTMLCollectionobjectcontainingallform
controlelementsintheform.Level1
enctype Getsorsetsthevalueoftheenctypeattribute. Level1length Returnsthenumberofformcontrolswithintheform. Level1method Getsorsetsthevalueofthemethodattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1target Getsorsetsthevalueofthetargetattribute. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
reset() Resetsallformcontrolelementscontainedwithintheformtotheirdefaultvalues.
Level1
submit() Submitstheform.Doesnotfirethesubmitevent. Level1
HTMLFrameElementRepresentsthe<frame/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
contentDocument GetstheDocumentobjectfortheframe.Returnsnullifoneisn’tavailable.
Level2
frameBorder GetsorsetsthevalueoftheframeBorderattribute. Level1marginHeight GetsorsetsthevalueofthemarginHeightattribute. Level1marginWidth GetsorsetsthevalueofthemarginWidthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1noResize GetsorsetsthevalueofthenoResizeattribute. Level1scrolling Getsorsetsthevalueofthescrollingattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1
HTMLFrameSetElementRepresentsthe<frameset/>element.
Properties
PROPERTYNAME DESCRIPTION INTRODUCEDcols Getsorsetsthevalueofthecolsattribute. Level1rows Getsorsetsthevalueoftherowsattribute. Level1
HTMLIFrameElementRepresentsthe<iframe/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
contentDocument GetstheDocumentobjectoftheframe.Returnsnullifonedoesn’texist.
Level2
frameBorder GetsorsetsthevalueoftheframeBorderattribute. Level1height Getsorsetsthevalueoftheheightattribute. Level1marginHeight GetsorsetsthevalueofthemarginHeightattribute. Level1marginWidth GetsorsetsthevalueofthemarginWidthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1noResize GetsorsetsthevalueofthenoResizeattribute. Level1scrolling Getsorsetsthevalueofthescrollingattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1width Getsorsetsthevalueofthewidthattribute. Level1
HTMLImageElementRepresentsthe<img/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
alt Getsorsetsthevalueofthealtattribute. Level1border Deprecated.Getsorsetsthevalueoftheborder
attribute.Level1
height Getsorsetsthevalueoftheheightattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1src Getsorsetsthevalueofthesrcattribute. Level1width Getsorsetsthevalueofthewidthattribute. Level1
HTMLInputElementRepresentsthe<input/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1align Deprecated.Getsorsetsthevalueofthealign
attribute.Level1
alt Getsorsetsthevalueofthealtattribute. Level1checked Usedwhentypeischeckboxorradio.Returnsa
booleanvaluedependingonwhetherornotthecheckboxorradiobuttonischecked.
Level1
defaultChecked Usedwhentypeischeckboxorradio.Getsorsetsthecheckedattribute.Thevaluedoesnotchangewhenothercheckboxesorradiobuttonsarechecked.
Level1
disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe
<input/>element.Returnsnulliftheelementisnotinsideaform.
Level1
maxLength GetsorsetsthevalueofthemaxLengthattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1readOnly Usedonlyiftypeistextorpassword.Getsorsets
thevalueofthereadonlyattribute.Level1
size Getsorsetsthevalueofthesizeattribute. Level1src Iftypeisimage,thisgetsorsetsthevalueofthesrc
attribute.Level1
type Getsthevalueofthetypeattribute. Level1value Getsorsetsthevalueofthevalueattribute. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
blur() Removeskeyboardfocusfromtheelement. Level1click() Simulatesamouseclickfor<input/>elementswithtype
button,checkbox,radio,reset,andsubmit.Level1
focus() Giveskeyboardfocustotheelement. Level1select() Selectscontentof<input/>elementswithtypetext,
password,andfile.Level1
HTMLOptionElementRepresentsthe<option/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
defaultSelected Getsorsetstheselectedattribute.Thevalueofthispropertydoesnotchangeasother<option/>elementsinthe<select/>elementareselected.
Level1
disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe
<option/>element.Returnsnulliftheelementisnotinsideaform.
Level1
index Getstheindexpositionofthe<option/>elementinitscontaining<select/>element.Startsat0.
Level1
label Getsorsetsthevalueofthelabelattribute. Level1selected Returnsabooleanvaluedependingonwhetheror
notthe<option/>elementiscurrentlyselected.Level1
text Getsthetextcontainedwithinthe<option/>element.
Level1
value Getsorsetsthevalueofthevalueattribute. Level1
HTMLOptionCollectionTheHTMLOptionCollectionobjectwasintroducedinDOMLevel2.Itcontainsalistof<option/>elements.
PROPERTYNAME
DESCRIPTION INTRODUCED
length Getsthenumberof<option/>elementsinthelist.
Level2
Methods
METHODNAME
DESCRIPTION INTRODUCED
item(index) Retrievesthe<option/>elementatthespecifiedindex.
Level2
namedItem(name) Retrievesthe<option/>elementbythespecifiedname.Itfirstattemptstofindan<option/>elementwiththespecifiedid.Ifnonecanbefound,itlooksfor<option/>elementswiththespecifiednameattribute.
Level2
HTMLParagraphElementRepresentsthe<p/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
HTMLSelectElementRepresentsthe<select/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe
<select/>element.Returnsnulliftheelementisnotinsideaform.
Level1
length Returnsthenumberof<option/>elements. Level1multiple Getsorsetsthevalueofthemultipleattribute. Level1name Getsorsetsthevalueofthenameattribute. Level1options ReturnsanHTMLOptionsCollectionobjectcontaining
thelistofthe<option/>elements.Level1
selectedIndex Returnstheindexofthecurrentlyselected<option/>element.Returns-1ifnothingisselectedandreturnsthefirst<option/>elementselectedifmultipleitemsareselected.
Level1
size Getsorsetsthevalueofthesizeattribute. Level1type Getsthevalueofthetypeattribute. Level1value Getsorsetsthecurrentformcontrol’svalue. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
add(element[,
before])
Addsan<option/>elementtothe<select/>element.Ifbeforeisnull,thenelementisaddedattheendofthelist.
Level1
blur() Removeskeyboardfocusfromtheelements. Level1focus() Giveskeyboardfocustotheelement. Level1remove(index) Removesthe<option/>elementatthegivenindex.
Doesnothingifindexisoutofrange.Level1
HTMLTableCellElement
Representsthe<td/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
bgColor Deprecated.Getsorsetsthevalueofthebgcolorattribute.
Level1
cellIndex TheindexofthecellintherowinDOMtreeorder. Level1colSpan Getsorsetsthevalueofthecolspanattribute. Level1height Deprecated.Getsorsetsthevalueoftheheight
attribute.Level1
noWrap Deprecated.Getsorsetsthevalueofthenowrapattribute.
Level1
rowSpan GetsorsetsthevalueoftherowSpanattribute. Level1vAlign Getsorsetsthevalueofthevalignattribute. Level1width Deprecated.Getsorsetsthevalueofthewidth
attribute.Level1
HTMLTableElementRepresentsthe<table/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute. Level1bgColor Deprecated.Getsorsetsthevalueofthebgcolor
attribute.Level1
border Getsorsetsthevalueoftheborderattribute. Level1cellPadding GetsorsetsthevalueofthecellPaddingattribute. Level1cellSpacing GetsorsetsthevalueofthecellSpacingattribute. Level1rows ReturnsanHTMLCollectioncontainingallrowsinthe
table.Level1
tBodies ReturnsanHTMLCollectionofthedefined<tbody/>elementobjectsinthetable.
Level1
tFoot Returnsthetable’s<tfoot/>elementobject(HTMLTableSectionElement),ornullifonedoesn’texist.
Level1
tHead Returnsthetable’s<thead/>elementobject(HTMLTableSectionElement),ornullifonedoesn’texist.
Level1
width Getsorsetsthevalueofthewidthattribute. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
createTFoot() Createsandreturnsa<tfoot/>elementifonedoesnotexist.Returnstheexisting<tfoot/>elementifitexists.
Level1
createTHead() Createsandreturnsa<thead/>elementifonedoesnotexist.Returnstheexisting<thead/>elementifitexists.
Level1
deleteRow(index) Deletestherowatthespecifiedindex. Level1deleteTFoot() Deletesthetable’sfooterifoneexists. Level1deleteTHead() Deletesthetable’sheaderifoneexists. Level1insertRow(index) Insertsandreturnsanewrowatthespecified
index.Ifindexis-1orequaltothenumberofrows,thenewrowisappendedtotheendoftherowlist.
Level1
HTMLTableRowElementRepresentsthe<tr/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
bgColor Deprecated.Getsorsetsthevalueofthebgcolorattribute.
Level1
cells ReturnsanHTMLCollectioncontainingthecellsintherow.
Level1
rowIndex Theindexoftherowinthetable. Level1sectionRowIndex Theindexoftherowrelativetothesectionit
belongsto(<thead/>,<tfoot/>,or<tbody/>).Level1
vAlign Getsorsetsthevalueofthevalignattribute. Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDdeleteCell(index) Deletesthecellatthespecifiedindex. Level1insertCell(index) Insertsandreturnsanempty<td/>element.If
indexis-1orequaltothenumberofcellsintherow,thenewcellisappendedtotheendofthelist.
Level1
HTMLTableSectionElementRepresentsthe<thead/>,<tbody/>,and<tfoot/>elements.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
align Deprecated.Getsorsetsthevalueofthealignattribute.
Level1
rows ReturnsanHTMLCollectioncontainingtherowsofthesection.
Level1
vAlign Getsorsetsthevalueofthevalignattribute. Level1
Methods
METHODNAME
DESCRIPTION INTRODUCED
deleteRow(index) Deletestherowatthespecifiedindexrelativetothesection.
Level1
insertRow(index) Insertsandreturnsanewrowintothesectionatthespecifiedindex(relativetothesection).Ifindexis-1orequaltothenumberofrows,therowisappendedtotheendofthelist.
Level1
HTMLTextAreaElementRepresentsthe<textarea/>element.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
accessKey GetsorsetsthevalueoftheaccessKeyattribute. Level1cols Getsorsetsthevalueofthecolsattribute. Level1defaultValue Getsorsetsthecontentsoftheelement.Thevaluedoes
notchangewhenthecontentchanges.Level1
disabled Getsorsetsthevalueofthedisabledattribute. Level1form GetstheHTMLFormElementobjectcontainingthe
<textarea/>element.Returnsnulliftheelementisnotinsideaform.
Level1
name Getsorsetsthevalueofthenameattribute. Level1readOnly Usedonlyiftypeistextorpassword.Getsorsetsthe
valueofthereadonlyattribute.Level1
rows Getsorsetsthevalueoftherowsattribute. Level1type Getsthevalueofthetypeattribute.Alwayssetto
textarea.Level1
value Getsorsetsthecurrentvalueoftheelement. Level1
Methods
METHODNAME DESCRIPTION INTRODUCEDblur() Removeskeyboardfocusfromtheelement. Level1focus() Giveskeyboardfocustotheelement. Level1select() Selectsthecontentsoftheelement. Level1
HTMLMediaObjectsTheHTMLMediaElementobjectisthebasetypeforboth<video/>and<audio/>elements.
HTMLMediaElementProperties
PROPERTYNAME DESCRIPTION INTRODUCEDautoplay Reflectstheautoplayattribute,anddetermines
whereplaybackshouldautomaticallybeginassoonasenoughmediaisavailable.
HTML5
buffered Getstherangesofthemediasourcethatthebrowserhasbuffered.
HTML5
controller Getsorsetsthemediacontrollerassociatedwiththeelement;returnsnullifnoneislinked.
HTML5
controls Getsorsetsthecontrolsattribute,determiningifthebrowser’sdefaultcontrolsaredisplayed.
HTML5
currentSrc GetstheabsoluteURLofthemedia. HTML5currentTime Thecurrentplaybacktimeinseconds.Setting
seeksthemediatothespecifiedtime.HTML5
defaultMuted Getsorsetsthemutedattribute.Thisdoesnotaffecttheaudioafterplaybackstarts.Usethemutedpropertyforthat.
HTML5
defaultPlaybackRate Thespeedofplayback.1.0isnormal. HTML5duration Getsthelengthofthemediainseconds. HTML5ended Indicateswhetherthemediaelementhasended
playback.HTML5
error Themostrecenterror;nullifnoerrorhasoccurred.
HTML5
loop Getsorsetstheloopattribute;indicateswhetherthemediashouldstartoverwhenitreachestheend.
HTML5
mediaGroup Getsorsetsthemediagroupattribute. HTML5muted Mutesorunmutestheaudio. HTML5networkState Thecurrentstateoffetchingthemediaoverthe
network.HTML5
paused Indicateswhetherthemediaelementispaused. HTML5
playbackRate Getsorsetsthecurrentplaybackrate. HTML5played Getstherangesthatthemediasourcehas
played,ifany.HTML5
preload Getsorsetsthepreloadattribute. HTML5readyState Getsthereadinessofthemedia. HTML5seekable Getsthetimerangesthattheusercanseek. HTML5
seeking Indicateswhetherthemediaisintheprocessofseekingtoanewposition.
HTML5
src Getsorsetsthesrcattribute. HTML5volume Getsorsetsthevolumeoftheaudio.0.0(silent)
to1.0(loudest)HTML5
Methods
METHODNAME
DESCRIPTION INTRODUCED
canPlayType() Determinesthelikelihoodthebrowsercanplaythegivenmediatype.
HTML5
load() Beginsloadingthemediacontentfromtheserver. HTML5pause() Pausesthemediaplayback. HTML5play() Beginsorresumesthemediaplayback. HTML5
HTMLAudioElementThe<audio/>elementdoesnothaveanyuniquepropertiesormethodsfromHTMLMediaElement.
HTMLVideoElementThe<video/>elementhasafewuniqueproperties.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
height Getsorsetstheheightattribute,determiningthesizeofthedisplayarea.
HTML5
poster Getsorsetstheposterattribute,specifyingtheimagetoshowwhilenovideodataisavailable.
HTML5
videoHeight GetstheintrinsicheightoftheresourceinCSSpixels. HTML5videoWidth GetstheintrinsicwidthoftheresourceinCSSpixels. HTML5width Getsorsetsthewidthattribute,determinethesizeofthe
displayarea.HTML5
DOMEVENTMODELANDOBJECTSTheDOMeventmodelwasintroducedinDOMLevel2.Itdescribesaneventsystemwhereeveryeventhasaneventtarget.Whenaneventreachesaneventtarget,allregisteredeventhandlersontheeventtargetaretriggeredforthatspecificevent.ThefollowingobjectsaredescribedbytheDOMeventmodel.
EventTargetTheEventTargetobjectisinheritedbyallHTMLElementobjectsintheDOM.Thisobjectprovidesthemeansfortheregistrationandremovalofeventhandlersontheeventtarget.
Methods
METHODName DESCRIPTIONaddEventListener(type,
listener,useCapture)
Registersaneventhandleronanelement.typeistheeventtypetolistenfor,listeneristheJavaScriptfunctiontocallwhentheeventisfired,anduseCapturedetermineswhethertheeventiscapturedorbubbles.
removeEventListener(type,
listener,useCapture)
Removesalistenerfromtheelement.
EventWhenaneventfires,anEventobjectispassedtotheeventhandlerifoneisspecified.Thisobjectcontainscontextualinformationaboutanevent.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
bubbles Indicateswhetherornottheeventisabubblingevent.
Level2
cancelable Indicateswhetherornottheeventcanhaveitsdefaultactionprevented.
Level2
currentTarget IndicatestheEventTargetwhoselistenersarecurrentlybeingprocessed.
Level2
target IndicatestheEventTargetobjecttowhichtheeventwasoriginallyfired.
Level2
timeStamp Specifiesthetime(inmilliseconds)atwhichtheeventwasfired.
Level2
type Thenameoftheevent(remember:thisisthenamewithouttheonprefix).
Level2
Methods
METHODNAME DESCRIPTION INTRODUCEDpreventDefault() Cancelstheevent,preventingthedefaultaction
fromtakingplace,onlyiftheeventiscancelable.Level2
stopPropagation() Preventsfurtherpropagationofanevent. Level2
MouseEventTheMouseEventobjectprovidesspecificinformationassociatedwithmouseevents.MouseEventobjectscontainnotonlythefollowingproperties,butalsothepropertiesandmethodsoftheEventobject.
Validmouseeventsareshowninthefollowingtable.
EVENTNAME
DESCRIPTION
click Occurswhenthemousebuttonisclickedoveranelement.Aclickisdefinedasamousedownandmouseupoverthesamescreenlocation.
mousedown Occurswhenthemousebuttonispressedoveranelement.mouseup Occurswhenthemousebuttonisreleasedoveranelement.mouseover Occurswhenthemousepointermovesontoanelement.mousemove Occurswhenthemousepointermoveswhileitisovertheelement.mouseout Occurswhenthemousepointermovesawayfromanelement.
Properties
PROPERTYNAME
DESCRIPTION INTRODUCED
altKey ReturnsabooleanvalueindicatingwhetherornottheAltkeywaspressedduringtheevent’sfiring.
Level2
button Indicateswhichmousebuttonwaspressed,ifapplicable.Thenumber0representstheleftbutton,1indicatesthemiddlebutton,and2indicatestherightbutton.Left-hand-configuredmicereversethebuttons(rightis0,middleis1,andleftis2).
Level2
clientX Thehorizontalcoordinaterelativetotheclientarea. Level2clientY Theverticalcoordinaterelativetotheclientarea. Level2ctrlKey Returnsabooleanvalueindicatingwhetherornotthe
Ctrlkeywaspressedwhentheeventfired.Level2
relatedTarget IndentifiesasecondaryEventTarget.Currently,thispropertyisusedwiththemouseovereventtoindicatetheEventTargetthatthemousepointerexitedandwiththemouseouteventtoindicatewhichEventTargetthepointerentered.
Level2
screenX Thehorizontalcoordinaterelativetothescreen. Level2screenY Theverticalcoordinaterelativetothescreen. Level2shiftKey Returnsabooleanvalueindicatingwhetherornotthe
Shiftkeywaspressedwhentheeventfired.Level2
MISCELLANEOUSEVENTSThefollowingtablesdescribetheeventsavailableinclient-sideJavaScript.
MouseEvents
EVENT DESCRIPTIONclick RaisedwhentheuserclicksanHTMLcontrol.dblclick Raisedwhentheuserdouble-clicksanHTMLcontrol.mousedown Raisedwhentheuserpressesamousebutton.mousemove Raisedwhentheusermovesthemousepointer.mouseout RaisedwhentheusermovesthemousepointeroutfromwithinanHTML
control.mouseover RaisedwhentheusermovesthemousepointeroveranHTMLcontrol.mouseup Raisedwhentheuserreleasesthemousebutton.
KeyboardEvents
EVENT DESCRIPTIONkeydown Raisedwhentheuserpressesakeyonthekeyboard.keypress Raisedwhentheuserpressesakeyonthekeyboard.Thiseventwillberaised
continuallyuntiltheuserreleasesthekey.keyup Raisedwhentheuserreleasesakeythathadbeenpressed.
HTMLControlEvents
EVENT DESCRIPTIONblur RaisedwhenanHTMLcontrollosesfocus.change RaisedwhenanHTMLcontrollosesfocusanditsvaluehaschanged.focus RaisedwhenfocusissettotheHTMLcontrol.reset Raisedwhentheuserresetsaform.select RaisedwhentheuserselectstextinanHTMLcontrol.submit Raisedwhentheusersubmitsaform.
WindowEvents
EVENT DESCRIPTIONload Raisedwhenthewindowhascompletedloading.resize Raisedwhentheuserresizesthewindow.unload ExecutesJavaScriptcodewhentheuserexitsadocument.
MediaEvents
EVENT DESCRIPTIONabort Raisedwhenplaybackisaborted.canplay Sentwhenenoughdataisavailablethatthemediacanbeplayed.canplaythrough Firedwhentheentiremediacanbeplayedwithoutinterruption.durationchange Raisedwhenthemetadatahaschanged.emptied Fireswhenthemediahasbecomeempty.ended Sentwhenplaybackcompletes.error Sentwhenanerroroccurs.loadeddata Themedia’sfirstframehasbeenloaded.loadedmetadata Firedwhenthemedia’smetadataisloaded.loadstart Sentwhendownloadingbegins.pause Playbackhasbeenpaused.play Playbackbeginsafterapause.playing Raisedwhenmediabeginstoplay.progress Indicatestheprogressofthemediadownload.ratechange Fireswhentheplaybackratechanges.seeked Seekinghasended.seeking Playbackisbeingmovedtoanewposition.stalled Raisedwhenthebrowsertriestodownloadthemedia,butreceivesno
data.suspend Sentwhentheloadingofthemediaissuspended.timeupdate Themedia’scurrentTimehaschanged.volumechange Fireswhentheaudiovolumechanges(bothwhenvolumeissetand
whenmuted).waiting Raisedwhenplaybackispausedinordertodownloadmoredata.
OtherEvents
EVENT DESCRIPTIONabort Raisedwhentheuserabortsloadinganimage.error Raisedwhenanerroroccursloadingthepage.
DLatin-1CharacterSetThisappendixcontainstheLatin-1charactersetandthecharactercodesinbothdecimalandhexadecimalformats.AsexplainedinChapter2,theescapesequence\xNN,whereNNisahexadecimalcharactercodefromtheLatin-1charactersetshownhere,canbeusedtorepresentcharactersthatcan’tbetypeddirectlyinJavaScript.
DECIMALCHARACTERCODE
HEXADECIMALCHARACTERCODE
SYMBOL
32 20 Space33 21 !34 22 “35 23 #36 24 $37 25 %38 26 &39 27 ‘40 28 (41 29 )42 2A *43 2B +44 2C ,45 2D -46 2E .47 2F /48 30 049 31 150 32 251 33 352 34 453 35 554 36 655 37 756 38 8
57 39 958 3A :59 3B ;60 3C <61 3D =62 3E >63 3F ?64 40 @65 41 A66 42 B67 43 C68 44 D69 45 E70 46 F71 47 G72 48 H73 49 I74 4A J75 4B K76 4C L77 4D M78 4E N79 4F O80 50 P81 51 Q82 52 R83 53 S84 54 T85 55 U86 56 V87 57 W88 58 X89 59 Y90 5A Z91 5B [
92 5C \93 5D ]
94 5E ^95 5F _96 60 `97 61 a98 62 b99 63 c100 64 d101 65 e102 66 f103 67 g104 68 h105 69 i106 6A j107 6B k108 6C l109 6D m110 6E n111 6F o112 70 p113 71 q114 72 r115 73 s116 74 t117 75 u118 76 v119 77 w120 78 x121 79 y122 7A z123 7B {124 7C |125 7D }126 7E ~
160 A0 Non-breakingspace
161 A1 ¡
162 A2 ¢163 A3 £164 A4 ¤165 A5 ¥166 A6 ¦167 A7 §168 A8 ¨169 A9 ©170 AA ª171 AB «172 AC ¬173 AD Softhyphen174 AE ®175 AF ¯176 B0 °177 B1 ±
178 B2 2
179 B3 3
180 B4 ´181 B5 μ182 B6 ¶183 B7 ·184 B8 ¸185 B9 1186 BA °187 BB »188 BC ~QF189 BD ~HF190 BE ~TQF191 BF ¿192 C0 À193 C1 Á
194 C2 Â195 C3 Ã196 C4 Ä197 C5 Å198 C6 Æ199 C7 Ç200 C8 È201 C9 É202 CA Ê203 CB Ë204 CC Ì205 CD Í206 CE Î207 CF Ï208 D0 Ð209 D1 Ñ210 D2 Ò211 D3 Ó212 D4 Ô213 D5 Õ214 D6 Ö215 D7 ∞216 D8 Ø217 D9 Ù218 DA Ú219 DB Û220 DC Ü221 DD Ý222 DE þ223 DF ß224 E0 à225 E1 á226 E2 â227 E3 ã228 E4 ä
229 E5 å230 E6 æ231 E7 ç
232 E8 è
233 E9 é234 EA ê235 EB ë236 EC ì237 ED í238 EE î239 EF ï240 F0 ð241 F1 ñ242 F2 ò243 F3 ó244 F4 ô245 F5 õ246 F6 ö247 F7 ÷248 F8 ø249 F9 ù250 FA ú251 FB û252 FC ü253 FD ý254 FE þ255 FF ÿ
BeginningJavaScript®5e
PublishedbyJohnWiley&Sons,Inc.10475CrosspointBoulevardIndianapolis,IN46256www.wiley.com
Copyright©2015byJohnWiley&Sons,Inc.,Indianapolis,Indiana
PublishedsimultaneouslyinCanada
ISBN:978-1-118-90333-9ISBN:978-1-118-90343-8(ebk)ISBN:978-1-118-90374-2(ebk)
Nopartofthispublicationmaybereproduced,storedinaretrievalsystemortransmittedinanyformorbyanymeans,electronic,mechanical,photocopying,recording,scanningorotherwise,exceptaspermittedunderSections107or108ofthe1976UnitedStatesCopyrightAct,withouteitherthepriorwrittenpermissionofthePublisher,orauthorizationthroughpaymentoftheappropriateper-copyfeetotheCopyrightClearanceCenter,222RosewoodDrive,Danvers,MA01923,(978)750-8400,fax(978)646-8600.RequeststothePublisherforpermissionshouldbeaddressedtothePermissionsDepartment,JohnWiley&Sons,Inc.,111RiverStreet,Hoboken,NJ07030,(201)748-6011,fax(201)748-6008,oronlineathttp://www.wiley.com/go/permissions.
LimitofLiability/DisclaimerofWarranty:Thepublisherandtheauthormakenorepresentationsorwarrantieswithrespecttotheaccuracyorcompletenessofthecontentsofthisworkandspecificallydisclaimallwarranties,includingwithoutlimitationwarrantiesoffitnessforaparticularpurpose.Nowarrantymaybecreatedorextendedbysalesorpromotionalmaterials.Theadviceandstrategiescontainedhereinmaynotbesuitableforeverysituation.Thisworkissoldwiththeunderstandingthatthepublisherisnotengagedinrenderinglegal,accounting,orotherprofessionalservices.Ifprofessionalassistanceisrequired,theservicesofacompetentprofessionalpersonshouldbesought.Neitherthepublishernortheauthorshallbeliablefordamagesarisingherefrom.ThefactthatanorganizationorWebsiteisreferredtointhisworkasacitationand/orapotentialsourceoffurtherinformationdoesnotmeanthattheauthororthepublisherendorsestheinformationtheorganizationorWebsitemayprovideorrecommendationsitmaymake.Further,readersshouldbeawarethatInternetWebsiteslistedinthisworkmayhavechangedordisappearedbetweenwhenthisworkwaswrittenandwhenitisread.
ForgeneralinformationonourotherproductsandservicespleasecontactourCustomerCareDepartmentwithintheUnitedStatesat(877)762-2974,outsidetheUnitedStatesat(317)572-3993orfax(317)572-4002.
Wileypublishesinavarietyofprintandelectronicformatsandbyprint-on-demand.Somematerialincludedwithstandardprintversionsofthisbookmaynotbeincludedine-booksorinprint-on-demand.IfthisbookreferstomediasuchasaCDorDVDthatisnotincludedintheversionyoupurchased,youmaydownloadthismaterialathttp://booksupport.wiley.com.FormoreinformationaboutWileyproducts,visitwww.wiley.com.
LibraryofCongressControlNumber:2014958440
Trademarks:Wiley,theWileylogo,Wrox,theWroxlogo,ProgrammertoProgrammer,andrelatedtradedressaretrademarksorregisteredtrademarksofJohnWiley&Sons,Inc.and/oritsaffiliates,intheUnitedStatesandothercountries,andmaynotbeusedwithoutwrittenpermission.JavaScriptisaregisteredtrademarkofOracle,Inc.Allothertrademarksarethepropertyoftheirrespectiveowners.JohnWiley&Sons,Inc.,isnotassociatedwithanyproductorvendormentionedinthisbook.
Thisbookisdedicatedtomywife,Starla,andmysons,Hayden,Evan,andJordan.Thankyouforyourlove,support,andpatienceduringthewritingofthisbook.Tomyparents:JerryandJudy.Thankyoufor
yourloveandsupport.
—JeremyMcPeak
Inmemoryofmymum,JuneWilton,whoin2006lostherbravebattleagainstcancer.Shewasalwaysveryproudofmeandmybooksandshowedmybookstoanyoneandeveryoneshehappenedtomeethoweverbrieflyandwhethertheywantedtoseethemornot!
She’sverymuchmissed.
—PaulWilton
CreditsProjectEditorKellyTalbot
TechnicalEditorRussMullen
ProductionManagerKathleenWisor
CopyEditorKimCofer
ManagerofContentDevelopment&AssemblyMaryBethWakefield
MarketingDirectorDavidMayhew
MarketingManagerCarrieSherrill
ProfessionalTechnology&StrategyDirectorBarryPruett
BusinessManagerAmyKnies
AssociatePublisherJimMinatel
ProjectCoordinator,CoverPatrickRedmond
ProofreaderNancyCarrasco
IndexerJohnnaVanHooseDinse
CoverDesignerWiley
CoverImage©iStock.com/hamikus
AbouttheAuthorsJeremyMcPeakisaself-taughtprogrammerwhobeganhiscareerbytinkeringwithwebsitesin1998.HeistheauthorofJavaScript24-HourTrainer(Wiley2010)andco-authorofProfessionalAjax,2ndEdition(Wiley2007).HealsocontributestoTuts+Code(http://code.tutsplus.com),providingarticles,videotutorials,andcoursesforJavaScript,C#,andASP.NET.Heiscurrentlyemployedbyanoilandgascompanybuildingin-houseconventionalandwebapplications.Jeremycanbecontactedviathep2pforums,hiswebsite(http://www.wdonline.com),andTwitter(@jwmcpeak).
PaulWiltonstartedasaVisualBasicapplicationsprogrammerattheMinistryofDefenseintheUKandthenfoundhimselfpulledintotheNet.HavingjoinedanInternetdevelopmentcompany,hespentthreeyearshelpingcreateInternetsolutions.He’snowrunninghisownsuccessfulandrapidlygrowingcompanydevelopingonlineholidaypropertyreservationsystems.
AcknowledgmentsFirstandforemost,IwanttothankGodfortheblessingshehasbestoweduponme,andthankyou,dearreader,forwithoutyouthisbookwouldnotbepossible.Also,ahugethankyougoestomywifeandfamilyforputtingupwithmeasIspentmyavailableweekendfree-timeupdatingthisbook.
Writingandproducingabookrequiresalotofpeople,andIknowIcannotnameeveryonewhohashadahandinthisproject.ButaverybigthankyougoestoJimMinatelandRobertElliottforgreen-lightingthisproject.ThankyouKellyTalbotforkeepingmeontrackandputtingupwithme.Totheeditingteam,thankyouformakingmytextlookgood.AndtoRussMullen,thanksforkeepingmehonest.
—JEREMYMCPEAK
First,abigthankyoutomypartnerBeci,who,nowthatthebook’sfinished,willgettoseemeformorethan10minutesaweek.
I’dalsoliketosayaverybigthankyoutotheeditors,whoworkedveryefficientlyongettingthisbookintoprint.
ThanksalsotoJimMinatelformakingthisbookhappen.
Manythankstoeveryonewho’ssupportedandencouragedmeovermymanyyearsofwritingbooks.Yourhelpwillalwaysberemembered.
Finally,patsandtreatstomyGermanShepherdDog,Katie,whodoesanexcellentjobofwardingoffdisturbancesfromdoor-to-doorsalespeople.
—PAULWILTON
WILEYENDUSERLICENSEAGREEMENTGotowww.wiley.com/go/eulatoaccessWiley’sebookEULA.