object-oriented javascript - third edition · 2017. 4. 20. · es6 object literals object...

607

Upload: others

Post on 06-Aug-2021

30 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare
Page 2: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object-Oriented JavaScript - Third Edition

Page 3: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Table of Contents

Object-OrientedJavaScript-ThirdEditionCreditsAbouttheAuthorsAbouttheReviewerwww.PacktPub.comWhysubscribe?

CustomerFeedbackPrefaceWhatthisbookcoversWhatyouneedforthisbookWhothisbookisforConventionsReaderfeedbackCustomersupportErrataPiracyQuestions

1.Object-OrientedJavaScriptAbitofhistoryBrowserwarsand renaissanceThe presentThefuture

ECMAScript5StrictmodeinES6

ECMAScript6BrowsersupportforES6Babel

Object-orientedprogrammingObjectsClassesEncapsulationAggregationInheritancePolymorphism

OOPsummarySettingupyourtrainingenvironmentWebKit'swebinspectorJavaScriptCoreonaMacMoreconsoles

Page 4: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Summary2.PrimitiveDataTypes, Arrays,Loops,andConditionsVariablesVariablesarecasesensitive

OperatorsPrimitivedatatypesFindingoutthevaluetype-thetypeofoperatorNumbersOctalandhexadecimalnumbersBinaryLiteralsExponentliteralsInfinityNaNNumber.isNaNNumber.isInteger

StringsStringconversionsSpecialstringsStringtemplateliterals

BooleansLogicaloperatorsOperatorprecedenceLazyevaluationComparison

UndefinedandnullSymbols

PrimitivedatatypesrecapArraysAdding/updatingarrayelementsDeletingelementsArraysofarrays

ConditionsandloopsCode blocksTheifconditionTheelseclauseCheckingifavariableexistsAlternativeifsyntaxSwitchDon'tforgettobreak

LoopsWhileloopsDo-whileloops

Page 5: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ForloopsFor...inloops

CommentsExercisesSummary

3.FunctionsWhatisafunction?Calling a functionParameters

DefaultparametersRestparametersSpreadoperatorsPredefinedfunctionsparseInt()parseFloat()isNaN()isFinite()Encode/decodeURIseval()Abonus-thealert()function

ScopeofvariablesVariablehoisting

BlockscopeFunctionsaredataAnonymousfunctionsCallbackfunctionsCallbackexamples

ImmediatefunctionsInner(private)functionsFunctionsthatreturnfunctionsFunction,rewritethyself!

ClosuresScope chainBreakingthechain withaclosureClosure#1Closure#2Adefinitionandclosure#3

ClosuresinaloopGetterandsetterIterator

IIFEversusblocksArrowfunctions

Page 6: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ExercisesSummary

4.ObjectsFromarraystoobjectsElements,properties,methods,andmembersHashesandassociativearraysAccessinganobject'spropertiesCalling an object's methodsAlteringproperties/methodsUsingthethisvalueConstructorfunctionsTheglobalobjectTheconstructorpropertyTheinstanceofoperatorFunctionsthatreturnobjectsPassingobjectsComparingobjectsObjectsintheWebKitconsoleLoggingusingtheconsole.logmethod

ES6objectliteralsObjectpropertiesandattributesES6objectmethodsCopypropertiesusingObject.assignComparevalueswithObject.is

DestructuringBuilt-inobjectsObjectArrayAfewarraymethods

ES6arraymethodsArray.fromCreatingarraysusingArray.ofArray.prototype methodsFunctionPropertiesoffunctionobjectsUsingtheprototypepropertyMethodsoffunctionobjectsCallandapplyTheargumentsobjectrevisited

LexicalthisinarrowfunctionsInferringobjecttypesBoolean

Page 7: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

NumberStringAfewmethodsofstringobjects

MathDateMethodstoworkwithdateobjectsCalculatingbirthdays

RegExpPropertiesofRegExpobjectsMethodsofRegExpobjectsStringmethodsthatacceptregularexpressionsasargumentssearch()andmatch()replace()Replacecallbackssplit()Passingastring whenaRegExpisexpectedErrorobjects

ExercisesSummary

5.ES6IteratorsandGeneratorsFor...ofloopIteratorsanditerablesIteratorsIterables

GeneratorsIteratingovergenerators

CollectionsMapIteratingovermapsConvertingmapstoarrays

SetWeakMapandWeakSet

Summary6.PrototypeTheprototypepropertyAddingmethodsandpropertiesusingtheprototype

Usingtheprototype'smethodsandpropertiesOwnpropertiesversusprototypepropertiesOverwritingaprototype'spropertywithanownpropertyEnumeratingproperties

UsingisPrototypeOf()methodThesecret__proto__link

Page 8: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Augmentingbuilt-inobjectsAugmentingbuilt-inobjects-discussionPrototypegotchas

ExercisesSummary

7.InheritancePrototypechainingPrototype chaining exampleMovingsharedpropertiestotheprototype

InheritingtheprototypeonlyAtemporaryconstructor-newF()

Uber-accesstotheparentfromachildobjectIsolatingtheinheritancepartintoafunctionCopyingpropertiesHeads-upwhencopyingbyreferenceObjectsinheritfromobjectsDeepcopyUsingobject()methodUsingamixofprototypalinheritanceandcopyingpropertiesMultipleinheritanceMixins

ParasiticinheritanceBorrowingaconstructorBorrowingaconstructorandcopyingitsprototype

Casestudy-drawingshapesAnalysisImplementationTesting

ExercisesSummary

8.ClassesandModulesDefiningclassesConstructorPrototypemethodsStaticmethodsStaticpropertiesGeneratormethods

SubclassingMixins

ModulesExportlists

Summary

Page 9: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

9.PromisesandProxiesAsynchronousprogrammingmodelJavaScriptcallstackMessagequeueEventloopTimersRuntocompletionEventsCallbacks

PromisesCreatingpromisesPromise.all()

MetaprogrammingandproxiesProxyFunctiontraps

Summary10.TheBrowserEnvironmentIncludingJavaScriptinanHTMLpageBOMandDOM-anoverviewBOMThewindowobjectrevisitedUsingwindow.navigatorpropertyYourconsoleisacheatsheetUsingwindow.locationpropertyUsingwindow.historypropertyusingwindow.framespropertyUsingwindow.screenpropertywindow.open()/close()methodwindow.moveTo()andwindow.resizeTo()methodswindow.alert(),window.prompt(),andwindow.confirm()methodsUsingwindow.setTimeout()andwindow.setInterval()methodswindow.documentproperty

DOMCoreDOMandHTMLDOMAccessingDOMnodesThedocumentnodedocumentElementChildnodesAttributesAccessingthecontentinsideatagDOMaccessshortcutsSiblings,body,first,andlastchild

Page 10: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

WalktheDOMModifyingDOMnodesModifyingstylesFunwithforms

CreatingnewnodesDOM-onlymethodUsingcloneNode()methodUsing insertBefore() method

RemovingnodesHTML-onlyDOMobjectsPrimitivewaystoaccessthedocumentUsingdocument.write()methodCookies,title,referrer,anddomain

EventsInlineHTMLattributesElementPropertiesDOMeventlistenersCapturingandbubblingStoppropagationPreventdefaultbehaviorCross-browsereventlistenersTypesofevents

XMLHttpRequestSendingtherequestProcessingtheresponseCreatingXMLHttpRequestobjectsinIEpriortoVersion7AisforAsynchronousXisforXMLAnexample

ExercisesSummary

11.CodingandDesignPatternsCoding patternsSeparatingbehaviorContentPresentationBehaviorExampleofseparatingbehavior

AsynchronousJavaScriptloadingNamespacesAnObjectasanamespaceNamespacedconstructors

Page 11: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Anamespace()methodInit-timebranchingLazydefinitionConfigurationobjectPrivatepropertiesandmethodsPrivilegedmethodsPrivatefunctionsaspublicmethodsImmediate functionsModulesChainingJSONHigherorderfunctions

DesignpatternsSingletonpatternSingleton2patternGlobalvariablePropertyoftheconstructorInaprivateproperty

FactorypatternDecoratorpatternDecoratingachristmastree

ObserverpatternSummary

12.TestingandDebuggingUnittestingTestDrivenDevelopmentBehaviorDrivenDevelopmentMocha,ChaiandSinon

JavaScriptdebuggingSyntaxerrorsUsingstrict

RuntimeexceptionsConsole.log and assertsChromeDeveloperTools

Summary13.ReactiveProgrammingandReactReactiveprogrammingWhyshouldyouconsiderreactiveprogramming?

ReactVirtualDOMInstallingandrunningreactComponentsandprops

Page 12: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

StateLifecycleevents

SummaryA.ReservedWordsKeywordsES6reservedwordsFuturereservedwords

Previously reserved wordsB.Built-inFunctionsC.Built-inObjectsObjectMembersoftheObjectconstructorTheObject.prototypemembersECMAScript5additionstoobjects

ES6additiontoobjectsPropertyshorthandComputedpropertynamesObject.assign

ArrayTheArray.prototypemembersECMAScript5additionstoArrayES6additiontoarrays

FunctionTheFunction.prototypemembersECMAScript5additionstoaFunctionECMAScript6additionstoaFunction

BooleanNumberMembersoftheNumberconstructorTheNumber.prototypemembers

StringMembersoftheStringconstructorThe String.prototype membersECMAScript5additionstoStringECMAScript6additionstoString

DateMembersoftheDateconstructorTheDate.prototypemembersECMAScript5additionstoDate

MathMembersoftheMathobject

RegExp

Page 13: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheRegExp.prototypemembersErrorobjectsTheError.prototypemembers

JSONMembersoftheJSONobject

D.RegularExpressionsE.AnswerstoExerciseQuestionsChapter 2, Primitive Data Types, Arrays, Loops, and ConditionsExercises

Chapter3,FunctionsExercises

Chapter4,ObjectsExercises

Chapter5,PrototypeExercises

Chapter6,InheritanceExercises

Chapter7,TheBrowserEnvironmentExercises

Page 14: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object-Oriented JavaScript - Third Edition

Page 15: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object-Oriented JavaScript - Third EditionCopyright © 2017 Packt Publishing

Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.

Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthors,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.

PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproducts mentioned in this book by the appropriate use of capitals. However, Packt Publishingcannotguaranteetheaccuracyofthisinformation.

Firstpublished:July2008

Secondedition:July2013

Thirdedition:January2017

Production reference: 1050117

PublishedbyPacktPublishingLtd.

LiveryPlace

35LiveryStreet

Birmingham

B32PB,UK.

ISBN978-1-78588-056-8

www.packtpub.com

Page 16: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CreditsAuthors

VedAntani

StoyanStefanov

CopyEditor

ZainabBootwala

Reviewer

MohamedSanaulla

ProjectCoordinator

RitikaManoj

CommissioningEditor

WilsonDsouza

Proofreader

SafisEditing

AcquisitionEditor

DenimPinto

Indexer

RekhaNair

ContentDevelopmentEditor

ArunNadar

Graphics

JasonMonteiro

TechnicalEditor

AbhishekSharma

ProductionCoordinator

ArvindkumarGupta

Page 17: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

About the AuthorsVedAntani has been building scalable server and mobile platforms using JavaScript, Go, andJavasince2005.HeisanassociatevicepresidentatMyntraandhaspreviouslyworkedatElectronicArtsandOracle.Heisanavidreaderandauthoronseveralsubjects.HehasstudiedcomputerscienceandcurrentlylivesinBangalore,India.Vedispassionateaboutclassicalmusicandlovestospendtimewithhisson.

Writingthisbookrequiredasignificantinvestmentofmytime,andIwouldliketothankmyparentsandfamilyfortheirsupportandencouragementduringthoselongdaysandweekendswhenIwaspracticallyinvisible.

StoyanStefanovisaFacebookengineer,author,andspeaker.Hetalksregularlyaboutwebdevelopmenttopicsatconferences,andhisblog,www.phpied.com.Healsorunsanumberofothersites,includingJSPatterns.com-asitededicatedtoexploringJavaScriptpatterns.PreviouslyatYahoo!,StoyanwasthearchitectofYSlow2.0andcreatoroftheimageoptimizationtool,Smush.it.

A"citizenoftheworld", StoyanwasbornandraisedinBulgaria,butisalsoaCanadiancitizen,currentlyresidinginLos Angeles,California.Inhisofflinemoments,heenjoysplayingtheguitar,takingflyinglessons,andspendingtimeattheSantaMonicabeacheswithhisfamily.

I'dliketodedicatethisbooktomywife,Eva,andmydaughters,ZlatinaandNathalie.Thankyouforyourpatience,support,andencouragement.

Page 18: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

About the ReviewerMohamed Sanaulla is a software developer with more than 7 years of experience in developingenterpriseapplicationsandJava-basedback-endsolutionsfore-commerceapplications.

HisinterestsincludeEnterprisesoftwaredevelopment,refactoringandredesigningapplications,designingandimplementingRESTfulwebservices,troubleshootingJavaapplicationsforperformanceissues,andTDD.

HehasstrongexpertiseinJava-basedapplicationdevelopment,ADF(JSF-basedJavaEEwebframework),SQL,PL/SQL,JUnit,designingRESTfulservices,Spring,Struts,Elasticsearch,andMongoDB.HeisalsoaSunCertifiedJavaProgrammerfortheJava6platform.HeisamoderatorforJavaRanch.com.Helikestosharefindingsonhisblog(http://sanaulla.info).

Page 19: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

www.PacktPub.comFor support files and downloads related to your book, please visit www.PacktPub.com.

DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusatservice@packtpub.comformoredetails.

Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.

https://www.packtpub.com/mapt

Getthemostin-demandsoftwareskillswithMapt.MaptgivesyoufullaccesstoallPacktbooksandvideocourses,aswellasindustry-leadingtoolstohelpyouplanyourpersonaldevelopmentandadvanceyourcareer.

Page 20: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Why subscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser

Page 21: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Customer FeedbackThank you for purchasing this Packt book. We take our commitment to improving our content andproductstomeetyourneedsseriously-that'swhyyourfeedbackissovaluable.Whateveryourfeelingsaboutyourpurchase,pleaseconsiderleavingareviewonthisbook'sAmazonpage.Notonlywillthishelpus,moreimportantlyitwillalsohelpothersinthecommunitytomakeaninformeddecisionabouttheresourcesthattheyinvestintolearn.Youcanalsoreviewforusonaregularbasisbyjoiningourreviewers'club.Ifyou'reinterestedinjoining,orwouldliketolearnmoreaboutthebenefitsweoffer,pleasecontactus:[email protected].

Page 22: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

PrefaceJavaScript has emerged as one of the most robust and versatile programming language around.ModernJavaScriptembracesavastarrayoftime-testedandcuttingedgefeatures.Severalofthesefeaturesareslowlygivingshapetothenextgenerationofwebandserverplatforms.ES6introducesveryimportantlanguageconstructs,suchaspromises,classes,arrowfunctions,andseveral,muchanticipatedfeatures.Thisbooktakesadetailedlookatthelanguageconstructsandtheirpracticaluses.Thisbookdoesn'tassumeanypriorknowledgeofJavaScriptandworksfromthegrounduptogiveyouathoroughunderstandingofthelanguage.Peoplewhoknowthelanguagewillstillfinditusefulandinformative.ForpeoplewhoalreadyknowJavaScriptandarefamiliarwithES5syntax,thisbookwillbeaveryusefulprimerforES6features.

Page 23: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

What this book coversChapter 1, Object-Oriented JavaScript, talks briefly about the history, present, and future ofJavaScript,andthenmovesontoexplorethebasicsofobject-orientedprogramming(OOP)ingeneral.Youwillthenlearnhowtosetupyourtrainingenvironment(Firebug)inordertodiveintothelanguageonyourown,usingthebookexamplesasabase.

Chapter2,PrimitiveDataTypes,Arrays,Loops,andConditions,discussesthelanguagebasics-variables,datatypes,primitivedatatypes,arrays,loops,andconditionals.

Chapter3,Functions,coversfunctionsthatJavaScriptuses,andhereyouwilllearntomasterthemall.YouwillalsolearnaboutthescopeofvariablesandJavaScript'sbuilt-infunctions.Aninteresting,butoftenmisunderstood,featureofthelanguage-closures-isdemystifiedattheendofthechapter.

Chapter 4, Objects, talks about objects, how to work with properties and methods, and thevariouswaystocreateyourobjects.Thischapteralsotalksaboutbuilt-in objectssuchasArray,Function,Boolean,Number,andString.

Chapter5,ES6IteratorsandGenerators,introducesthemostanticipatedfeaturesofES6,IteratorsandGenerators.Withthisknowledge,youwillproceedtotakeadetailedlookattheenhancedcollectionsconstructs.

Chapter6,Prototype,isdedicatedtotheall-importantconceptofprototypesinJavaScript.Italsoexplainshowtheprototypechainworks,hasOwnProperty(),andsomegotchasofprototypes.

Chapter7,Inheritance,discusseshowinheritanceworks.Thischapteralsotalksaboutamethodtocreatesubclasseslikeotherclassiclanguages.

Chapter8,ClassesandModules,showsthatES6introducesimportantsyntacticalfeaturesthatmakesiteasiertowriteclassicalobject-oriented programmingconstructs.ES6classsyntaxwrapstheslightlycomplexsyntaxofES5.ES6alsohasfulllanguagesupportformodules.ThischaptergoesintothedetailsoftheclassesandmoduleconstructsintroducedinES6.

Chapter9,PromisesandProxies,explainsthatJavaScripthasalwaysbeenalanguagewithstrongsupportforasynchronousprogramming.UpuntilES5,writingasynchronousprogramsmeantyouneededtorelyoncallbacks-sometimesresultingincallbackhell.ES6promisesareamuch-awaitedfeatureintroducedinthelanguage. PromisesprovideamuchcleanerwaytowriteasynchronousprogramsinES6.Proxiesareusedtodefinecustombehaviortosomeofthefundamentaloperations.ThischapterlooksatpracticalusesofbothpromisesandproxiesinES6.

Chapter 10, The Browser Environment, is dedicated to browsers. This chapter also covers BOM(BrowserObjectModel),DOM(W3C'sDocumentObjectModel),browserevents,andAJAX.

Page 24: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter11,CodingandDesignPatterns,divesintovariousuniqueJavaScriptcodingpatterns,aswellasseverallanguage-independentdesignpatterns,translatedtoJavaScriptfromtheBookofFour,themostinfluentialworkofsoftwaredesignpatterns.ThischapteralsodiscussesJSON.

Chapter12,TestingandDebugging,talksabouthowModernJavaScriptisequippedwithtoolsthatsupportTestDrivenDevelopmentandBehaviorDrivenDevelopment.Jasmineisoneofthemostpopulartoolsavailableatthemoment.ThischapterdiscussesTDDandBDDusingJasmineastheframework.

Chapter13,ReactiveProgrammingandReact,explainsthatwiththeadventofES6,severalradicalideasaretakingshape.Reactiveprogrammingtakesaverydifferentapproachtohowwemanagechangeofstatesusingdataflows.React,however,isaframeworkfocusingontheViewpartofMVC.Thischapterdiscussesthesetwoideas.

AppendixA,ReservedWords,liststhereservedwordsinJavaScript.

Appendix B, Built-in Functions, is a reference of built-in JavaScript functions together withsampleuses.

AppendixC,Built-inObjects,isareferencethatprovidesdetailsandexamplesoftheuseofeverymethodandpropertyofeverybuilt-inobjectinJavaScript.

AppendixD,RegularExpressions,isaregularexpressionspatternreference.

AppendixE,AnswerstoExerciseQuestions,hassolutionsforalltheexercisesmentionedattheendofthechapters.

Page 25: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

What you need for this bookYou need a modern browser-Google Chrome or Firefox are recommended, and an optionalNode.jssetup.Mostofthecodeinthisbookcanbeexecutedinhttp://babeljs.io/repl/orhttp://jsbin.com/.ToeditJavaScript,youcanuse anytexteditorofyourchoice.

Page 26: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Who this book is forThis book is for anyone who is starting to learn JavaScript, or who knows JavaScript but isn'tverygoodattheobject-orientedpartofit.ThisbookcanbeausefulprimerforES6ifyouarealreadyfamiliarwiththeES5featuresofthelanguage.

Page 27: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ConventionsIn this book, you will find a number of text styles that distinguish between different kinds ofinformation.Herearesomeexamplesofthesestylesandanexplanationoftheirmeaning.

Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:"TheTriangleconstructortakesthreepointobjectsandassignsthemtothis.points(itsowncollectionofpoints)."

Ablockofcodeissetasfollows:

functionsum(a,b){varc=a+b;returnc;}

Anycommand-lineinput oroutputiswrittenasfollows:

mkdirbabel_testcdbabel_test&&npminitnpminstall--save-devbabel-cli

Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,forexample,inmenusordialogboxes,appearinthetextlikethis:"InordertobringuptheconsoleinChromeorSafari,right-clickanywhereonapageandselectInspectElement.TheadditionalwindowthatshowsupistheWebInspectorfeature.SelecttheConsoletab,andyou'rereadytogo".

Note

Warningsorimportantnotesappearinaboxlikethis.

Tip

Tipsandtricksappearlikethis.

Page 28: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Reader feedbackFeedback from our readers is always welcome. Let us know what you think about this book-whatyoulikedordisliked.Readerfeedbackisimportantforusasithelpsusdeveloptitlesthatyouwillreallygetthemostoutof.

Tosendusgeneralfeedback,[email protected],andmentionthebook'stitleinthesubjectofyourmessage.

Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideatwww.packtpub.com/authors.

Page 29: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Customer supportNow that you are the proud owner of a Packt book, we have a number of things to help you to getthemostfromyourpurchase.

Page 30: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Errata

Althoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks-maybeamistakeinthetextorthecode-wewouldbegratefulifyoucouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheErrataSubmissionFormlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedtoourwebsiteoraddedtoanylistofexistingerrataundertheErratasectionofthattitle.

Toviewthepreviouslysubmittederrata,gotohttps://www.packtpub.com/books/content/supportandenterthenameofthebookinthesearchfield.TherequiredinformationwillappearundertheErratasection.

Page 31: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Piracy

PiracyofcopyrightedmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.IfyoucomeacrossanyillegalcopiesofourworksinanyformontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.

[email protected] piratedmaterial.

Weappreciateyourhelpinprotectingourauthorsandourabilitytobringyouvaluablecontent.

Page 32: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Questions

Ifyouhaveaproblemwithanyaspectofthisbook,[email protected],andwewilldoourbesttoaddresstheproblem.

Page 33: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 1. Object-Oriented JavaScriptEver since the early days of the web, there has been a need for more dynamic and responsiveinterfaces.Whileit'sOKtoreadstaticHTMLpagesoftext,andevenbetterwhentheyarebeautifullypresentedwiththehelpofCSS,it'smuchmorefuntoengagewithapplicationsinourbrowsers,suchase-mail,calendars,banking,shopping,drawing,playinggames,andtextediting.AllthatispossiblethankstoJavaScript,theprogramminglanguageoftheweb.JavaScriptstartedwithsimpleone-linersembeddedinHTML,butisnowusedinmuchmoresophisticatedways.Developersleveragethe object-orientednatureofthelanguagetobuildscalablecodearchitecturesmadeupof reusablepieces.

Ifyoulookatthepastandpresentbuzzwordsinwebdevelopment,DHTML,Ajax,Web2.0,HTML5,theyallessentiallymeanHTML,CSS,andJavaScript-HTMLforcontent,CSSforpresentation,andJavaScriptforbehavior.Inotherwords,JavaScriptisthegluethatmakeseverythingworktogethersothatwecanbuildrichwebapplications.

However,that'snotall;JavaScriptcanbeusedformorethanjusttheweb.

JavaScriptprogramsrun insideahostenvironment.Thewebbrowseristhemostcommonenvironment,butit'snottheonlyone.UsingJavaScript,youcancreateallkindsofwidgets,applicationextensions,andotherpiecesofsoftware,asyou'llseeinabit.TakingthetimetolearnJavaScriptisasmartinvestment;youlearnonelanguageandcanthenwriteallkindsofdifferentapplicationsrunningonmultipleplatforms,includingmobileandserver-sideapplications.Thesedays,it'ssafetosaythatJavaScriptiseverywhere.

Thisbookstartsfromzero,anddoesnotassumeanypriorprogrammingknowledgeotherthansomebasicunderstandingofHTML.Althoughthereisonechapterdedicatedtothewebbrowserenvironment,therestofthebookisaboutJavaScriptingeneral,soit'sapplicabletoallenvironments.

Let'sstartwiththefollowing:

AbriefintroductiontothestorybehindJavaScriptThebasicconceptsyou'llencounterindiscussionsonobject-orientedprogramming

Page 34: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

A bit of historyInitially, the web was not much more than just a number of scientific publications in the form ofstaticHTMLdocumentsconnectedtogetherwithhyperlinks.Believeitornot,therewasatimewhentherewasnowaytoputanimageinapage.However,thatsoonchanged.Asthewebgrewinpopularityandsize,thewebmasterswhowere creatingHTMLpagesfelttheyneededsomethingmore.Theywantedtocreatericheruserinteractions,mainlydrivenbythedesiretosaveserverroundtripsforsimpletaskssuchasformvalidation.Twooptionscameup-JavaappletsandLiveScript,alanguageconceivedbyBrendanEichatNetscapein1995andlaterincludedintheNetscape2.0browserunderthenameofJavaScript.

Theappletsdidn'tquitecatchon,butJavaScriptdid.TheabilitytouseshortcodesnippetsembeddedinHTMLdocumentsandalterotherwisestaticelementsofawebpagewasembracedbythewebmastercommunity.Soon,thecompetingbrowservendor,Microsoft,shippedInternetExplorer(IE)3.0withJScript,whichwasareverseengineeredversionofJavaScriptplussomeIE-specificfeatures.Eventually,therewasanefforttostandardizethevariousimplementationsofthelanguage,andthisishowECMAScriptwasborn.EuropeanComputerManufacturersAssociation(ECMA)createdthestandardcalledECMA-262,whichdescribesthecorepartsoftheJavaScriptprogramminglanguagewithoutbrowserandwebpage-specificfeatures.

YoucanthinkofJavaScriptasatermthatencompassesthefollowingthreepieces:

ECMAScript:Thecorelanguage-variables,functions,loops,andsoon.Thispartisindependentofthebrowserandthislanguagecanbeusedinmanyotherenvironments.DocumentObjectModel(DOM):ThisprovideswaystoworkwithHTMLandXMLdocuments.Initially,JavaScriptprovidedlimitedaccesstowhat'sscriptableonthepage,mainlyforms,links,andimages.Later,itwasexpandedtomakeallelementsscriptable.ThisledtothecreationoftheDOMstandardbytheWorldWideWebConsortium(W3C)asalanguage-independent(nolongertiedtoJavaScript)waytomanipulatestructureddocuments.Browser Object Model (BOM): This is a set of objects related to the browser environmentandwasneverpartofanystandarduntilHTML5startedstandardizingsomeofthecommonobjectsthatexistacrossbrowsers.

Whilethereisonechapterinthisbookdedicated tothebrowser,theDOM,andtheBOM,mostofthisbookdescribesthecorelanguageandteachesyouskillsyoucanuseinanyenvironmentwhereJavaScriptprogramsrun.

Page 35: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Browserwarsandrenaissance

Forbetterorforworse,JavaScript'sinstantpopularityhappenedduringtheperiodofthebrowserwarsI(approximately1996to2001).ThosewerethetimesduringtheinitialInternetboomwhenthetwomajorbrowservendors,NetscapeandMicrosoft,werecompetingformarketshare.BothwereconstantlyaddingmorebellsandwhistlestotheirbrowsersandtheirversionsofJavaScript,DOM,andBOM,whichnaturallyledtomanyinconsistencies.Whileaddingmorefeatures,thebrowservendorswerefallingbehindonprovidingproperdevelopmentanddebuggingtoolsandadequatedocumentation.Often,developmentwasapain;youwouldwriteascriptwhiletestinginonebrowser,andonceyou'redonewithdevelopment,youtestintheotherbrowser,onlytofindthatyourscriptsimplyfails fornoapparentreason,andthebestyoucangetisacrypticerrormessage,suchasoperationaborted.

Inconsistentimplementations,missingdocumentation,andnoappropriatetoolspaintedJavaScriptin such a light that many programmers simply refused to bother with it.

Ontheotherhand,developerswhodidtrytoexperimentwithJavaScriptgotalittlecarriedaway,addingtoomanyspecialeffectstotheirpageswithoutmuchregardofhowusabletheendresultswere.Developerswereeagertomakeuseofeverynewpossibilitythebrowsersprovided,andendedupenhancingtheirwebpageswiththingssuchasanimationsinthestatusbar,flashingcolors,blinkingtexts,objectsstalkingyourmousecursor,andmanyotherinnovationsthatactuallyhurttheuserexperience.ThesevariouswaystoabuseJavaScriptarenowmostlygone,buttheywereoneofthereasonswhythelanguagehadsomethingofabadreputation.ManyseriousprogrammersdismissedJavaScriptasnothingbutatoyfordesignerstoplayaroundwith,anddismisseditasalanguageunsuitableforseriousapplications.TheJavaScriptbacklashcausedsomewebprojectstocompletelybananyclient-sideprogrammingandtrustonlytheirpredictableandtightlycontrolledserver.Andreally,whywouldyoudoublethetimetodeliverafinishedproductandthenspendadditionaltimedebuggingproblemswiththedifferentbrowsers?

EverythingchangedintheyearsfollowingtheendofthebrowserwarsI.Anumberofeventsreshapedthewebdevelopmentlandscapeinapositiveway.Someofthemaregivenasfollows:

MicrosoftwonthewarwiththeintroductionofIE6,thebestbrowseratthetime,andformanyyearstheystoppeddevelopingInternetExplorer.ThisallowedtimeforotherbrowserstocatchupandevensurpassIE'scapabilities.Themovementforwebstandardswasembracedbydevelopersandbrowservendorsalike.Naturally,developersdidn'tlikehavingtocodeeverythingtwo(ormore)timestoaccountforbrowsers'differences;therefore,theylikedtheideaofhavingagreed-uponstandardsthateveryonewouldfollow.Developersandtechnologiesmaturedandmorepeoplestartedcaringaboutthingssuchasusability,progressiveenhancementtechniques,andaccessibility.ToolssuchasFirebugmadedevelopersmuchmoreproductiveandthedevelopmentlessofapain.

Page 36: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inthishealthierenvironment,developersstartedfindingoutnewandbetterwaystousetheinstrumentsthatwerealreadyavailable.AfterthepublicreleaseofapplicationssuchasGmailandGoogleMaps,whichwererichonclient-sideprogramming,itbecameclearthatJavaScriptisamature,uniqueincertainways,andpowerfulprototypalobject-orientedlanguage.ThebestexampleofitsrediscoverywasthewideadoptionofthefunctionalityprovidedbytheXMLHttpRequestobject,whichwasonceanIE-onlyinnovation,butwasthenimplementedbymostotherbrowsers.XMLHttpRequestobjectallowsJavaScripttomake HTTPrequestsandgetfreshcontentfromtheserverinordertoupdatesomepartsofapagewithoutafullpagereload.DuetothewideuseoftheXMLHttpRequestobject,anewbreedofdesktop-likewebapplications,dubbedAjaxapplications,wasborn.

Page 37: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thepresent

AninterestingthingaboutJavaScriptisthatitalwaysrunsinsideahostenvironment.Thewebbrowserisjustoneoftheavailablehosts.JavaScriptcanalsorunontheserver,onthedesktop,andonmobiledevices.Today,youcanuseJavaScripttodoallofthefollowing:

Createrichandpowerfulwebapplications(thekindofapplicationsthatruninsidethewebbrowser).AdditionstoHTML5,suchasapplicationcache,client-sidestorage,anddatabases,makebrowserprogrammingmoreandmorepowerfulforbothonlineandofflineapplications.PowerfuladditionstoChromeWebKitalsoincludesupportforserviceworkersandbrowserpushnotifications.Writeserver-sidecodeusingNode.js,aswellascodethatcanrunusingRhino(aJavaScriptenginewritteninJava).Makemobileapplications;youcancreateappsforiPhone,Android, andotherphonesandtabletsentirelyinJavaScriptusingPhoneGaporTitanium.Additionally,appsforFirefoxOSformobilephonesareentirelyinJavaScript,HTML,andCSS.ReactNativefromFacebookisanexcitingnewwaytodevelopnativeiOS,Android,andWindows(experimental)applicationsusingJavaScript.Createrichmediaapplications,suchasFlashorFlex,usingActionScript,whichisbasedonECMAScript.Writecommand-linetoolsandscriptsthatautomateadministrativetasksonyourdesktopusingWindowsScriptingHost(WSH)orWebKit'sJavaScriptCore,whichisavailableonallMacs.Writeextensionsandpluginsforaplethoraofdesktopapplications,suchasDreamweaver,Photoshop,andmostotherbrowsers.Createcross-operatingsystemdesktopapplicationsusingMozilla'sXULRunnerandElectron.Electronisusedtobuildsomeofthemostpopularappsonthedesktop,suchasSlack,Atom,andVisualStudioCode.Emscripten,ontheotherhand,allowscode writteninC/C++tobecompiledintoanasm.jsformat,whichcanthenberuninsideabrowser.TestingframeworkslikePhantomJSareprogrammedusingJavaScript.This is by no means an exhaustive list. JavaScript started inside web pages, but today it'ssafetosayitispracticallyeverywhere.Inaddition,browservendorsnowusespeedasacompetitiveadvantageandareracingtocreatethefastestJavaScript engines,whichisgreatforbothusersanddevelopers,andopensdoorsforevenmorepowerfulusesofJavaScriptinnewareassuchasimage,audioandvideoprocessing,andgamesdevelopment.

Page 38: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thefuture

Wecanonlyspeculatewhatthefuturewillbe,butit'squitecertainthatitwillincludeJavaScript.Forquitesometime,JavaScriptmayhavebeenunderestimatedandunderused(ormaybeoverusedinthewrongways),buteveryday,wewitnessnewapplicationsofthelanguageinmuchmoreinterestingandcreativeways.Itallstartedwithsimpleone-liners,oftenembeddedinHTMLtagattributes,suchasonclick.Nowadays,developersshipsophisticated,well-designedandarchitected,andextensibleapplicationsandlibraries,oftensupportingmultipleplatformswithasinglecodebase.JavaScriptisindeedtakenseriously,anddevelopersarestartingtorediscoverandenjoyitsuniquefeaturesmoreandmore.

Oncelistedinthenice-to-havesectionsofjobpostings,today,knowledgeofJavaScriptisoftenadecidingfactorwhenitcomestohiringwebdevelopers.Commonjobinterviewquestionsyoucanheartodayinclude-IsJavaScriptanobject-orientedlanguage?Good.Now,howdoyouimplementinheritanceinJavaScript?Afterreadingthisbook,you'llbepreparedtoaceyourJavaScript job interview and even impress your interviewers with some bits that, maybe, theydidn'tknow.

Page 39: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript 5The last most important milestone in ECMAScript revisions was ECMAScript 5 (ES5),officiallyacceptedinDecember2009.ECMAScript5standardisimplementedandsupportedonallmajorbrowsersandserver-sidetechnologies.

ES5wasamajorrevisionbecauseapartfromseveralimportantsyntacticchangesandadditionstothestandardlibraries, ES5alsointroducedseveralnewconstructsinthelanguage.

Forinstance,ES5introducedsomenewobjectsandproperties,andalsotheso-calledstrictmode.Strictmodeisasubsetofthelanguagethatexcludesdeprecatedfeatures.Thestrictmodeisopt-inandnotrequired,meaningthatifyouwantyourcodetoruninthestrictmode,youwilldeclareyourintentionusing(onceperfunction,oronceforthewholeprogram)thefollowingstring:

"usestrict";

ThisisjustaJavaScriptstring,andit'soktohavestringsfloatingaroundunassignedtoanyvariable.Asaresult,olderbrowsersthatdon'tspeakES5willsimplyignoreit,sothisstrictmodeisbackwardscompatibleandwon'tbreakolderbrowsers.

Forbackwardscompatibility,alltheexamplesin thisbookworkinES3,butatthesametime,allthecodeinthebookiswrittensothatitwillrunwithoutwarningsinES5'sstrictmode.Additionally, any ES5-specific parts will be clearly marked. Appendix C, Built-in Objects, liststhenewadditionstoES5indetail.

Page 40: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

StrictmodeinES6

WhilestrictmodeisoptionalinES5,allES6modulesandclassesarestrictbydefault.Asyouwillseesoon,mostofthecodewewriteinES6residesinamodule;hence,strictmodeisenforcedbydefault.However,itisimportanttounderstandthatallotherconstructsdonothaveimplicitstrictmodeenforced.Therewereefforts tomakenewerconstructs,suchasarrowandgeneratorfunctions,toalsoenforcestrictmode,butitwaslaterdecidedthatdoingsowouldresultinveryfragmentedlanguagerulesandcode.

Page 41: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript 6ECMAScript 6 revision took a long time to finish and was finally accepted on June 17, 2015. ES6featuresareslowlybecomingpartofmajorbrowsersandservertechnologies.ItispossibletousetranspilerstocompileES6toES5andusethecodeonenvironmentsthatdonotyetsupportES6completely(wewilldiscusstranspilersindetaillater).

ES6substantiallyupgradesJavaScriptasalanguageandbringsinveryexcitingsyntacticalchangesandlanguageconstructs.Broadly,therearetwokindsoffundamentalchangesinthisrevisionofECMAScript,whichareasfollows:

Improvedsyntaxforexistingfeaturesandeditionstothestandardlibrary;forexample,classesandpromisesNewlanguagefeatures;forexample,generators

ES6allowsyoutothinkdifferentlyaboutyourcode.Newsyntaxchangescanletyouwritecodethatiscleaner,easiertomaintain,anddoesnotrequirespecialtricks.Thelanguageitselfnowsupportsseveralconstructsthatrequiredthird-partymodulesearlier.LanguagechangesintroducedinES6needaseriousrethinkinthewaywehavebeencodinginJavaScript.

Anoteonthenomenclature-ECMAScript6,ES6,andECMAScript2015arethesame,butusedinterchangeably.

Page 42: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BrowsersupportforES6

ThemajorityofthebrowsersandserverframeworksareontheirwaytowardsimplementingES6features.Youcancheckoutthewhatissupportedandwhatisnotbyclickinghttp://kangax.github.io/compat-table/es6/.

ThoughES6isnotfullysupportedonallbrowsersandserverframeworks,wecanstartusingalmostallfeaturesofES6withthehelpoftranspilers.Transpilersaresource-to-sourcecompilers.ES6transpilersallowyoutowritecodeinES6syntaxandcompile/transformthemintoequivalentES5syntax,whichcanthenberunonbrowsersthatdonotsupporttheentirerangeofES6features.

ThedefactoES6transpileratthemomentisBabel.Inthisbook,wewilluseBabelandwriteandtestourexamples.

Page 43: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Babel

BabelsupportsalmostallES6featuresoutoftheboxorwithcustomplugins.Babelcanbeusedfromawiderangeofbuildsystems,frameworks, andlanguagestotemplateengines,andhasagoodcommandlineandread-eval-printloop(REPL)builtin.

TogetagoodideaabouthowBabeltranspilesES6codetoitsES5equivalentform,headovertoBabelREPL(http://babeljs.io/repl/).

BabelREPLallowsyoutoquicklytestsmallsnippetsofES6.WhenyouopenBabelREPLinthebrowser, you will see some ES6 code defaulted there. On the left pane, remove the code and typeinthefollowingtext:

varname="John",mood="happy";console.log(`Hey${name},areyoufeeling${mood}today?`)

Whenyoutypethisandtaboutoftheleftpane,youwillseeREPLtranspilingthisES6codeintosomethinglikethefollowingcode:

"usestrict";varname="John",mood="happy";console.log("Hey"+name+",areyoufeeling"+mood+"today?");

ThisistheES5equivalentofthecodewewroteearlierintheleftpane.Youcanseethattheresulting code in the right pane is a familiar ES5. As we said, Babel REPL is a good place to tryandexperimentwithvariousES6constructs.However,weneedbabeltoautomaticallytranspileyourES6codeintoES5,andforthat,youcanincludeBabelintoyourexistingbuildsystemsorframeworks.

Let'sbeginbyinstallingBabelasacommand-linetool.Forthis,wewillassumethatyouarefamiliarwithnodeandNodePackageManager (npm).InstallingBabelusingnpmiseasy.Let'sfirstcreateadirectorywherewewillhaveBabelinstalledasamoduleandrestofthesourcecode.OnmyMac,thefollowingcommandswillcreateadirectorycalledbabel_test,initializetheprojectusingnpminit,andinstallBabelcommandlineusingnpm:

mkdirbabel_testcdbabel_test&&npminitnpminstall--save-devbabel-cli

Ifyouarefamiliarwithnpm,youmaygettemptedtoinstallBabelglobally.However,installingBabelasaglobalmoduleisnotgenerallyagoodidea.OnceyouhaveinstalledBabelinyourproject,yourpackage.jsonfilewilllooksomethinglikethefollowingblockofcode:

{

Page 44: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"name":"babel_test","version":"1.0.0","description":"","main":"index.js","scripts":{"test":"echo"Error:notestspecified"&&exit1"},"author":"","license":"ISC","devDependencies":{"babel-cli":"^6.10.1"}}

YoucanseeadevelopmentdependencycreatedforBabelforversion>6.10.1.YoucanuseBabeltotranspileyourcodebyeitherinvokingitfromthecommandlineoraspartofthebuildstep.Foranynon-trivialwork,youwillneedthelaterapproach.ToinvokeBabelaspartoftheprojectbuildstep,youcanaddabuildstepinvokingBabelinsideyourscripttagtoyourpackage.jsonfile,forexample:

"scripts":{"build": "babel src -d lib"

},

Whenyoudonpmbuild,Babelwillbeinvokedonyoursrcdirectoryandthetranspiledcodewillbeplacedinsidelibdirectory.Alternatively,youcanrunBabelmanuallyalsobywritingthefollowingcommand:

$./node_modules/.bin/babelsrc-dlib

WewilltalkaboutvariousBabeloptionsandpluginslaterinthebook.ThissectionwillequipyoutostartexploringES6.

Page 45: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object-oriented programmingBefore diving into JavaScript, let's take a moment to review what people mean when they sayobject-oriented,andwhatthemainfeaturesofthisprogrammingstyleare.Here'salistofconceptsthataremostoftenusedwhentalkingaboutobject-orientedprogramming(OOP):

Object,method,andpropertyClassEncapsulationAggregationReusability/inheritancePolymorphism

Let'stakeacloserlookintoeachoneoftheseconcepts.Ifyou'renewtotheobject-orientedprogramminglingo,theseconceptsmightsoundtootheoretical,andyoumighthavetroublegraspingorrememberingthemfromonereading.Don'tworry,itdoestakeafewtries,andthesubjectcanbealittledryataconceptuallevel.However,we'lllookatplentyofcodeexamplesfurtheroninthebook,andyou'llseethatthingsaremuchsimplerinpractice.

Page 46: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Objects

Asthenameobject-orientedsuggests,objectsareimportant.Anobjectisarepresentationofathing(someoneorsomething),andthisrepresentationisexpressedwiththehelpofaprogramminglanguage.Thethingcanbeanything,areal-lifeobject,oramoreconvolutedconcept.Takingacommonobject,acat,forexample,youcanseethatithascertaincharacteristics-color,name,weight,andsoonandcanperformsomeactions-meow,sleep,hide,escape,andsoon.ThecharacteristicsoftheobjectarecalledpropertiesinOOP-speak,andtheactionsarecalledmethods.

Theanalogywiththespokenlanguageareasfollows:

Objectsaremostoftennamedusingnouns,suchasbook,person,andsoonMethodsareverbs,forexample,read,run,andsoonValuesofthepropertiesareadjectives

Takethesentence"Theblackcatsleepsonthemat"asanexample."Thecat"(anoun)istheobject,"black"(adjective)isthevalueofthecolorproperty,and"sleep"(averb)isanactionoramethodinOOP.Forthesakeoftheanalogy,wecangoastepfurtherandsaythat"onthemat"specifiessomethingabouttheaction"sleep",soit'sactingasaparameterpassedtothesleepmethod.

Page 47: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Classes

Inreallife,similarobjectscanbegroupedbasedonsomecriteria.Ahummingbirdandaneaglearebothbirds,sotheycanbeclassifiedasbelongingtosomemade-upBirdsclass.InOOP,aclassisablueprintorarecipeforanobject.Anothernameforobjectisinstance,sowecansaythattheeagleisoneconcreteinstanceofthegeneralBirdsclass.Youcancreatedifferentobjectsusingthesameclassbecauseaclassisjustatemplate,whiletheobjectsareconcreteinstancesbasedonthetemplate.

There'sadifferencebetweenJavaScriptandtheclassicOOlanguagessuchasC++andJava.YoushouldbeawarerightfromthestartthatinJavaScript,therearenoclasses;everythingisbasedonobjects.JavaScripthasthenotionofprototypes,whicharealsoobjects(we'lldiscussthemlaterindetail).InaclassicOOlanguage,you'dsaysomethinglike-createanewobjectformecalledBob,whichisofclassPerson.InaprototypalOOlanguage,you'dsay-I'mgoingtotakethisobjectcalledBob'sdadthatIhavelyingaround(onthecouchinfrontoftheTV?)andreuseitasaprototypeforanewobjectthatI'llcallBob.

Page 48: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Encapsulation

Encapsulationisanother OOPrelatedconcept,whichillustratesthefactthatanobjectcontains(encapsulates)thefollowing:

Data(storedinproperties)Themeanstodosomethingwiththedata(usingmethods)

Oneothertermthatgoestogetherwithencapsulationisinformationhiding.Thisisaratherbroadtermandcanmeandifferentthings,butlet'sseewhatpeopleusuallymeanwhentheyuseitinthecontextofOOP.

Imagineanobject,say,anMP3player.You,astheuseroftheobject,aregivensomeinterfacetoworkwith,suchasbuttons,display,andsoon.Youusetheinterfaceinordertogettheobjecttodosomethingusefulforyou,likeplayasong.Howexactlythedeviceisworkingontheinside,youdon'tknow,and,mostoften,don'tcare.Inotherwords,theimplementationoftheinterfaceishiddenfromyou.ThesamethinghappensinOOPwhenyourcodeusesanobjectbycallingitsmethods.Itdoesn'tmatterifyoucodedtheobjectyourselforitcamefromsomethird-partylibrary;yourcodedoesn'tneedtoknowhowthemethodsworkinternally. Incompiledlanguages,youcan'tactuallyreadthecodethatmakesanobjectwork.InJavaScript,becauseit'saninterpretedlanguage,youcanseethesourcecode,buttheconceptisstillthesame-youworkwiththe object's interface without worrying about its implementation.

Anotheraspectofinformationhidingisthevisibilityofmethodsandproperties.Insomelanguages,objectscanhavepublic,private,andprotectedmethodsandproperties.Thiscategorizationdefinesthelevelofaccesstheusersoftheobjecthave.Forexample,onlythemethodsofthesameobjecthaveaccesstotheprivatemethods,whileanyonehasaccesstothepublicones.InJavaScript,allmethodsandpropertiesarepublic,butwe'llseethattherearewaystoprotectthedatainsideanobjectandachieveprivacy.

Page 49: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Aggregation

Combiningseveralobjectsintoanewoneisknownasaggregationorcomposition.It'sapowerfulwaytoseparateaproblemintosmallerandmoremanageableparts(divideandconquer).Whenaproblemscopeissocomplexthatit'simpossibletothinkaboutitatadetailedlevelinitsentirety,youcanseparatetheproblemintoseveralsmallerareas,andpossiblythenseparateeachoftheseintoevensmallerchunks.Thisallowsyoutothinkabouttheproblemonseverallevelsofabstraction.

Take,forexample,apersonalcomputer.It'sacomplexobject.Youcannotthinkaboutallthethingsthatneedtohappenwhenyoustartyourcomputer.But,youcanabstracttheproblemsayingthatyouneedtoinitializealltheseparateobjectsthatyourComputerobjectconsistsoftheMonitorobject,theMouseobject,theKeyboardobject,andsoon.Then,youcandivedeeperintoeachofthesubobjects.Thisway,you'recomposingcomplexobjectsbyassemblingreusableparts.

Touseanotheranalogy,aBookobjectcancontain(aggregate)oneormoreAuthorobjects,aPublisherobject,severalChapterobjects,aTOC(tableofcontents),andsoon.

Page 50: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inheritance

Inheritanceisanelegantwaytoreuseexistingcode.Forexample,youcanhaveagenericobject,Person,whichhaspropertiessuchasnameanddate_of_birth,andwhichalsoimplementsthewalk,talk,sleep,andeatfunctionality.Then,youfigureoutthatyouneedanotherobjectcalledProgrammer.YoucanreimplementallthemethodsandpropertiesthataPersonobjecthas,butitwillbesmartertojustsaythattheProgrammerobjectinheritsaPersonobject,andsaveyourselfsomework.TheProgrammerobjectonlyneedstoimplementmorespecificfunctionality,suchasthewriteCodemethod,whilereusingallofthePersonobject'sfunctionality.

InclassicalOOP,classesinheritfromotherclasses,butinJavaScript,astherearenoclasses,objectsinheritfromotherobjects.

Whenanobjectinheritsfromanotherobject,itusuallyaddsnewmethodstotheinheritedones,thusextendingtheoldobject.Often,thefollowingphrasescanbeusedinterchangeably-BinheritsfromAandBextendsA.Also,theobjectthatinheritscanpickoneormoremethodsandredefinethem, customizing them for its own needs. This way, the interface stays the same and the methodnameisthesame,butwhencalledonthenewobject,themethodbehavesdifferently.Thiswayofredefininghowaninheritedmethodworksisknownasoverriding.

Page 51: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Polymorphism

Intheprecedingexample,aProgrammerobjectinheritedallofthemethodsoftheparentPersonobject.Thismeansthatbothobjectsprovideatalkmethod,amongothers.Nowimaginethatsomewhereinyourcode,there'savariablecalledBob,anditjustsohappensthatyoudon'tknowifBobisaPersonobjectoraProgrammerobject.YoucanstillcallthetalkmethodontheBobobjectandthecodewillwork.Thisabilitytocallthesamemethodondifferentobjects,andhaveeachofthemrespondintheirownway,iscalledpolymorphism.

Page 52: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

OOP summaryHere's a quick table summarizing the concepts discussed so far:

FeatureIllustratesconcept

Bobisaman(anobject). Objects

Bob'sdateofbirthisJune1,1980,gender-male,andhair-black. Properties

Bobcaneat,sleep,drink,dream,talk,andcalculatehisownage. Methods

BobisaninstanceoftheProgrammerclass.Class(inclassicalOOP)

BobisbasedonanotherobjectcalledProgrammer.

Prototype

(inprototypalOOP)

Bobholdsdata,suchasbirth_date,andmethodsthatworkwiththedata,suchascalculateAge(). Encapsulation

Youdon'tneedtoknowhowthecalculationmethodworksinternally.Theobjectmighthavesomeprivatedata,suchasthenumberofdaysinFebruaryinaleapyear.Youdon'tknow,nordoyouwanttoknow.

Informationhiding

BobispartofaWebDevTeamobjecttogetherwithJill,aDesignerobject,andJack,aProjectManagerobject.Aggregationandcomposition

Designer,ProjectManager,andProgrammerareallbasedonandextendaPersonobject. Inheritance

YoucancallthemethodsBob.talk(),Jill.talk(),andJack.talk(),andthey'llallworkfine,albeitproducingdifferentresults.Bobwillprobablytalkmoreaboutperformance,Jillaboutbeauty,andJackaboutdeadlines.EachobjectinheritedthemethodtalkfromPersonandcustomizedit.

Polymorphismandmethodoverriding

Page 53: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Setting up your training environmentThis book takes a do-it-yourself approach when it comes to writing code, because I firmlybelievethatthebestwaytoreallylearnaprogramminglanguageisbywritingcode.Therearenocut-and-paste-readycodedownloadsthatyousimplyputinyourpages.Onthecontrary,you'reexpectedtotypeincode,seehowitworks,andthentweakitandplayaroundwithit.Whentryingoutthecodeexamples,you'reencouragedtoenterthecodeintoaJavaScriptconsole.Let'sseehowyougoaboutdoingthis.

Asadeveloper,youmostlikelyalreadyhaveanumberofwebbrowsersinstalledonyoursystem,suchasFirefox,Safari,Chrome,orInternetExplorer.AllmodernbrowsershaveaJavaScriptconsolefeaturethatyou'llusethroughoutthebooktohelpyoulearnandexperimentwiththelanguage.Morespecifically,thisbookusesWebKit'sconsole,whichisavailableinSafariandChrome,buttheexamplesshouldworkinanyotherconsole.

Page 54: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

WebKit'swebinspector

Thisexampleshowshowyoucanusetheconsoletotypeinsomecodethatswapsthelogoonthegoogle.comhomepagewithanimageofyourchoice.Asyoucansee,you cantestyourJavaScriptcodeliveonanypage:

InordertobringuptheconsoleinChromeorSafari,rightclickanywhereonapageandselectInspectElement.TheadditionalwindowthatshowsupistheWebInspectorfeature.SelecttheConsoletab,andyou'rereadytogo.

Youtypecodedirectlyintotheconsole,andwhenyoupressEnter,yourcodeisexecuted.The

Page 55: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

returnvalueofthecodeisprintedintheconsole.Thecodeisexecutedinthecontextofthecurrentlyloadedpage,so,forexample,ifyoutypelocation.href,itwillreturntheURLofthecurrentpage.

The console also has an autocomplete feature. It works in a similar way to the normal command-linepromptinyouroperatingsystemorautocompletefeatureofthefull-fledgedIDEs.If,forexample,youtypedocuandhittheTaborrightarrowkey,docuwillbeautocompletedtodocument.Then,ifyoutype.(thedotoperator),youcaniteratethroughalltheavailablepropertiesandmethodsyoucancallonthedocumentobject.

Byusingtheupanddownarrowkeys,youcangothroughthelistofalreadyexecutedcommandsandbringthembackintheconsole.

Theconsolegivesyouonlyonelinetotypein,butyoucanexecuteseveralJavaScriptstatementsbyseparatingthemwithsemicolons.Ifyouneedmorelines,youcanpressShift+Entertogotoanewlinewithoutexecutingtheresultjustyet.

Page 56: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

JavaScriptCoreonaMac

OnaMac,youdon'tactuallyneedabrowser;youcanexploreJavaScriptdirectlyfromyourcommandlineTerminalapplication.

Ifyou'veneverusedTerminal,youcansimplysearchforitinSpotlightsearch.Onceyou'velaunchedit,typethefollowingcommand:

aliasjsc='/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc'

ThiscommandmakesanaliastothelittlejscapplicationthatstandsforJavaScriptCoreandispartoftheWebKitengine.JavaScriptCoreisshippedtogetherwithMacoperatingsystems.

You can add the alias line shown previously to your ~/.profile file so that jsc is always therewhen you need it.

Now,inordertostarttheinteractiveshell,youwillsimplytypejscfrom anydirectory.Then,youcantypeJavaScriptexpressions,andwhenyouhitEnter,you'llseetheresultoftheexpression.Takealookatthefollowingscreenshot:

Page 57: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Moreconsoles

Allmodernbrowsershaveconsolesbuiltin.YouhaveseentheChrome/Safariconsolepreviously.InanyFirefoxversion,youcaninstalltheFirebugextension,whichcomeswithaconsole.Additionally,innewerFirefoxreleases,there'saconsolebuiltinandaccessibleviatheTools|WebDeveloper|WebConsolemenu.

InternetExplorer,sinceversion8,hasanF12DeveloperToolsfeature,whichhasaconsoleinitsScripttab.

It'salsoagoodideatofamiliarizeyourselfwithNode.js,andyoucanstartbytryingoutitsconsole.InstallNode.jsfromhttp://nodejs.organdtrytheconsoleinyourcommandprompt(terminal):

Page 58: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Asyoucansee,youcanusetheNode.jsconsoletotryoutquickexamples.But,youcanalsowritelongershellscripts(test.jsinthescreenshot)andrunthemwiththescriptname.jsnode.

NodeREPLisapowerfuldevelopmenttool.Whenyoutype'node'onthecommandline,theREPLinvokes.YoucantryoutJavaScriptonthis REPL:

node>console.log("HellowWorld");HellowWorldundefined>a=10,b=10;10>console.log(a*b);100undefined

Page 59: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, you learned about how JavaScript was born, and where it is today. You were alsointroducedtoobject-orientedprogrammingconceptsandhaveseenhowJavaScriptisnotaclass-basedOOlanguage,butaprototype-basedone.Finally,youlearnedhowtouseyourtrainingenvironment-theJavaScriptconsole.Now,you'rereadytodiveintoJavaScriptandlearnhowtouseitspowerfulOOfeatures.However,let'sstartfromthebeginning.

ThenextchapterwillguideyouthroughthedatatypesinJavaScript(therearejustafew),conditions,loops,andarrays.Ifyouthinkyouknowthesetopics,feelfreetoskipthenextchapter,butnotbeforeyoumakesureyoucancompletethefewshortexercisesattheendofthechapter.

Page 60: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 2. Primitive Data Types, Arrays,Loops,andConditionsBeforedivingintotheobject-orientedfeaturesof JavaScript,let'sfirsttakealookatsomeofthebasics.Thischapterwalksyouthroughthefollowingtopics:

TheprimitivedatatypesinJavaScript,such asstringsandnumbersArraysCommonoperators,suchas+,-,delete,andtypeofFlowcontrolstatements,suchasloopsandif...elseconditions

Page 61: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

VariablesVariables are used to store data; they are placeholders for concrete values. When writingprograms,it'sconvenienttousevariablesinsteadoftheactualdataasit'smucheasiertowritepiinsteadof3.141592653589793;especiallywhenithappensseveraltimesinsideyourprogram.Thedatastoredinavariablecanbechangedafteritinitiallyassigned,hencethenamevariable.Youcanalsousevariablestostoredatathatisunknowntoyouwhileyouwritethecode,suchastheresultofalateroperation.

Usingavariablerequiresthefollowingtwosteps.Youwillneedto:

Declare the variableInitializeit,thatis,giveitavalue

Todeclareavariable,youwillusethevarstatementlikethefollowingpieceofcode:

vara;varthisIsAVariable;var_and_this_too;varmix12three;

Forthenamesofthevariables,youcanuseanycombinationofletters,numbers,theunderscorecharacter,andthedollarsign.However,youcan'tstartwithanumber,whichmeansthatthefollowingdeclarationofcodeisinvalid:

var2three4five;

Toinitializeavariablemeanstogiveitavalueforthefirst(initial)time.Thefollowingarethetwowaystodoso:

Declarethevariablefirst,theninitializeitDeclareandinitializeitwithasinglestatement

Anexampleofthelatterisasfollows:

vara=1;

Nowthevariablenamedacontainsthevalue1.

Youcandeclare,andoptionallyinitialize,severalvariableswithasinglevarstatement;justseparatethedeclarationswithacomma,asshowninthefollowinglineofcode:

varv1,v2,v3='hello',v4=4,v5;

Forreadability,thisisoftenwrittenusingonevariableperline,asfollows:

varv1,

Page 62: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

v2,v3='hello',v4=4,v5;

Note

The$characterinvariablenames

Youmayseethedollarsigncharacter($)usedinvariablenames,asin$myvarorlesscommonlymy$var.Thischaracterisallowedtoappearanywhereinavariablename,althoughpreviousversionsoftheECMAstandarddiscourageditsuseinhandwrittenprogramsandsuggesteditshouldonlybeusedingeneratedcode(programs writtenbyotherprograms).ThissuggestionisnotwellrespectedbytheJavaScriptcommunity,and$isinfactcommonlyusedinpracticeasafunctionname.

Page 63: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Variablesarecasesensitive

Variablenamesarecasesensitive.YoucaneasilyverifythisstatementusingyourJavaScriptconsole.TrytypingthefollowingcodebypressingEnteraftereachline:

varcase_matters='lower';varCASE_MATTERS='upper';case_matters;CASE_MATTER;

Tosavekeystrokeswhenyouenterthethirdline,youcantypecaseandpresstheTaborrightarrowkey.Consoleautocompletesthevariablenametocase_matters.Similarly,forthelastline,typeCASEandpresstheTabkey.Theendresultisshowninthefollowingfigure:

Throughouttherestofthisbook,onlythecodefortheexamplesisgiveninsteadofascreenshot,asfollows:

>varcase_matters='lower';>varCASE_MATTERS='upper';

> case_matters;"lower">CASE_MATTERS;"upper"

Thegreater-thansigns(>)showthecodethatyoutype;therestistheresultasprintedinConsole.

Page 64: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Again,rememberthatwhenyouseesuchcodeexamples,you'restronglyencouragedtotypeinthecodeyourself.Then,youcanexperimentbytweakingitalittlehereandtheretogetabetterfeelingofhowexactlyitworks.

Note

YoucanseeintheprecedingscreenshotthatsometimeswhatyoutypeinConsoleresultsinthewordundefined.Youcansimplyignorethis,butifyou'recurious,here'swhathappenswhenevaluating(executing)whatyoutype-theConsoleprintsthereturnedvalue.Someexpressions,suchasvara=1;,don'treturnanythingexplicitly,inwhichcase,theyimplicitlyreturnthespecialvalueundefined(moreoninabit).Whenanexpressionreturnssomevalue(forexample,case_mattersinthepreviousexampleorsomethingsuchas1+1),theresultingvalueisprintedout.Notallconsolesprinttheundefinedvalue;forexample,theFirebugconsole.

Page 65: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

OperatorsOperators take one or two values (or variables), perform an operation, and return a value. Let'scheckoutasimpleexampleofusinganoperator,justtoclarifytheterminology:

>1+2;3

Intheprecedingcode:

The+symbolistheoperatorTheoperationisadditionTheinputvaluesare1and2(theyarealsocalledoperands)Theresultvalueis3Thewholethingiscalledanexpression

Insteadofusingthevalues1and2directlyintheexpression,youcanusevariables.Youcanalsouseavariabletostoretheresultoftheoperationasthefollowingexampledemonstrates:

>vara=1;>varb=2;>a+1;2>b+2;4>a+b;3>varc=a+b;>c;3

Thefollowingtableliststhebasicarithmeticoperators:

Operatorsymbol

Operation Example

+ Addition>1+2;3

- Subtraction>99.99-11;88.99

* Multiplication>2*3;6

/ Division>6/4;1.5

Page 66: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

%Modulo,theremainderofadivision

>6%3;0>5%3;2

It'ssometimesusefultotestifanumberisevenorodd.Usingthemodulooperator,it'seasytodojustthat.Alloddnumbersreturn1whendividedby2,whileallevennumbersreturn0,forexample:

>4%2;0>5%2;1

++Incrementavalue by 1

Postincrementiswhentheinputvalueisincrementedafterit'sreturned,forexample:

>vara=123;>varb=a++;>b;123>a;124

Theoppositeispre-increment.Theinputvalueisincrementedby1firstandthenreturned,forexample:

>vara=123;>varb=++a;>b;124>a;124

--Decrementavalueby1

Post-decrement:

>vara=123;>varb=a--;>b;123>a;122

Pre-decrement:

>vara=123;>varb=--a;>b;122>a;122

Thevara=1;isalsoanoperation;it'sthesimpleassignmentoperation,and=isthesimpleassignmentoperator.

Thereisalsoafamilyof operatorsthatareacombinationofanassignmentandanarithmeticoperator. These are called compound operators. They can make your code more compact. Let'sseesomeofthemwiththefollowingexamples:

>vara=5;>a+=3;8

Page 67: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inthisexample,a+=3;isjustashorterwayofdoinga=a+3;.Forexample:

>a-=3;5

Here,a-=3;isthesameasa=a-3;:

>a*=2;10>a/=5;2>a%=2;0

Inadditiontothearithmeticandassignmentoperatorsdiscussedpreviously,thereareothertypesofoperators,asyou'llseelaterinthis,andthefollowingchapters.

Note

Bestpractice

Alwaysendyourexpressionswithasemicolon.JavaScripthasasemicoloninsertionmechanism,whereitcanaddthesemicolonifyouforgetitattheendofaline.However,thiscanalsobeasourceoferrors,soit'sbesttomakesureyoualwaysexplicitlystatewhereyouwanttoterminateyourexpressions.Inotherwords,bothexpressions>1+1and>1+1;willwork;butthroughoutthebook,you'llalwaysseethesecondtype,terminatedwithasemicolon,justtoemphasizethishabit.

Page 68: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Primitive data typesAny value that you use is of a certain type. In JavaScript, the following are just a few primitivedatatypes:

1. Number:Thisincludesfloatingpointnumbersaswellasintegers.Forexample,thesevaluesareallnumbers-1,100,3.14.

2. String:Theseconsistofanynumberofcharacters,forexample,a,one,andone2three.3. Boolean:Thiscanbeeithertrueorfalse.4. Undefined:Whenyoutrytoaccessavariablethatdoesn'texist,yougetthespecialvalueundefined.Thesamehappenswhenyoudeclareavariablewithoutassigningavaluetoityet.JavaScriptinitializesthevariablebehindthesceneswiththevalueundefined.Theundefineddatatype canonlyhaveonevalue-thespecialvalueundefined.

5. Null:Thisisanotherspecialdatatypethatcanhaveonlyonevalue-thenullvalue.Itmeansnovalue,anemptyvalue,ornothing.Thedifferencewithundefinedisthatifavariablehasanullvalue,it'sstilldefined;itjustsohappensthatitsvalueisnothing.You'llseesomeexamplesshortly.

Anyvaluethatdoesn'tbelongtooneofthefiveprimitivetypeslistedhereisanobject.Evennullisconsideredanobject,whichisalittleawkwardhavinganobject(something)thatisactuallynothing.We'lllearnmoreaboutobjectsinChapter4,Objects,butforthetimebeing,justrememberthatinJavaScript,thedatatypesareasfollows:

Primitive(thefivetypeslistedpreviously)Non-primitive(objects)

Page 69: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Findingoutthevaluetype-thetypeofoperator

Ifyouwanttoknowthetypeofavariableoravalue,youcanusethespecialtypeofoperator.Thisoperatorreturnsastringthatrepresentsthedatatype.Thereturnvaluesofusingtypeofareoneofthefollowing:

numberstringbooleanundefinedobjectfunction

Inthenextfewsections,you'llseetypeofinactionusingexamplesofeachofthefiveprimitivedatatypes.

Page 70: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Numbers

Thesimplestnumberisaninteger.Ifyouassign1toavariable,andthenusethetypeofoperator,itreturnsthestringnumber,asfollows:

>varn=1;>typeofn;"number">n=1234;>typeofn;"number"

Intheprecedingexample,youcanseethatthesecondtimeyousetavariable'svalue,youdon'tneedthevarstatement.

Numberscanalsobefloatingpoint(decimals),forexample:

>varn2=1.23;>typeofn;"number"

Youcancalltypeofdirectlyonthevaluewithoutassigningittoavariablefirst,forexample:

>typeof123;"number"

Octalandhexadecimalnumbers

Whenanumberstartswitha0,it'sconsideredan octalnumber.Forexample,theoctal0377isthedecimal255:

>varn3=0377;>typeofn3;"number">n3;255

Thelastlineintheprecedingexampleprintsthedecimalrepresentationoftheoctalvalue.

ES6providesaprefix0o(or0O,butthislooksveryconfusinginmostmonospacefonts)torepresentoctals.Considerthefollowinglineofcodeforexample:

console.log(0o776);//510

Whileyoumaynotbeintimatelyfamiliarwithoctalnumbers,you'veprobablyusedhexadecimalvaluestodefinecolorsinCSSstylesheets.

InCSS,youhaveseveraloptionstodefineacolor,twoofthemareasfollows:

Page 71: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

UsingdecimalvaluestospecifytheamountofR(red),G(green),andB(blue),rangingfrom0to255.Forexample,rgb(0,0,0)isblackandrgb(255,0,0)isred (maximumamountofredandnogreenor blue).UsinghexadecimalsandspecifyingtwocharactersforeachR,G,andBvalue.Forexample,#000000isblackand#ff0000isred.Thisisbecauseffisthehexadecimalvaluefor255.

InJavaScript,youcanput0xbeforeahexadecimalvalue,alsocalledhex forshort,forexample:

>varn4=0x00;>typeofn4;"number">n4;0>varn5=0xff;>typeofn5;"number">n5;255

BinaryLiterals

UntillES6,ifyouneededbinaryrepresentationofaninteger,youhadtopassthemtotheparseInt()functionasastringwitharadixof2,asfollows:

console.log(parseInt('111',2));//7

InES6youcanuse0b(or0B)prefixtorepresentbinaryintegers.Forexample:

console.log(0b111);//7

Exponentliterals

1e1(alsowrittenas1e+1or1E1or1E+1)representsthenumber1witha0afterit,orinotherwords,10.Similarly,2e+3representsthenumber2withthree0safterit,or2000,forexample:

>1e1;10>1e+1;

10>2e+3;2000>typeof2e+3;"number"

2e+3meansmovingthedecimalpointthreedigitstotherightofthenumber2.There'salso2e-3,meaningyoumovethedecimalpointthreedigitstotheleftofthenumber2.Lookatthefollowingfigure:

Page 72: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thefollowingisthecode:

>2e-3;0.002>123.456E-3;0.123456>typeof2e-3;"number"

Infinity

ThereisaspecialvalueinJavaScriptcalledInfinity.ItrepresentsanumbertoobigforJavaScripttohandle.Infinityisindeedanumber,astypingtypeofInfinityintheconsolewillconfirm.Youcanalsoquicklycheckthatanumberwith308zerosisok,but309zerosistoomuch.Tobeprecise,thebiggestnumberJavaScriptcanhandleis1.7976931348623157e+308,whilethesmallestis5e-324,Lookatthefollowingexample:

> Infinity;Infinity>typeofInfinity;"number">1e309;Infinity>1e308;1e+308

Dividingbyzerogivesyouinfinity,forexample:

>vara=6/0;>a;

Infinity

Infinityisthebiggestnumber(orratheralittlebiggerthanthebiggest),buthowaboutthe

Page 73: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

smallest?It'sinfinitywithaminussigninfrontofit;-Infinity,forexample:

>vari=-Infinity;>i;-Infinity>typeofi;"number"

Doesthismeanyoucanhavesomethingthat'sexactlytwiceasbigasInfinity,from0uptoinfinityandthenfrom0downtominusinfinity?Well,notreally.WhenyousumInfinityand-Infinity,youdon'tget0,butsomethingthatiscalledNotaNumber(NaN),Forexample:

>Infinity-Infinity;NaN>-Infinity+Infinity;NaN

AnyotherarithmeticoperationwithInfinityasoneoftheoperandsgivesyouInfinity,forexample:

>Infinity-20;Infinity>-Infinity*3;-Infinity>Infinity/2;Infinity>Infinity-99999999999999999;Infinity

Thereisalesserknownglobalmethod,isFinite(),thattellsyouifthevalueisinfinityornot.ES6addsaNumber.isFinite()methodtodojustthat.Whyanothermethod,youmayask.TheglobalvariantofisFinite()triestocastthevaluethroughNumber(value),whileNumber.isFinite()doesn't,henceit'smoreaccurate.

NaN

WhatwasthisNaNinthepreviousexample?Itturnsoutthatdespiteitsname,NotaNumber,NaNisaspecialvaluethatisalsoanumber:

>typeofNaN;"number">vara=NaN;>a;NaN

YougetNaNwhenyoutrytoperformanoperationthatassumesnumbers,buttheoperationfails.Forexample,ifyoutrytomultiply10bythecharacter"f",theresultisNaN,because"f"isobviouslynotavalidoperandforamultiplication:

Page 74: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>vara=10*"f";>a;NaN

NaNiscontagious,soifyouhaveevenoneNaNinyourarithmeticoperation,thewholeresultgoesdownthedrain,forexample:

>1+2+NaN;NaN

Number.isNaN

ES5hasaglobalmethod-isNaN().ItdeterminesifavalueisNaNornot.ES6providesaverysimilarmethod-Number.isNaN()(Noticethatthismethodisnotglobal).

ThedifferencebetweentheglobalisNaN()andNumber.isNaN()isthatglobalisNaN()castsnon-numericvaluesbeforeevaluatingthemtobeNaN.Let'slookatthefollowingexample.WeareusingtheES6Number.isNaN()methodtotestifsomethingisaNaNornot:

console.log(Number.isNaN('test'));//false:StringsarenotNaNconsole.log(Number.isNaN(123));//false:integersarenotNaNconsole.log(Number.isNaN(NaN));//true:NaNsareNaNsconsole.log(Number.isNaN(123/'abc'));//true:123/'abc'resultsinan

NaN

WesawthatES5'sglobalisNaN()methodfirstcastsnon-numericvaluesandthendoesthecomparison;thefollowingresultwillbedifferentfromitsES6counterpart:

console.log(isNaN('test'));//true

Ingeneral,comparedtoitsglobalvariant,Number.isNaN()ismorecorrect.However,neitherofthemcanbeusedtofigureoutifsomethingisnotanumber-theyjustanswerifthevalueisaNaNornot.Practically,youareinterestedinknowingifavalueidentifiesasanumberornot.Mozillasuggeststhefollowingpolyfillmethodtodojustthat:

functionisNumber(value){returntypeofvalue==='number'&&!Number.isNaN(value);}

Number.isInteger

ThisisanewmethodinES6.Itreturnstrueifthenumberisfiniteanddoesnotcontainanydecimalpoints(isaninteger):

console.log(Number.isInteger('test'));//falseconsole.log(Number.isInteger(Infinity));//falseconsole.log(Number.isInteger(NaN));//falseconsole.log(Number.isInteger(123));//trueconsole.log(Number.isInteger(1.23));//false

Page 75: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Strings

Astringisasequenceof charactersusedtorepresenttext.InJavaScript,anyvalueplacedbetweensingleordoublequotesisconsideredastring.Thismeansthat1isanumber,but"1"isastring.Whenusedwithstrings,typeofreturnsthestring"string",forexample:

> var s = "some characters";>typeofs;"string">vars='somecharactersandnumbers1235.87';>typeofs;"string"

Here'sanexampleofanumberusedinthestringcontext:

>vars='1';>typeofs;"string"

Ifyouputnothinginquotes,it'sstillastring(anemptystring),forexample:

>vars="";typeofs;"string"

Asyoualreadyknow,whenyouusetheplussignwithtwonumbers,thisisthearithmeticadditionoperation.However,ifyouusetheplussignwithstrings,thisisastringconcatenationoperation,anditreturnsthetwostringsgluedtogether:

>vars1="web";>vars2="site";

> var s = s1 + s2;>s;"website">typeofs;"string"

Thedualpurposeofthe+operatorisasourceoferrors.Therefore,ifyouintendtoconcatenatestrings,it'salwaysbesttomakesurethatalloftheoperandsarestrings.Thesameappliesforaddition;ifyouintendto addnumbersthenmakesuretheoperandsarenumbers.You'lllearnvariouswaystodosofurtherinthechapterandthebook.

Stringconversions

When you use a number-like string, for example, "1", as an operand in an arithmetic operation,the string is converted to a number behind the scenes. This works for all arithmetic operationsexceptaddition,becauseofitsambiguity.Considerthefollowingexample:

>vars='1';>s=3*s;

Page 76: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>typeofs;"number">s;3>vars='1';>s++;>typeofs;"number">s;2

Alazywaytoconvertanynumber-likestringtoanumberistomultiplyitby1(anotherwayistouseafunctioncalledparseInt(),asyou'llseeinthenextchapter):

>vars="100";typeofs;"string">s=s*1;100>typeofs;"number"

Iftheconversionfails,you'llgetNaN:

>varmovie='101dalmatians';>movie*1;NaN

Youcanconvertastringtoanumberbymultiplyingitby1.Theopposite-convertinganythingtoastring-canbedonebyconcatenatingitwithanemptystring,asfollows:

>varn=1;>typeofn;"number">n=""+n;"1">typeofn;"string"

Specialstrings

Therearealsostringswithspecialmeanings,aslistedinthefollowingtable:

String Meaning Example

\\

'

"

The\istheescapecharacter.Whenyouwanttohavequotesinsideyourstring,youcanescapethemsothatJavaScriptdoesn'tthinktheymeantheendofthestring.

Ifyouwanttohaveanactualbackslashinthestring,escapeit

>vars='Idon'tknow';:ThisisanerrorbecauseJavaScriptthinksthestringisIdonandtherestisinvalidcode.Thefollowingcodesarevalid:

> var s = 'I don't know';>vars="Idon'tknow";>vars="Idon'tknow";>vars='"Hello",hesaid.';>vars=""Hello",hesaid.";

Page 77: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

withanotherbackslash. Escapingtheescape:>vars="1\\2";s;"1\2"

\n Endofline.

>vars='\n1\n2\n3\n';>s;"123"

\r Carriagereturn.

Consider the following statements:

>vars='1\r2';>vars='1\n\r2';>vars='1\r\n2';

Theresultofalloftheseisasfollows:

>s;"12"

\t Tab.>vars="1\t2";>s;"12"

\uThe\ufollowedbyacharactercodeallowsyoutouseUnicode.

Here'smynameinBulgarianwrittenwithCyrilliccharacters:

>"\u0421\u0442\u043E\u044F\u043D";"Стoян"

Therearealsoadditionalcharactersthatarerarelyused:\b(backspace),\v(verticaltab),and\f(formfeed).

Stringtemplateliterals

ES6introducedtemplateliterals.Ifyouarefamiliarwithotherprogramminglanguages,PerlandPythonhavesupportedtemplateliteralsforawhilenow.Templateliteralsallowexpressionstobeembeddedwithinregularstrings.ES6hastwokindsofliterals:templateliteralsandtaggedliterals.

Templateliteralsaresingleormultiplelinestringswithembeddedexpressions.Forexample,youmusthavedonesomethingsimilartothis:

varlog_level="debug";varlog_message="meltdown";console.log("Loglevel:"+log_level+"-message:"+log_message);//Loglevel:debug-message:meltdown

Page 78: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Youcanaccomplishthesameusingtemplateliterals,asfollows:

console.log(`Loglevel:${log_level}-message:${log_message}`)

Templateliteralsareenclosedbytheback-tick(``)(graveaccent)characterinsteadoftheusualdoubleorsinglequotes.Templateliteralplaceholdersareindicatedbythedollarsignandcurlybraces(${expression}).Bydefault,theyareconcatenatedtoformasinglestring.Thefollowingexampleshowsatemplateliteralwithaslightlycomplexexpression:

vara=10;varb=10;console.log(`Sumis${a+b}andMultiplicationwouldbe${a*b}.`);//Sumis20andMultiplicationwouldbe100.

Howaboutembeddingafunctioncall?

vara=10;varb=10;functionsum(x,y){returnx+y}

function multi(x,y){returnx*y}console.log(`Sumis${sum(a,b)}andMultiplicationwouldbe${multi(a,b)}.`);

Templateliteralsalsosimplifymultilinestringsyntax.Insteadofwritingthefollowinglineofcode:

console.log("Thisislineone\n"+"andthisislinetwo");

Youcanhaveamuchcleanersyntaxusingtemplateliterals,whichisasfollows:

console.log(`Thisislineoneandthisislinetwo`);

ES6hasanotherinterestingliteraltypecalledTaggedTemplateLiterals.Taggedtemplatesallowyoutomodifytheoutputoftemplateliteralsusingafunction.Ifyouprefixanexpressiontoatemplateliteral,thatprefixisconsideredtobeafunctiontobeinvoked.Thefunctionneedstobe defined before we can use the tagged template literal. For example, the following expression:

transform`Nameis${lastname},${firstname}${lastname}`

Theprecedingexpressionisconvertedintoafunctioncall:

transform([["Nameis",",",""],firstname,lastname)

Thetagfunction,'transform',getstwoparameters-templatestringslikeNameisandsubstitutionsdefinedby${}.Thesubstitutionsareonlyknownatruntime.Let'sexpandthetransform

Page 79: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

function:

functiontransform(strings,...substitutes){console.log(strings[0]);//"Nameis"console.log(substitutes[0]);//Bond}varfirstname="James";varlastname="Bond"transform`Nameis${lastname},${firstname}${lastname}`

When template strings (Name is) are passed to the tag function, there are two forms of eachtemplate string, as follows:

TherawformwherethebackslashesarenotinterpretedThecookedformwherethebackslasheshas specialmeaning

Youcanaccesstherawstringformusingrawproperty,asthefollowingexampleshows:

functionrawTag(strings,...substitutes){console.log(strings.raw[0])}rawTag`Thisisarawtextand\narenottreateddifferently`//Thisisarawtextand\narenottreateddifferently

Page 80: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Booleans

ThereareonlytwovaluesthatbelongtotheBooleandatatype-thetrueandfalsevaluesusedwithoutquotes:

> var b = true;>typeofb;"boolean">varb=false;>typeofb;"boolean"

Ifyouquotetrueorfalse,theybecomestrings,asshowninthefollowingexample:

> var b = "true";>typeofb;"string"

Logical operators

Therearethreeoperators,calledlogicaloperators,thatworkwithBooleanvalues.Theseareasfollows:

!-logicalNOT(negation)&&-logicalAND||-logicalOR

Youknowthatwhensomethingisnottrue,itmustbefalse.Here'showthisisexpressedusingJavaScriptandthelogical!operator:

>varb=!true;>b;false

IfyouusethelogicalNOTtwice,youwillgettheoriginalvalue,whichisasfollows:

>varb=!!true;>b;true

Ifyouusealogicaloperatoronanon-Booleanvalue,thevalueisconvertedtoBooleanbehindthescenes,asfollows:

>varb="one";>!b;false

Intheprecedingcase,thestringvalue"one"isconvertedtoaBoolean,true,andthennegated.Theresultofnegatingtrueisfalse.Inthefollowingexample,there'sadoublenegation,sothe

Page 81: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

resultistrue:

>varb="one";>!!b;true

You can convert any value to its Boolean equivalent using a double negation. Understanding howanyvalueconvertstoaBooleanisimportant.Mostvaluesconverttotruewiththeexceptionofthefollowing,whichconverttofalse:

Theemptystring""nullundefinedThenumber0ThenumberNaNTheBooleanfalse

Thesesixvaluesarereferredtoasfalsy,whileallothersaretruthy,(including,forexample,thestrings"0","",and"false").

Let'sseesomeexamples oftheothertwooperators-thelogicalAND(&&)andthelogicalOR(||).Whenyouuse&&,theresultistrueonlyifalloftheoperandsaretrue.Whenyouuse||,theresultistrueifatleastoneoftheoperandsistrue:

>varb1=true,b2=false;> b1 || b2;

true>b1&&b2;false

Here'salistofthepossibleoperationsandtheirresults:

Operation Result

true&&true true

true&&false false

false&&true false

false&&false false

true||true true

true||false true

Page 82: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

false||true true

false||false false

Youcanuseseverallogicaloperationsoneaftertheother,asfollows:

>true&&true&&false&&true;false>false||true||false;true

Youcanalsomix&&and ||inthesameexpression.Insuchcases,youshoulduseparenthesestoclarifyhowyouintendtheoperationtowork.Considerthefollowingexample:

>false&&false||true&&true;true>false&&(false||true)&&true;false

Operatorprecedence

Youmightwonderwhythepreviousexpression(false&&false||true&&true)returnedtrue.Theanswerliesintheoperatorprecedence,asyouknowfrommathematics:

>1+2*3;7

Thisisbecausemultiplicationhasahigherprecedenceoveraddition,so2*3isevaluatedfirst,asifyoutyped:

>1+(2*3);7

Similarlyforlogicaloperations,!hasthehighestprecedenceandisexecutedfirst,assumingtherearenoparenthesesthatdemandotherwise.Then,intheorderofprecedence,comes&&andfinally,||.Inotherwords,thefollowingtwocodesnippetsarethesame.Thefirstoneisasfollows:

>false&&false||true&&true;true

Andthesecondoneisasfollows:

>(false&&false)||(true&&true);true

Note

Bestpractice

Page 83: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Useparenthesesinsteadofrelyingonoperatorprecedence.Thismakesyourcodeeasiertoreadandunderstand.

The ECMAScript standard defines the precedence of operators. While it may be a goodmemorizationexercise,thisbookdoesn'tofferit.Firstofall,you'llforgetit,andsecond,evenifyoumanagetorememberit,youshouldn'trelyonit.Thepersonreadingandmaintainingyourcodewilllikelybeconfused.

Lazyevaluation

Ifyouhaveseverallogicaloperationsoneaftertheother,buttheresultbecomesclearatsomepointbeforetheend,thefinaloperationswillnot beperformedbecausetheydon'taffecttheendresult.Considerthefollowinglineofcodeasanexample:

>true||false||true||false||true;true

AstheseareallORoperationsandhavethesameprecedence,theresultwillbetrueifatleast,oneoftheoperandsistrue.Afterthefirstoperandisevaluated,itbecomesclearthattheresultwillbetrue,nomatterwhatvaluesfollow.So,theJavaScriptenginedecidestobelazy(OK,efficient)andavoidsunnecessaryworkbyevaluatingcodethatdoesn'taffecttheendresult.Youcanverifythisshort-circuitingbehaviorbyexperimentingintheconsole,asshowninthefollowingcodeblock:

>varb=5;> true || (b = 6);

true>b;5>true&&(b=6);6>b;6

Thisexamplealsoshowsanotherinterestingbehavior-ifJavaScriptencountersanon-Booleanexpressionasanoperandinalogicaloperation,thenon-Booleanisreturnedasaresult:

>true||"something";true>true&&"something";"something">true&&"something"&&true;true

Thisbehaviorisnotsomethingyoushouldrelyonbecauseitmakesthecodehardertounderstand.It's common to use this behavior to define variables when you're not sure whether they werepreviouslydefined.Inthenextexample,ifthemynumbervariableisdefined,itsvalueiskept;otherwise,it'sinitializedwiththevalue10:

Page 84: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>varmynumber=mynumber||10;>mynumber;10

Thisissimpleandlooks elegant,butbeawarethatit'snotcompletelyfoolproof.Ifmynumberisdefinedandinitializedto0,ortoanyofthesixfalsyvalues,thiscodemightnotbehaveasyouexpect,asshowninthefollowingpieceofcode:

>varmynumber=0;>varmynumber=mynumber||10;>mynumber;

10

Comparison

There'sanothersetofoperatorsthatallreturnaBooleanvalueasaresultoftheoperation.Thesearethecomparisonoperators.Thefollowingtableliststhemtogetherwithexampleuses:

Operatorsymbol

Description Example

==Equalitycomparison:Thisreturnstruewhenbothoperandsareequal.Theoperandsareconvertedtothesametypebeforebeingcompared.They'realsocalledloosecomparison.

>1==1;true>1==2;false>1=='1';true

===Equalityandtype comparison:Thisreturnstrueifbothoperandsareequalandofthesametype.It'sbetterandsafertocomparethiswaybecausethere'snobehind-the-scenestypeconversions.Itisalsocalledstrictcomparison.

>1==='1';false>1===1;true

!=Non-equalitycomparison:Thisreturnstrueiftheoperandsarenotequaltoeachother(afteratypeconversion).

> 1 !=1;false>1!='1';false>1!='2';true

!==Non-equalitycomparisonwithouttype conversion:Returnstrueiftheoperandsarenotequaloriftheyareofdifferenttypes.

>1!==1;false>1!=='1';true

>1>1;

Page 85: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

> Thisreturnstrueiftheleftoperandisgreaterthantherightone.

false>33>22;true

>= Thisreturnstrueiftheleftoperandisgreaterthanorequaltotherightone.>1>=1;true

< Thisreturnstrueiftheleftoperandislessthantherightone.

>1<1;false>1<2;true

<= Thisreturnstrueiftheleftoperandislessthanorequaltotherightone.

>1<=1;true>1<=2;true

NotethatNaNisnotequaltoanything,notevenitself.Takealookatthefollowinglineofcode:

>NaN==NaN;false

Page 86: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Undefinedandnull

Ifyoutrytouseanon-existingvariable,you'llgetthefollowingerror:

> foo;ReferenceError:fooisnotdefined

Usingthetypeofoperatoronanon-existingvariableisnotanerror.Youwillgetthe"undefined"stringback,asfollows:

>typeoffoo;"undefined"

Ifyoudeclareavariablewithoutgivingitavalue,thisis,ofcourse,notanerror.But,thetypeofstillreturns"undefined":

>varsomevar;>somevar;>typeofsomevar;"undefined"

This is because, when you declare a variable without initializing it, JavaScript automaticallyinitializesitwiththeundefinedvalue,asshowninthefollowinglinesofcode:

>varsomevar;>somevar===undefined;true

Thenullvalue,ontheotherhand,isnotassignedbyJavaScriptbehindthescenes;it'sassignedbyyourcode,whichisasfollows:

>varsomevar=null;null>somevar;null>typeofsomevar;"object"

Althoughthedifferencebetweennullandundefinedissmall,itcanbecriticalattimes.Forexample,ifyouattemptanarithmeticoperation,youwillgetdifferentresults:

> var i = 1 + undefined;>i;NaN>vari=1+null;>i;1

Thisisbecauseofthedifferentwaysnullandundefinedareconvertedtotheotherprimitive

Page 87: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

types.Thefollowingexamplesshowthepossibleconversions:

Conversiontoanumber:

> 1 * undefined;

ConversiontoNaN:

>1*null;0

ConversiontoaBoolean:

>!!undefined;false>!!null;false

Conversiontoastring:

>"value:"+null;"value:null">"value:"+undefined;"value:undefined"

Page 88: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Symbols

ES6introducedanewprimitivetype-symbols.Severallanguageshaveasimilarnotion.Symbolslookverysimilartoregularstrings,buttheyareverydifferent.Let'sseehowthesesymbolsarecreated:

varatom=Symbol()

Noticethatwedon'tusenewoperatorwhilecreatingsymbols.Youwillgetanerrorwhenyoudouseit:

varatom=newSymbol()//Symbolisnotaconstructor

YoucandescribeSymbolaswell:

varatom=Symbol('atomicsymbol')

Describingsymbolscomesinveryhandywhiledebugginglargeprogramswheretherearelotsofsymbolsscatteredacross.

ThemostimportantpropertyofSymbol(andhencethereasonoftheirexistence)isthattheyareuniqueandimmutable:

console.log(Symbol()===Symbol())//falseconsole.log(Symbol('atom')===Symbol('atom'))//false

Fornow,wewillhavetopausethisdiscussiononsymbols.Symbolsareusedaspropertykeysandplaceswhereyouneeduniqueidentifiers.Wewilldiscusssymbolsinalaterpartofthisbook.

Page 89: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Primitive data types recapLet's quickly summarize some of the main points discussed so far:

TherearefiveprimitivedatatypesinJavaScript:NumberStringBooleanUndefinedNull

Everythingthatisnotaprimitivedatatypeisanobject.

Theprimitivenumberdatatypecanstorepositiveandnegativeintegersorfloats,hexadecimalnumbers,octalnumbers,exponents,andthespecialnumbers-NaN,Infinity,and-Infinity.Thestringdatatypecontainscharactersinquotes.Templateliteralsallowembeddingofexpressionsinsideastring.TheonlyvaluesoftheBooleandatatypearetrueandfalse.Theonlyvalueofthenulldatatypeisthenullvalue.Theonlyvalueoftheundefineddatatypeistheundefinedvalue.AllvaluesbecometruewhenconvertedtoaBoolean,withtheexceptionofthefollowingsixfalsyvalues:

""

null

undefined

0

NaN

false

Page 90: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ArraysNow that you know about the basic primitive data types in JavaScript, it's time to move to a morepowerfuldatastructure-thearray.

So,whatisanarray?It'ssimplyalist(asequence)ofvalues.Insteadofusingonevariabletostoreonevalue,youcanuseonearrayvariabletostoreanynumberofvaluesaselementsofthearray.

Todeclareavariablethatcontainsanemptyarray,youcanusesquarebracketswithnothingbetweenthem,asshowninthefollowinglineofcode:

>vara=[];

Todefineanarraythathasthreeelements,youcanwritethefollowinglineofcode:

>vara=[1,2,3];

Whenyousimplytypethenameofthearrayintheconsole,youcangetthecontentsofyourarray:

>a;[1,2,3]

Nowthequestionishowtoaccessthevaluesstoredinthesearrayelements.Theelementscontainedinanarrayareindexedwithconsecutivenumbers,startingfromzero.Thefirstelementhasindex(orposition)0,thesecondhasindex1, andsoon.Here'sthethree-elementarrayfromthepreviousexample:

Index Value

0 1

1 2

2 3

Toaccessanarrayelement,youcanspecifytheindexofthatelementinsidesquarebrackets.So,a[0]givesyouthefirstelementofthearraya,a[1]givesyouthesecond,andsoon,asshowninthefollowingexample:

>a[0];1>a[1];2

Page 91: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Adding/updatingarrayelements

Usingtheindex,youcanalsoupdatethevaluesoftheelementsofthearray.Thenextexampleupdatesthethirdelement(index2)andprintsthecontentsofthenewarray,asfollows:

>a[2]='three';"three">a;[1,2,"three"]

Youcanaddmoreelementsbyaddressinganindexthatdidn'texistbefore,asshowninthefollowing lines of code:

>a[3]='four';"four">a;[1,2,"three","four"]

Ifyouaddanewelementbutleaveagapinthearray,thoseelementsinbetweendon'texistandreturntheundefinedvalueifaccessed.Checkoutthefollowingexample:

>vara=[1,2,3];>a[6]='n`xew';"new">a;[1,2,3,undefinedx3,"new"]

Page 92: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Deletingelements

Todeleteanelement,youcanusethedeleteoperator.However,afterthedeletion,thelengthofthearraydoesnotchange.Inasense,youmaygetaholeinthearray:

> var a = [1, 2, 3];>deletea[1];true>a;[1,undefined,3]>typeofa[1];"undefined"

Page 93: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Arraysofarrays

Arrayscancontainalltypesofvalues,includingotherarrays:

> var a = [1, "two", false, null, undefined];>a;[1,"two",false,null,undefined]>a[5]=[1,2,3];[1,2,3]>a;[1,"two",false,null,undefined,Array[3]]

TheArray[3]intheresultisclickableintheconsoleanditexpandsthearrayvalues.Let'slookatanexamplewhereyouhaveanarrayoftwoelements,bothofthembeingotherarrays:

>vara=[[1,2,3],[4,5,6]];>a;[Array[3],Array[3]]

Thefirstelementofthearrayis[0],andit'salso anarray:

>a[0];[1,2,3]

To access an element in the nested array, you can refer to the element index in another set ofsquarebrackets,asfollows:

>a[0][0];1>a[1][2];6

Notethatyoucanusethearraynotationtoaccess individualcharactersinsideastring,asshowninthefollowingcodeblock:

>vars='one';>s[0];"o"

> s[1];"n">s[2];"e"

Note

Arrayaccesstostringswassupportedbymanybrowsersforawhile(notolderIEs),butitwasofficiallyrecognizedonlyaslateasECMAScript5.

Therearemorewaystohavefunwitharrays(andwegettothoseinChapter4,Objects),butlet'sstopherefornow,rememberingthefollowingpoints:

Page 94: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

AnarrayisadatastoreAnarraycontainsindexedelementsIndexesstartfromzeroandincrementbyoneforeachelementinthearrayToaccessanelementofanarray,youcanuseitsindexinsquarebracketsAnarraycancontainanytypeofdata,includingotherarrays

Page 95: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Conditions and loopsConditions provide a simple but powerful way to control the flow of code execution. Loopsallowyoutoperformrepetitiveoperationswithlesscode.Let'stakealookat:

ifconditionsswitchstatementswhile,do...while,for,andfor...inloops

Note

TheexamplesinthefollowingsectionsrequireyoutoswitchtothemultilineFirebugconsole.Or,ifyouusetheWebKitconsole,pressShift+EnterinsteadofEntertoaddanewline.

Page 96: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Codeblocks

Intheprecedingexamples,yousawtheuseofcodeblocks.Let'stakeamomenttoclarifywhatablockofcodeis,becauseyouwilluseblocksextensivelywhenconstructingconditionsandloops.

Ablockofcodeconsistsofzeroormoreexpressionsenclosedincurlybrackets,whichisshowninthefollowinglinesofcode:

{vara=1;varb=3;}

Youcannestblockswithineachotherindefinitely,asshowninthefollowingexample:

{vara=1;varb=3;varc,d;{c=a+b;{d=a-b;}}}

Note

Bestpracticetips

Useend-of-linesemicolons,asdiscussedpreviouslyinthechapter.Althoughthesemicolonisoptionalwhenyouhaveonlyoneexpressionperline,it'sgoodtodevelopthehabitofusingthem.Forbestreadability,theindividualexpressionsinsideablockshouldbeplacedoneperlineandseparatedbysemicolons.

Indentanycodeplacedwithincurlybrackets.Someprogrammerslikeonetabindentation,someusefourspaces,andsomeusetwospaces.Itreallydoesn'tmatter,aslongasyou'reconsistent.Intheprecedingexample,theouterblockisindentedwithtwospaces,thecodeinthefirstnestedblockisindentedwithfourspaces,andtheinnermostblockisindentedwithsixspaces.

Use curly brackets. When a block consists of only one expression, the curly brackets are optional,butforreadabilityandmaintainability,youshouldgetintothehabitofalwaysusingthem,evenwhenthey'reoptional.

Theifcondition

Page 97: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Here'sasimpleexampleofanifcondition:

varresult='',a=3;if(a>2){result='aisgreaterthan2';}

Thepartsoftheifconditionareasfollows:

TheifstatementAconditioninparentheses-isagreaterthan2?Ablockofcodewrappedin{}thatexecutesiftheconditionissatisfied

Thecondition(thepartinparentheses)alwaysreturnsaBooleanvalue,andmayalsocontainthefollowing:

Alogicaloperation-!,&&,or||Acomparison,suchas===,!=,>,andsoonAnyvalueorvariablethatcanbeconvertedtoaBooleanAcombinationoftheabove

Theelseclause

Therecanalsobeanoptionalelsepartoftheifcondition.Theelsestatementisfollowedbyablockofcodethatrunsiftheconditionevaluatestofalse:

if(a>2){result='aisgreaterthan2';}else{result='aisNOTgreaterthan2';}

Inbetweentheifandtheelsestatements,therecanalsobeanunlimitednumberofelse...ifconditions.Here'sanexample:

if(a>2||a<-2){result='aisnotbetween-2and2';}elseif(a===0&&b===0){result='bothaandbarezeros';}elseif(a===b){result='aandbareequal';}else{result='Igiveup';}

Youcanalsonestconditionsbyputtingnewconditionswithinanyoftheblocks,asshowninthefollowingpieceofcode:

if(a===1){if(b===2){

Page 98: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

result='ais1andbis2';}else{result='ais1butbisdefinitelynot2';}}else{result='aisnot1,noideaaboutb';}

Checkingifavariableexists

Let'sapplythenewknowledgeaboutconditionsforsomethingpractical.It'softennecessarytocheckwhetheravariableexists.Thelaziestwaytodothisistosimplyputthevariableintheconditionpartoftheifstatement,forexample,if(somevar){...}.But,thisisnotnecessarilythebestmethod.Let'stakealookatanexamplethattestswhetheravariablecalledsomevarexists,andifso,setstheresultvariabletoyes:

>varresult='';>if(somevar){result='yes';}ReferenceError:somevarisnotdefined>result;""

Thiscodeobviouslyworksbecausetheendresultwasnotyes.Butfirstly,thecodegeneratedanerror-somevarisnotdefined,andyoudon'twant yourcodetobehavelikethat.Secondly,justbecauseif(somevar)returnsfalse,itdoesn'tmeanthatsomevarisnotdefined.Itcouldbethatsomevarisdefinedandinitializedbutcontainsafalsyvaluelikefalseor0.

Abetterwaytocheckifavariableisdefinedistousetypeof:

>varresult="";>if(typeofsomevar!=="undefined"){result="yes";

}>result;""

Thetypeofoperatoralwaysreturnsastring,andyoucancomparethisstringwiththestring"undefined".Notethatthesomevarvariablemayhavebeendeclaredbutnotassignedavalueyetandyou'llstillgetthesameresult.So,whentestingwithtypeoflikethis,you'rereallytestingwhetherthevariablehas anyvalueotherthantheundefinedvalue:

>varsomevar;>if(typeofsomevar!=="undefined"){result="yes";

}>result;""

Page 99: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>somevar=undefined;>if(typeofsomevar!=="undefined"){result="yes";}>result;""

Ifavariableisdefinedandinitializedwithanyvalueotherthanundefined,itstypereturnedbytypeofisnolonger"undefined",asshowninthefollowingpieceofcode:

>somevar=123;>if(typeofsomevar!=="undefined"){result='yes';}>result;"yes"

Alternativeifsyntax

Whenyouhaveasimplecondition,youcanconsiderusinganalternativeifsyntax.Takealookatthis:

vara=1;varresult='';

if (a === 1) {result="aisone";}else{result="aisnotone";}

Youcanalsowritethisas:

>vara=1;>varresult=(a===1)?"aisone":"aisnotone";

Youshouldonlyusethissyntaxforsimpleconditions.Becarefulnottoabuseit,asitcaneasilymakeyourcodeunreadable.Here'sanexample.

Let'ssayyouwanttomakesureanumberiswithinacertainrange,saybetween50and100:

>vara=123;>a=a>100?100:a<50?50:a;>a;100

Itmaynotbeclearhowthiscodeworksexactlybecauseofthemultiple?.Addingparenthesesmakesitalittleclearer,asshowninthefollowingcodeblock:

>vara=123;>a=(a>100?100:a<50)?50:a;>a;

Page 100: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

50>vara=123;>a=a>100?100:(a<50?50:a);>a;100

?:iscalledaternaryoperatorbecauseittakesthreeoperands.

Switch

Ifyoufindyourselfusinganifconditionandhavingtoomanyelse...ifparts,youcanconsiderchangingtheiftoaswitch,asfollows:

vara='1',result='';switch(a){case1:result='Number1';break;case'1':result='String1';break;default:result='Idon'tknow';break;}

Theresultafterexecutingthisis"String1".Let'sseewhatthepartsofaswitchare:

Theswitchstatement.Anexpressioninparentheses.Theexpressionmostoftencontainsavariable,butcanbeanythingthatreturnsavalue.Anumberofcaseblocksenclosedincurlybrackets.Eachcasestatementisfollowedbyanexpression.Theresultoftheexpressioniscomparedtotheexpressionfoundaftertheswitchstatement.Iftheresultofthecomparisonistrue,thecodethatfollowsthecolonafterthecaseisexecuted.Thereisanoptionalbreakstatementtosignaltheendofthecaseblock.Ifthisbreakstatementisreached,theswitchstatementisalldone.Otherwise,ifthebreakismissing,theprogramexecutionentersthenextcaseblock.There'sanoptionaldefaultcasemarkedwiththedefaultstatementandfollowedbyablockofcode.Thedefaultcaseisexecutedifnoneofthepreviouscasesevaluatedtotrue.

Inotherwords,thestep-by-stepproceduretoexecuteaswitchstatementisasfollows:

1. Evaluate the switch expression found in parentheses; remember it.2. Move to the first case and compare its value with the one fromStep 1.3. IfthecomparisoninStep2returnstrue,executethecodeinthecaseblock.4. Afterthecaseblockisexecuted,ifthere'sabreakstatementattheendofit,exitswitch.

Page 101: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

5. Ifthere'snobreakorStep2returnedfalse,moveontothenextcaseblock.6. Repeatsteps2to5.7. Ifyouarestillhere(noexitinStep4),executethecodefollowingthedefaultstatement.

Tip

Indentthecodethatfollowsthecaselines.Youcanalsoindentcasefromtheswitch,butthatdoesn'tgiveyoumuchin termsofreadability.

Don'tforgettobreak

Sometimes,youmaywanttoomitthebreakintentionally,butthat'srare.It'scalledafall-throughandshouldalwaysbedocumentedbecauseitmaylooklikeanaccidentalomission.Ontheotherhand,sometimesyoumaywanttoomitthewholecodeblockfollowingacaseandhavetwocasessharingthesamecode.Thisisfine,butitdoesn'tchangetherulethatifthere'scodethatfollowsacasestatement,thiscodeshouldendwithabreak.Intermsofindentation,aligningthebreakwiththecaseorwiththecodeinsidethecaseisapersonalpreference;again,beingconsistentiswhatmatters.

Usethedefaultcase.Thishelpsyoumakesurethatyoualwayshaveameaningfulresultaftertheswitchstatement,evenifnoneofthecasesmatchesthevaluebeingswitched.

Page 102: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Loops

Theif...elseandswitchstatementsallowyourcodetotakedifferentpaths,asifyou'reatacrossroad,anddecidewhichwaytogodependingonacondition.Loops,ontheotherhand,allowyourcodetotakeafewroundaboutsbeforemergingbackintothemainroad.Howmanyrepetitions?Thatdependsontheresultofevaluatingaconditionbefore(orafter)eachiteration.

Let'ssayyouare(yourprogramexecutionis)travelingfromAtoB.Atsomepoint,youwillreachaplacewhereyouhavetoevaluateacondition,C.TheresultofevaluatingCtellsyouwhetheryoushouldgointoaloop,L.YoumakeoneiterationandarriveatCagain.Then,youevaluatetheconditiononceagaintoseeifanotheriterationisneeded.Eventually,youmoveonyourwaytoB:

Aninfiniteloopiswhentheconditionisalwaystrue,andyourcodegetsstuckintheloopforever.Thisis,ofcourse,alogicalerror,andyoushouldlookoutforsuchscenarios.

InJavaScript,thefollowingarethefourtypesofloops:

whileloopsdo-whileloopsforloopsfor-inloops

While loops

Thewhileloopsarethesimplesttypeofiteration.Theylooklikethefollowing:

vari=0;while(i<10){i++;

Page 103: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}

Thewhilestatementisfollowedbyaconditioninparenthesesandacodeblockincurlybrackets.Aslongastheconditionevaluatestotrue,thecodeblockisexecutedoverandoveragain.

Do-whileloops

Thedo...whileloopsareaslightvariationofwhileloops.Anexampleisshownasfollows:

vari=0;do{

i++;}while(i<10);

Here,thedostatementisfollowedbyacodeblockandaconditionaftertheblock.Thismeansthatthecodeblockisalwaysexecuted,atleastonce,beforetheconditionisevaluated.

Ifyouinitializeito11insteadof0inthelasttwoexamples,thecodeblockinthefirstexample(thewhileloop)willnotbeexecuted,andiwillstillbe11attheend,whileinthesecond(thedo...whileloop),thecodeblockwillbeexecutedonceandiwillbecome12.

Forloops

Theforloopisthemostwidelyusedtypeofloop,andyoushouldmakesureyou'recomfortablewiththisone.Itrequiresjustalittlebitmoreintermsofsyntax:

InadditiontotheCconditionandtheLcodeblock,youhavethefollowing:

Initialization:Thisisthecodethatisexecutedbeforeyouevenentertheloop(markedwith0inthediagram)Increment:Thisisthecodethatisexecutedaftereveryiteration(markedwith++inthe

Page 104: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

diagram)

Thefollowingisthemostwidelyusedforlooppattern:

Intheinitializationpart,youcandefineavariable(orsettheinitialvalueofanexistingvariable),mostoftencallediIntheconditionpart,youcancompareitoaboundaryvalue,suchasi<100Intheincrementpart,youcanincreaseiby1,suchasi++

Here'sanexample:

varpunishment='';for(vari=0;i<100;i++){punishment+='Iwillneverdothisagain,';}

Allthreeparts(initialization,condition,andincrement)cancontainmultipleexpressionsseparatedbycommas.Sayyouwanttorewritetheexampleanddefinethevariablepunishmentinsidetheinitializationpartoftheloop:

for(vari=0,punishment='';i<100;i++){punishment+='Iwillneverdothisagain,';}

Canyoumovethebodyoftheloopinsidetheincrementpart?Yes,youcan,especiallyasit'saone-liner.Thisgivesyoualoopthatlooksalittleawkward,asithasnobody.Notethatthisisjustanintellectualexercise;it'snotrecommendedthatyouwriteawkward-lookingcode:

for(vari=0,punishment='';i<100;i++,punishment+='Iwillneverdothisagain,'){

//nothinghere

}

Thesethreepartsarealloptional.Here'sanotherwayofrewritingthesameexample:

vari=0,punishment='';for(;;){punishment+='Iwillneverdothisagain,';if(++i==100){break;}}

Althoughthelastrewriteworksexactlythesamewayastheoriginal,it'slongerandhardertoread.It'salsopossibletoachievethesameresult usingawhileloop.But,theforloopsmakethe

Page 105: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

codetighterandmorerobustbecausethemeresyntaxoftheforloopmakesyouthinkaboutthethreeparts(initialization,condition,andincrement),andthushelpsyoureconfirmyourlogicandavoidsituationssuchasbeingstuckinaninfiniteloop.

The for loops can be nested within each other. Here's an example of a loop that is nested insideanother loop and assembles a string containing ten rows and ten columns of asterisks. Think of ibeing the row and j being the column of an image:

varres='\n';for(vari=0;i<10;i++){for(varj=0;j<10;j++){res+='*';}res+='\n';}

Theresultisastring,asshownhere:

"****************************************************************************************************"

Here'sanotherexamplethatusesnestedloopsandamodulooperationtodrawasnowflake-likeresult:

varres='\n',i,j;for(i=1;i<=7;i++){for(j=1;j<=15;j++){res+=(i*j)%8?'':'*';}res+='\n';}

Theresultisasfollows:

"****************

Page 106: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

*"

For...inloops

Thefor...inloopisusedtoiterateovertheelementsofanarray,oranobject,asyou'llseelater.Thisisitsonlyuse;itcannotbeusedasageneral-purposerepetitionmechanismtoreplacefororwhile.Let'sseeanexampleofusingafor-intoloopthroughtheelementsofanarray.But,bearinmindthatthisisforinformationalpurposesonly,asfor...inismostlysuitableforobjectsandtheregularforloopshouldbeusedforarrays.

Inthisexample,youcaniterateoveralloftheelementsofanarrayandprintouttheindex(thekey)andthevalueofeachelement,forexample:

//exampleforinformationonly//for-inloopsareusedforobjects//regularforisbettersuitedforarrays

vara=['a','b','c','x','y','z'];

varresult='\n';

for(variina){result += 'index: ' + i + ', value: ' + a[i] + '\n';

}Theresultis:"index:0,value:aindex:1,value:bindex:2,value:cindex:3,value:xindex:4,value:yindex:5,value:z"

Page 107: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CommentsOne last thing for this chapter-comments. Inside your JavaScript program, you can put comments.TheseareignoredbytheJavaScriptengineanddon'thaveanyeffectonhowtheprogramworks.Buttheycanbeinvaluablewhenyourevisityourcodeafterafewmonths,ortransferthecodetosomeoneelseformaintenance.

Thefollowingtwotypes ofcommentsareallowed:

Single line comments start with // and end at the end of the line.Multiline comments start with /* and end with */ on the same line or any subsequent line.Note that any code in between the comment start and the comment end is ignored.

Someexamplesareasfollows:

//beginningofline

vara=1;//anywhereontheline

/*multi-linecommentonasingleline*/

/*commentthatspansseverallines*/

There are even utilities, such as JSDoc and YUIDoc, that can parse your code and extractmeaningfuldocumentationbasedonyourcomments.

Page 108: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Whatistheresultofexecutingeachoftheselinesintheconsole?Why?

>vara;typeofa;>vars='1s';s++;>!!"false";>!!undefined;

> typeof -Infinity;>10%"0";>undefined==null;>false==="";>typeof"2E+2";>a=3e+3;a++;

2. Whatisthevalueofvafterthefollowing?

>varv=v||10;

Experimentbyfirstsettingvto100,0,ornull.3. Writeasmallprogramthatprintsoutthemultiplicationtable.Hint:usealoopnestedinsideanotherloop.

Page 109: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, you learned a lot about the basic building blocks of a JavaScript program. Nowyouknowthefollowingprimitivedatatypes:

NumberStringBooleanUndefinedNull

Youalsoknowquiteafewoperators,whichareasfollows:

Arithmeticoperators:+,-,*,/,and%Incrementoperators:++and-Assignmentoperators:=,+=,-=,*=,/=,and%=Specialoperators:typeofanddeleteLogicaloperators:&&,||,and!Comparisonoperators:==,===,!=,!==,<,>,>=,and<=Theternaryoperator:?

Thenyoulearnedhowtousearraystostoreandaccessdata,andfinallyyousawdifferentwaystocontroltheflowofyourprogramusingconditions(if...elseorswitch)andloops(while,do...while,for,andfor...in).

Thisisquiteabitofinformation;giveyourselfawell-deservedpatonthebackbeforedivingintothenextchapter.Morefuniscomingup!

Page 110: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 3. FunctionsMastering functions is an important skill when you learn any programming language, and evenmoresowhenitcomestoJavaScript.ThisisbecauseJavaScripthasmanyusesforfunctions,andmuchofthelanguage'sflexibilityandexpressivenesscomesfromthem.Wheremostprogramminglanguageshaveaspecialsyntaxforsomeobject-orientedfeatures,JavaScriptjustusesfunctions.Thischapterwillcoverthefollowingtopics:

HowtodefineanduseafunctionPassingargumentstoafunctionPredefinedfunctionsthatareavailabletoyouforfreeThescopeofvariablesinJavaScriptTheconceptthatfunctionsarejustdata,albeitaspecialtypeofdata

Understandingthesetopicswillprovideasolidbasethatwillallowyoutodiveintothesecondpartofthechapter,whichshowssomeinterestingapplicationsoffunctions,asfollows:

UsinganonymousfunctionsCallbacksImmediate(self-invoking)functionsInner functions (functions defined inside other functions)FunctionsthatreturnfunctionsFunctionsthatredefinethemselvesClosures

Page 111: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

What is a function?Functions allow you to group together a code, give it a name, and reuse it later, addressing it bythenameyougaveit.Let'sconsiderthefollowingcodeasanexample:

functionsum(a,b){varc=a+b;returnc;}

Thepartsthatmakeupafunctionareshownasfollows:

Thefunctionkeyword.Thenameofthefunction;inthiscase,sum.Thefunctionparameters;inthiscase,aandb.Afunctioncantakeanynumberofparameters,ornoparameters,separatedbycommas.Acodeblock,alsocalledthebodyofthefunction.Thereturnstatement.Afunctionalwaysreturnsavalue.Ifitdoesn'treturnavalueexplicitly,itimplicitlyreturnsthevalueundefined.

Notethatafunctioncanonlyreturnasinglevalue.Ifyouneedtoreturnmorevalues,youcansimplyreturnanarraythatcontainsallofthevaluesyouneedaselementsofthisarray.

Theprecedingsyntaxiscalledafunctiondeclaration.It'sjustoneofthewaystocreateafunctioninJavaScript,andmorewaysarecomingup.

Page 112: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Callingafunction

Inordertomakeuseofafunction,youwillneedtocallit.Youcancallafunctionsimplyusingitsname,optionally,followedbyanynumberofvaluesinparentheses.Toinvokeafunctionisanotherwayofsayingtocall.

Let'scallthesum()function,passingtwoargumentsandassigningthevaluethatthefunctionreturnstothevariableresult:

>varresult=sum(1,2);>result;3

Page 113: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Parameters

Whendefiningafunction,youcanspecifywhatparametersthefunctionexpectstoreceivewhenit'scalled.Afunctionmaynotrequireanyparameters,butifitdoes,andyouforgettopassthem,JavaScriptwillassigntheundefinedvaluetotheonesyouskipped.Inthenextexample,thefunctioncallreturnsNaNbecauseittriestosum1andundefined:

>sum(1);NaN

Technicallyspeaking,thereisadifferencebetweenparametersandarguments,althoughthetwoareoftenusedinterchangeably.Parametersaredefinedtogetherwiththefunction,whileargumentsarepassedtothefunctionwhenit'scalled.Considerthefollowingexample:

>functionsum(a,b){returna+b;}>sum(1,2);

Here,aandbareparameters,while1and2arearguments.

JavaScriptisnotpickyatallwhenitcomestoacceptingarguments.Ifyoupassmorethanthefunctionexpects,theextraoneswillbesilentlyignored,asshowninthefollowingexample:

> sum(1, 2, 3, 4, 5);3

What'smore,youcancreatefunctionsthatareflexibleaboutthenumberofparameterstheyaccept.Thisispossiblethankstothespecialvalueargumentsthatarecreatedautomaticallyinsideeachfunction.Here'safunctionthatsimplyreturnswhateverargumentsarepassedtoit:

>functionargs(){returnarguments;}>args();[]>args(1,2,3,4,true,'ninja');[1,2,3,4,true,"ninja"]

Usingarguments,youcanimprovethesum()functiontoacceptanynumberofargumentsandaddthemallup,asshowninthefollowingexample:

functionsumOnSteroids(){vari,res=0,number_of_params=arguments.length;for(i=0;i<number_of_params;i++){res+=arguments[i];}

Page 114: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

returnres;}

Ifyoutestthisfunctionbycallingitwithadifferentnumberofarguments,orevennoneatall,youcanverifythatitworksasexpected,asyoucanseeinthefollowingexample:

>sumOnSteroids(1,1,1);3>sumOnSteroids(1,2,3,4);10>sumOnSteroids(1,2,3,4,4,3,2,1);20>sumOnSteroids(5);5

> sumOnSteroids();0

Thearguments.lengthexpressionreturnsthenumberofargumentspassedwhenthefunctionwascalled.Don'tworryifthesyntaxisunfamiliar,we'llexamineitindetailinthenextchapter.You'llalsoseethatargumentsisnotanarray(althoughitsurelookslikeone),butanarray-likeobject.

ES6introducesseveralimportantimprovementsaroundfunctionparameters.ES6functionparameterscannowhavedefaultvalues,restparameters,andallowsdestructuring.Thenextsectiondiscusseseachoftheseconceptsindetail.

Page 115: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Default parametersFunction parameters can be assigned default values. While calling the function, if a parameter isomitted,thedefaultvalueassignedtotheparameterisused:

functionrender(fog_level=0,spark_level=100){console.log(`FogLevel:${fog_level}andspark_level:${spark_level}`)}render(10);//FogLevel:10andspark_level:100

Inthisexample,weareomittingthespark_levelparameter,andhencethedefaultvalueassignedtotheparameterisused.Itisimportanttonotethatundefinedisconsideredasanabsenceofparametervalue;considerthefollowinglineofcode,forexample:

render(undefined,10);//FogLevel:0andspark_level:10

Whileprovidingdefaultvaluesofparameters,itispossibletorefertootherparametersaswell:

functiont(fog_level=1,spark_level=fog_level){console.log(`FogLevel:${fog_level}andspark_level:${spark_level}`)//FogLevel:10andspark_level:10}functions(fog_level=10,spark_level=fog_level*10){console.log(`FogLevel:${fog_level}andspark_level:

${spark_level}`)//FogLevel:10andspark_level:100}t(10);s(10);

Defaultparametershavetheirownscope;thisscopeissandwichedbetweentheouterfunctionscopeandtheinnerscopeofthefunction.Iftheparameterisshadowedbyavariableininnerscope,surprisingly,theinnervariableisnotavailable.Thefollowingexamplewillhelpexplainthis:

varscope="outer_scope";functionscoper(val=scope){varscope="inner_scope";console.log(val);//outer_scope}scoper();

Youmayexpectvaltogetshadowedbytheinnerdefinitionofthescopevariable,butasthedefaultparametershavetheirownscope,thevalueassignedtovalisunaffectedbytheinnerscope.

Page 116: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Rest parametersES6 introduces rest parameters. Rest parameters allow us to send an arbitrary number ofparameterstoafunctionintheformofanarray.Restparametercanonlybethelastoneinthelistofparameters,andtherecanonlybeonerestparameter.Puttingarestoperator(...)beforethelastformalparameterindicatesthatparameterisarestparameter.Thefollowingexampleshowsaddingarestoperatorbeforethelastformalparameter:

functionsayThings(tone,...quotes){console.log(Array.isArray(quotes)); //true

console.log(`In${tone}voice,Isay${quotes}`)}sayThings("MorganFreeman","Somethingserious","ImplodingUniverse","Amen");//InMorganFreemanvoice,IsaySomethingserious,ImplodingUniverse,Amen

Thefirstparameterpassedtothefunctionisreceivedintone,whiletherestoftheparametersarereceivedasanarray.Variablearguments(var-args)havebeenpartofseveralotherlanguagesandawelcomeeditiontoES6.Restparameterscanreplacetheslightlycontroversialargumentsvariable.Themajordifferencebetweenrestparametersandtheargumentsvariableisthattherestparametersarerealarrays.Allarraymethodsareavailabletorestparameters.

Page 117: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Spread operatorsA spread operator looks exactly like a rest operator but performs the exact opposite function.Spreadoperatorsareusedwhileprovidingargumentswhilecallingafunctionordefininganarray.Thespreadoperatortakesanarrayandsplitsitselementintoindividualvariables.Thefollowingexampleillustrateshowthespreadoperatorprovidesamuchclearersyntaxwhilecallingfunctionsthattakeanarrayasanargument:

functionsumAll(a,b,c){returna+b+c}varnumbers=[6,7,8]//ES5wayofpassingarrayasanargumentofafunction

console.log(sumAll.apply(null,numbers)); //21//ES6Spreadoperatorconsole.log(sumAll(...numbers))//21

InES5,itiscommontousetheapply()function whenpassinganarrayasanargumenttoafunction.Intheprecedingexample,wehaveanarrayweneedtopasstoafunctionwherethefunctionacceptsthreevariables.TheES5methodofpassinganarraytothisfunctionusestheapply()function,wherethesecondargumentallowsanarraytobepassedtothefunctionbeingcalled.ES6spreadoperatorsgiveamuchcleanerandprecisewaytodealwiththissituation.WhilecallingsumAll(),weusethespreadoperator(...)andpassthenumbersarraytothefunctioncall.Thearrayisthensplitintoindividualvariables-a,b,andc.

Spread operators improve the capabilities of arrays in JavaScript. If you want to create an arraythatismadeupofanotherarray,theexistingarraysyntaxdoesnotsupportthis.Youhavetousepush,splice,andconcattoachievethis.However,usingspreadoperators,thisbecomestrivial:

varmidweek=['Wed','Thu'];varweekend=['Sat','Sun'];varweek=['Mon','Tue',...midweek,'Fri',...weekend];//["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]console.log(week);

Intheprecedingexample,weareconstructingaweekarrayusingtwoarrays,midweekandweekend,usingthespreadoperator.

Page 118: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Predefinedfunctions

ThereareanumberoffunctionsthatarebuiltintotheJavaScriptengineandareavailableforyoutouse.Let'stakealookatthem.Whiledoingso,you'llhaveachancetoexperimentwithfunctions,theirargumentsandreturnvalues,andbecomecomfortableworkingwithfunctions.Thefollowingisalistofthebuilt-infunctions:

parseInt()parseFloat()isNaN()isFinite()encodeURI()decodeURI()encodeURIComponent()decodeURIComponent()eval()

Note

Theblackboxfunction

Often,whenyouinvokefunctions,yourprogramdoesn'tneedtoknowhowthesefunctionsworkinternally.Youcanthinkofafunctionasablackbox,giveitsomevalues(asinputarguments),andthentaketheoutputresultitreturns.Thisistrueforanyfunction-onethat'sbuiltintotheJavaScriptengine,onethatyoucreate,oronethataco-workerorsomeoneelsecreated.

parseInt()

TheparseInt()functiontakesanytypeofinput(mostoftenastring)and triestomakeanintegeroutofit.Ifitfails,itreturnsNaN,asshowninthefollowingcode:

>parseInt('123');123>parseInt('abc123');NaN>parseInt('1abc23');1>parseInt('123abc');123

The function accepts an optional second parameter, which is the radix, telling the function whattypeofnumbertoexpect-decimal,hexadecimal,binary,andsoon.Forexample,tryingtoextractadecimalnumberoutoftheFFstringmakesnosense,sotheresultisNaN,butifyoutryFFasahexadecimal,thenyouget255,asshowninthefollowingpieceofcode:

>parseInt('FF',10);NaN

Page 119: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>parseInt('FF',16);255

Anotherexamplewouldbeparsingastringwithabase10(decimal)andbase8(octal):

> parseInt('0377', 10);377>parseInt('0377',8);255

IfyouomitthesecondargumentwhencallingparseInt(),thefunctionwillassume10(adecimal),withthefollowingexceptions:

Ifyoupassastringbeginningwith0x,thentheradixisassumedtobe16(ahexadecimalnumberisassumed).Ifthestringyoupassstartswith0,thefunctionassumesradix8(anoctalnumberisassumed).Considerthefollowingexamples:

>parseInt('377');377>console.log(0o377);255>parseInt('0x377');887

Thesafestthingtodoistoalwaysspecifytheradix.Ifyouomittheradix,yourcodewillprobablystillworkin99percentofcases(becausemostoftenyouparsedecimals);however,everyonceinawhile,itmightcauseyouabitofhairlosswhiledebuggingsomeedgecases.Forexample,imagineyouhaveaformfieldthatacceptscalendardaysormonthsandtheusertypes06or08.

Note

ECMAScript5removestheoctalliteralvaluesandavoidstheconfusionwithparseInt()andunspecifiedradix.

parseFloat()

TheparseFloat()functionissimilartotheparseInt()function,butitalsolooksfordecimalswhentryingtofigureoutanumberfromyourinput.Thisfunctiontakesonlyoneparameter,whichisasfollows:

>parseFloat('123');123>parseFloat('1.23');1.23>parseFloat('1.23abc.00');1.23>parseFloat('a.bc1.23');

Page 120: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

NaN

AswithparseInt(),parseFloat()givesupatthefirstoccurrenceofanunexpectedcharacter,eventhoughtherestofthestringmighthaveusablenumbersinit:

>parseFloat('a123.34');NaN>parseFloat('12a3.34');12

TheparseFloat()functionunderstandsexponentsintheinput(unlikeparseInt()):

>parseFloat('123e-2');1.23>parseFloat('1e10');10000000000>parseInt('1e10');1

isNaN()

UsingisNaN(),youcancheckifaninputvalueisavalidnumberthatcan safelybeusedinarithmeticoperations.ThisfunctionisalsoaconvenientwaytocheckwhetherparseInt(),parseFloat(),oranyarithmeticoperationsucceeded:

>isNaN(NaN);true>isNaN(123);false>isNaN(1.23);false>isNaN(parseInt('abc123'));true

Thefunctionwillalsotrytoconverttheinputtoanumber:

>isNaN('1.23');false>isNaN('a1.23');true

TheisNaN()functionisusefulbecausethespecialvalueNaNisnotequaltoanything,includingitself.Inotherwords,NaN===NaNisfalse.So,NaNcannotbeusedtocheckifavalueisavalidnumber.

isFinite()

TheisFinite()functioncheckswhethertheinputisanumberthatisneitherInfinitynorNaN:

>isFinite(Infinity);false

Page 121: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>isFinite(-Infinity);false>isFinite(12);true>isFinite(1e308);true>isFinite(1e309);false

Ifyouarewonderingabouttheresultsreturnedbythelasttwocalls,rememberfromthepreviouschapterthatthebiggestnumberinJavaScriptis1.7976931348623157e+308,so1e309iseffectivelyinfinity.

Encode/decodeURIs

InaUniformResourceLocator(URL)oraUniformResourceIdentifier(URI),somecharactershavespecialmeanings.Ifyouwanttoescapethosecharacters,youcanusetheencodeURI()orencodeURIComponent()functions.ThefirstonewillreturnausableURL,whilethesecondoneassumesyou'reonlypassingapartoftheURL,suchasaquerystringforexample,andwillencodeallapplicablecharacters,asfollows:

>varurl='http://www.packtpub.com/script.php?q=thisandthat';>encodeURI(url);"http://www.packtpub.com/script.php?q=this%20and%20that">encodeURIComponent(url);"http%3A%2F%2Fwww.packtpub.com%2Fscript.php%3Fq%3Dthis%20and%20that"

TheoppositesofencodeURI()andencodeURIComponent()aredecodeURI()anddecodeURIComponent(),respectively.

Sometimes,inlegacycode,youmightseethefunctionsescape()andunescape()usedtoencodeanddecodeURLs,butthesefunctionshavebeendeprecated;theyencodedifferentlyandshouldnotbeused.

eval()

Theeval()functiontakesastringinputandexecutesitasaJavaScriptcode,asfollows:

>eval('varii=2;');>ii;2

So,eval('varii=2;')isthesameasvarii=2;

Theeval()functioncanbeusefulsometimes,butitshouldbeavoidedifthereareotheroptions.Mostofthetime,therearealternatives,andinmostcases,thealternativesaremoreelegantandeasiertowriteandmaintain.EvalisevilisamantrayoucanoftenhearfromseasonedJavaScriptprogrammers.Thedrawbacksofusingeval()areasfollows:

Page 122: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Security:JavaScriptispowerful,whichalsomeansitcancausedamage.Ifyoudon'ttrustthesourceoftheinputyoupasstoeval(),justdon'tuseit.Performance:It'sslowertoevaluatelivecodethantohavethecodedirectlyinthescript.

Abonus-thealert()function

Let'stakealookatanothercommonfunction-alert().It'snotpartofthecoreJavaScript(it'snowheretobefoundintheECMAspecification),butit'sprovidedbythehostenvironment-thebrowser.Itshowsastringoftextinamessagebox.Itcanalsobeusedasaprimitivedebuggingtool,althoughthedebuggersinmodernbrowsersaremuchbettersuitedforthispurpose.

Here'sascreenshotshowingtheresultofexecutingthealert("HiThere")code:

Beforeusingthisfunction,bearinmindthatitblocksthebrowserthread,meaningthatnoothercodewillbeexecuteduntiltheuserclosesthealert.IfyouhaveabusyAjax-typeapplication,it'sgenerallynotagoodideatousealert().

Page 123: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Scope of variablesIt's important to note, especially if you have come to JavaScript from another language, thatvariablesinJavaScriptarenotdefinedinablockscope,butinafunctionscope.Thismeansthatifavariableisdefinedinsideafunction,it'snotvisibleoutsideofthefunction.However,ifit'sdefinedinsideaniforaforcodeblock,it'svisibleoutsidetheblock.Thetermglobalvariablesdescribesvariablesyoudefineoutsideofanyfunction(intheglobalprogramcode),asopposedtolocalvariables,whicharedefinedinsideafunction.Thecodeinsideafunctionhasaccesstoallglobalvariablesaswellastoitsownlocalones.

Inthenextexample:

Thef()functionhasaccesstotheglobalvariableOutsidethef()function,thelocalvariable doesn'texist

varglobal=1;functionf(){varlocal=2;global++;returnglobal;}

Let'stestthis:

>f();2>f();3>local;ReferenceError:localisnotdefined

It'salsoimportanttonotethatifyoudon'tusevartodeclareavariable,thisvariableisautomaticallyassigneda globalscope.Let'sseeanexample:

Page 124: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Whathappened?Thef()functioncontainsthelocalvariable.Beforecallingthefunction,thevariabledoesn'texist.Whenyoucallthefunctionforthefirsttime,thelocalvariableiscreatedwithaglobalscope.Then,ifyouaccessthelocalvariableoutsidethefunction,itwillbeavailable.

Note

Bestpracticetips

Minimizethenumberofglobalvariablesinordertoavoidnamingcollisions.Imaginetwopeopleworkingontwodifferentfunctionsinthesamescript,andtheybothdecidetousethesamenamefortheirglobalvariable.Thiscouldeasilyleadtounexpectedresultsandhard-to-findbugs.Alwaysdeclareyourvariableswiththevarstatement.Considerasinglevarpattern.Defineallvariablesneededinyourfunctionattheverytopofthefunctionsoyouhaveasingleplacetolookforvariablesand,hopefully,preventaccidentalglobals.

Page 125: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Variablehoisting

Here'saninterestingexamplethatshowsanimportantaspectoflocalversusglobalscoping:

var a = 123;

functionf(){alert(a);vara=1;alert(a);}

f();

Youmightexpectthatthefirstalert()functionwilldisplay123(thevalueoftheglobalvariablea)andthesecondwilldisplay1(thelocalvariablea).But,thisisnotthecase.Thefirstalertwillshowundefined.Thisisbecause,insidethefunction,thelocalscopeismoreimportantthantheglobalscope.So,alocalvariableoverwrites anyglobalvariablewiththesamename.Atthetimeofthefirstalert(),theavariablewasnotyetdefined(hencetheundefinedvalue),butitstillexistedinthelocalspaceduetothespecialbehaviorcalledhoisting.

WhenyourJavaScriptprogramexecutionentersanewfunction,allthevariablesdeclaredanywhereinthefunctionaremoved,elevated,orhoistedtothetopofthefunction.Thisisanimportantconcepttokeepinmind.Further,onlythedeclarationishoisted,meaningonlythepresenceofthevariableismovedtothetop.Anyassignmentsstaywheretheyare.Intheprecedingexample,thedeclarationofthelocalvariableawashoistedtothetop.Onlythedeclarationwashoisted, butnottheassignmentto1.It'sasifthefunctionwaswritteninthefollowingway:

vara=123;

functionf(){vara;//sameas:vara=undefined;alert(a);//undefineda=1;alert(a);//1}

Youcanalsoadoptthesinglevarpatternmentionedpreviouslyinthebestpracticesection.Inthiscase,you'llbedoingasortofmanualvariablehoistingtopreventconfusionwiththeJavaScripthoistingbehavior.

Page 126: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Block scopeES6 provides additional scope while declaring variables. We looked at function scope and how itaffectsvariablesdeclaredwiththevarkeyword.IfyouarecodinginES6,blockscopewillmostlyreplaceyourneedtousevariablesdeclaredusingvar.Although,ifyouarestillwithES5,wewantyoutomakesurethatyoulookathoistingbehaviorcarefully.

ES6introducestheletandconstkeywordsthat allowustodeclarevariables.

Variablesdeclaredwithletareblock-scoped.Theyexistonlywithinthe currentblock.Variablesdeclaredwithvararefunctionscoped,aswesawearlier.Thefollowingexampleillustratestheblockscope:

vara=1;{leta=2;console.log(a);//2}console.log(a);//1

Thescopebetweenanopeningbrace'{'andaclosingbrace'}'isablock.IfyouarecomingfromabackgroundinJavaorC/C++,theconceptofablockscopewillbeveryfamiliartoyou.Inthoselanguages,programmersintroducedblocksjusttodefineascope.InJavaScript,however,therewasaneedtoidiomaticallyintroduceblocksastheydidn'thaveascopeassociatedtoit.However,ES6allowsyoutocreateblock-scopedvariablesusingtheletkeyword.Asyoucanseeintheprecedingexample,variableacreatedinsidetheblockisavailablewithintheblock.Whiledeclaringblock-scopedvariables,itisgenerallyrecommendedtoaddtheletdeclarationatthetopoftheblock.Let'slookatanotherexampletoclearlydistinguishfunctionandblockscope:

functionswap(a,b){//<--functionscopestartshereif(a>0&&b>0){//<--blockscopestartsherelettmp=a;a=b;b=tmp;}//<--blockscopeendshereconsole.log(a,b);

console.log(tmp); // tmp is not defined as it is availableonlyintheblockscopereturn[a,b];}swap(1,2);

Asyoucansee,tmpisdeclaredwithletandisavailableonlyintheblockinwhichitwasdefined.Forallpracticalpurposes,youshouldmaximizeyouruseofblock-scopedvariables.Unlessthereissomethingveryspecificyouaretryingtodothatmakesitnecessaryforyoutouse

Page 127: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

vardeclarations,makesureyoupreferblockscopedvariables.However,incorrectlyusingtheletkeywordcancauseacoupleofproblems.First,youcannotredeclarethesamevariablewithinthesamefunctionorblockscopeusingtheletkeyword:

functionblocker(x){if(x){letf;letf;//duplicatedeclaration"f"}}

InES6,variablesdeclaredbytheletkeywordarehoistedtoblockscope.However,referencingthevariablebeforeitsdeclarationisanerror.

AnotherkeywordintroducedinES6isconst.Avariabledeclaredwiththeconstkeywordcreatesaread-onlyreferencetoavalue.Thisdoesnotmeanthatthevalueheldbythereferenceisimmutable. However, the variable identifier cannot be reassigned. Constants are block-scopedjustlikevariablescreatedusingtheletkeyword.Also,youhavetoassignavaluetothevariablewhiledeclaringthem.

Althoughitsoundslikeitdoes,consthasnothingtodowithimmutablevalues.Constantscreateimmutablebinding.Thisisanimportantdistinctionandneedstobeunderstoodcorrectly.Let'sconsiderthefollowingexample:

constcar={}car.tyres=4

Thisisavalidcode;hereweareassigningvalue {}toaconstantcar.Onceassigned,thisreferencecannotbechanged.InES6,youshoulddothefollowing:

Useconstwherepossible.Usethemforallvariableswhosevaluesdon'tchange:

Uselet

Avoidvar.

Page 128: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Functions are dataFunctions in JavaScript are actually data. This is an important concept that we'll need later on.Thismeansthatyoucancreateafunctionandassignittoavariable,asfollows:

varf=function(){return1;};

Thiswayofdefiningafunctionissometimesreferredtoasfunctionliteralnotation.

Thefunction(){return1;}partisafunctionexpression.Afunctionexpressioncanoptionallyhaveaname,inwhichcaseitbecomesanamedfunctionexpression(NFE).So,thisisalsoallowed,althoughrarelyseeninpractice(andcausesIEtomistakenlycreatetwovariablesintheenclosingscope-fandmyFunc):

varf=functionmyFunc(){return1;};

Asyoucansee,there'snodifferencebetweenanamedfunctionexpressionandafunctiondeclaration. But they are, in fact, different. The only way to distinguish between the two is to lookatthecontextinwhichtheyareused.Functiondeclarationsmayonlyappearinprogramcode(inabodyofanotherfunctionorinthemainprogram).You'llseemanymoreexamplesoffunctionslateroninthebookthatwillclarifytheseconcepts.

Whenyouusethetypeofoperatoronavariablethatholdsafunctionvalue,itreturnsthestring"function"asshowninthefollowingexample:

>functiondefine(){return1;}

>varexpress=function(){return1;};

>typeofdefine;"function"

>typeofexpress;"function"

So,JavaScriptfunctionsaredata,butaspecialkindofdatawiththefollowingtwoimportantfeatures:

TheycontaincodeTheyareexecutable(theycanbeinvoked)

Page 129: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Asyouhaveseenbefore,thewaytoexecuteafunctionisbyaddingparenthesesafteritsname.Asthenextexampledemonstrates,thisworksregardlessofhowthefunctionwasdefined.Intheexample,youcanalsoseehowafunctionistreatedasaregularvalue;itcanbecopiedtoadifferentvariable,asfollows:

>varsum=function(a,b){returna+b;};

>varadd=sum;>typeofadd;function>add(1,2);3

Asfunctionsaredataassignedtovariables,thesamerulesfornamingfunctionsapplyasfornamingvariables-afunctionnamecannotstartwithanumberanditcancontainanycombinationofletters,numbers,theunderscorecharacter,and thedollarsign.

Page 130: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Anonymousfunctions

Asyounowknow,thereexistsafunctionexpressionsyntaxwhereyoucanhaveafunctiondefinedlikethefollowing:

varf=function(a){returna;};

Thisisalsooftencalledananonymousfunction(asitdoesn'thaveaname),especiallywhensuchafunctionexpressionisusedevenwithoutassigningittoavariable.Inthiscase,therecanbetwoelegantusesforsuchanonymousfunctions,whichareasfollows:

Youcanpassananonymousfunctionasaparametertoanotherfunction.Thereceivingfunctioncandosomethingusefulwiththefunctionthatyoupass.Youcandefineananonymousfunctionandexecuteitrightaway.

Let'sseethesetwoapplicationsofanonymousfunctionsinmoredetail.

Page 131: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Callbackfunctions

Asafunctionisjustlikeanyotherdataassignedtoavariable,itcanbedefined,copied,andalsopassedasanargumenttootherfunctions.

Here'sanexampleofafunctionthatacceptstwofunctionsasparameters,executesthem,andreturnsthesumofwhateachofthemreturns:

functioninvokeAdd(a,b){returna()+b();}

Now, let's define two simple additional functions using a function declaration pattern that onlyreturnshardcodedvalues:

functionone(){return1;}functiontwo(){return2;}

Nowyoucanpassthosefunctionstotheoriginalfunction,invokeAdd(),andgetthefollowingresult:

>invokeAdd(one,two);3

Anotherexampleofpassingafunctionasaparameteristouseanonymousfunctions(functionexpressions).Insteadofdefiningone()andtwo(),youcansimplydothefollowing:

>invokeAdd(function(){return1;},function(){return2;});3

Or,youcanmakeitmorereadable,asshowninthefollowingcode:

>invokeAdd(function(){return1;},function(){return2;});3

Or,youcandothefollowing:

>invokeAdd(function(){return1;},function(){

Page 132: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

return2;});3

Whenyoupassafunction,A,toanotherfunction,B,andthenBexecutesA,it'softensaidthatAisacallbackfunction.IfAdoesn'thaveaname,thenyoucansaythatit'sananonymouscallbackfunction.

Whenarecallbackfunctionsuseful?Let'sseesomeexamplesthatdemonstratethebenefitsofcallbackfunctions,namely:

Theyletyoupassfunctionswithouttheneedtonamethem,whichmeanstherearefewervariablesfloatingaroundYoucandelegatetheresponsibilityofcallingafunctiontoanotherfunction,whichmeansthere is less code to writeTheycanhelpwithperformancebydeferringtheexecutionorbyunblockingcalls

Callbackexamples

Take a look at this common scenario-you have a function that returns a value, which you then passtoanotherfunction.Inourexample,thefirstfunction,multiplyByTwo(),acceptsthreeparameters,loopsthroughthem,multipliesthembytwo,andreturnsanarraycontainingtheresult.Thesecondfunction,addOne(),takesavalue,addsonetoit,andreturnsit,asfollows:

functionmultiplyByTwo(a,b,c){vari,ar=[];for(i=0;i<3;i++){ar[i]=arguments[i]*2;}returnar;}

functionaddOne(a){returna+1;}

Let'stestthesefunctions:

>multiplyByTwo(1,2,3);[2,4,6]>addOne(100);101

Now,let'ssayyouwanttohaveanarray,myarr,thatcontainsthreeelements,andeachoftheelementsistobepassedthroughbothfunctions.First,let'sstartwithacalltomultiplyByTwo():

>varmyarr=[];>myarr=multiplyByTwo(10,20,30);[20,40,60]

Page 133: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Now,loopthrougheachelement,passingittoaddOne():

>for(vari=0;i<3;i++){myarr[i]=addOne(myarr[i]);}>myarr;[21,41,61]

Asyoucansee,everythingworksfine,butthere'sroomforimprovement.Forexample,thereweretwoloops.Loopscanbeexpensiveiftheygothroughalotofrepetitions.Youcanachievethesameresultwithonlyoneloop.Here'showtomodifymultiplyByTwo()sothatitacceptsacallbackfunctionandinvokesthatcallbackoneveryiteration:

functionmultiplyByTwo(a,b,c,callback){vari,ar=[];for(i=0;i<3;i++){ar[i]=callback(arguments[i]*2);}returnar;}

Usingthemodifiedfunction,alltheworkisdonewithjustonefunctioncall,whichpassesthestartvaluesandthecallbackfunction,asfollows:

>myarr=multiplyByTwo(1,2,3,addOne);[3,5,7]

InsteadofdefiningaddOne(),youcanuseananonymousfunction,thereforesavinganextraglobalvariable:

>multiplyByTwo(1,2,3,function(a){returna+1;});[3,5,7]

Anonymousfunctionsareeasytochangeshouldtheneedarise:

>multiplyByTwo(1,2,3,function(a){returna+2;});[4,6,8]

Page 134: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Immediatefunctions

Sofar,wehavediscussedusinganonymousfunctionsascallbacks.Let'sseeanotherapplicationofananonymousfunction-callingafunctionimmediatelyafterit'sdefined.Here'sanexample:

(function(){alert('boo');}

)();

Thesyntaxmaylookalittlescaryatfirst,butallyoudoissimplyplaceafunctionexpressioninsideparenthesesfollowedbyanothersetofparentheses.Thesecondsetsaysexecutenowandisalsotheplacetoputanyargumentsthatyouranonymousfunctionmightaccept,forexample:

(function(name){alert('Hello'+name+'!');})('dude');

Alternatively,youcanmovetheclosingofthefirstsetofparenthesestotheend.Bothofthesework:

(function(){// ...

}());

//vs.

(function(){//...})();

Onegoodapplicationofimmediate(self-invoking)anonymousfunctionsiswhenyouwanttohavesomeworkdonewithoutcreatingextraglobalvariables.Adrawback,ofcourse,isthatyoucannotexecutethesamefunctiontwice.Thismakesimmediatefunctionsbestsuitedforone-offorinitialization tasks.

Animmediatefunctioncanalsooptionallyreturnavalueifyouneedone.It'snotuncommontoseecodethatlookslikethefollowing:

varresult=(function(){//somethingcomplexwith//temporarylocalvariables...//...//returnsomething;}());

Page 135: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inthiscase,youdon'tneedtowrapthefunctionexpressioninparentheses;youonlyneedtheparenthesesthatinvokethefunction.So,thefollowingpieceofcodealsoworks:

varresult=function(){//somethingcomplexwith//temporarylocalvariables//returnsomething;}();

Thissyntaxworks,butmaylookslightlyconfusing;withoutreadingtheendofthefunction,youdon'tknowifresultisafunctionorthereturnvalueoftheimmediatefunction.

Page 136: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inner(private)functions

Bearinginmindthatafunctionisjustlikeanyothervalue,there'snothingthatstopsyoufromdefiningafunctioninsideanotherfunction,here's theexample:

functionouter(param){functioninner(theinput){returntheinput*2;}

return 'The result is ' + inner(param);}

Usingafunctionexpression,thiscanalsobewrittenasfollows:

varouter=function(param){varinner=function(theinput){returntheinput*2;};return'Theresultis'+inner(param);};

Whenyoucalltheglobalouter()function,itwillinternallycallthelocalinner()function.Asinner()islocal,it'snotaccessibleoutsideouter(),soyoucansayit'saprivatefunction:

>outer(2);"Theresultis4">outer(8);"Theresultis16">inner(2);ReferenceError:innerisnotdefined

Thebenefitsofusingprivatefunctionsareasfollows:

Youcankeeptheglobalnamespaceclean,whichislesslikelytocausenamingcollisionsPrivacy-youcanexposeonlythosefunctionstotheoutsideworldthatyoudecide,andkeepthefunctionalitythatisnotmeanttobeconsumedbytherestoftheapplicationtoyourself

Page 137: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Functionsthatreturnfunctions

Asmentionedearlier,afunctionalwaysreturnsa value,andifitdoesn'tdoitexplicitlywithreturn,thenitdoessoimplicitlybyreturningundefined.Afunctioncanreturnonlyonevalue,andthisvaluecanjustaseasilybeanotherfunction,forexample:

functiona(){alert('A!');returnfunction(){alert('B!');

};}

Inthisexample,thea()functiondoesitsjob(saysA!)andreturnsanotherfunctionthatdoessomethingelse(saysB!).Youcanassignthereturnvaluetoavariableandthenusethisvariableasanormalfunction,asfollows:

>varnewFunc=a();>newFunc();

Here,thefirstlinewillalertA!andthesecondwillalertB!.

Ifyouwanttoexecutethereturnedfunctionimmediatelywithoutassigningittoanewvariable,youcansimplyuseanothersetofparentheses.Theendresultwillbethesame:

>a()();

Page 138: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Function,rewritethyself!

Asafunctioncanreturnafunction,youcanusethenewfunctiontoreplacetheoldone.Continuingwiththepreviousexample,youcantakethevaluereturnedbythecalltoa()tooverwritetheactuala() function:

> a = a();

TheprecedinglineofcodealertsA!,butthenexttimeyoucalla()italertsB!.Thisisusefulwhenafunctionhassomeinitialone-offworktodo.Thefunctionoverwritesitselfafterthefirstcallinordertoavoiddoingunnecessaryrepetitiveworkeverytimeit'scalled.

Intheprecedingexample,thefunctionwasredefinedfromtheoutsideandthereturnedvaluewasassignedbacktothefunction.But,thefunctioncanactuallyrewriteitselffromtheinside,asshowninthefollowingexample:

functiona(){alert('A!');a=function(){alert('B!');};}

Ifyoucallthisfunctionforthefirsttime,itwilldothefollowing:

AlertA!(considerthisasbeingtheone-offpreparatorywork)Redefinetheglobalvariableaandassigninganewfunctiontoit

Everysubsequenttimethatthefunctioniscalled,itwillalertB!.

Here'sanotherexamplethatcombinesseveralofthetechniquesdiscussedinthelastfewsectionsofthischapter:

vara=(function(){

functionsomeSetup(){varsetup='done';}

functionactualWork(){alert('Worky-worky');

}

someSetup();returnactualWork;

}());

Page 139: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Fromthisexample,youcannotethefollowingthings:

Youhaveprivatefunctions;someSetup()andactualWork().Youhaveanimmediatefunction:ananonymousfunctionthatcallsitselfusingtheparenthesesfollowingitsdefinition.Thefunctionexecutesforthefirsttime,callssomeSetup(),andthenreturnsareferencetotheactualWorkvariable,whichisafunction.Noticethattherearenoparenthesesinthereturnstatementbecauseyou'rereturningafunctionreference,nottheresultofinvokingthisfunction.Asthewholethingstartswithvara=,thevaluereturnedbytheself-invokedfunctionisassignedtoa.

Ifyouwanttotestyourunderstandingofthetopicsjustdiscussed,answerthefollowingquestions.Whatwilltheprecedingcodealertbeinthefollowingcases:

Itisinitiallyloaded?Youcalla()afterwards?

Thesetechniquescouldbereallyusefulwhenworkinginthebrowserenvironment.Differentbrowserscanhavedifferentwaysofachievingthesameresult.Ifyouknowthatthebrowserfeatureswon'tchangebetweenfunctioncalls,youcanhaveafunctiondeterminethebestwaytodotheworkinthecurrentbrowser,thenredefineitselfsothatthebrowsercapabilitydetectionisdoneonlyonce.You'llseeconcreteexamplesofthisscenariolaterinthisbook.

Page 140: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ClosuresThe rest of the chapter is about closures (what better way to close a chapter?). Closures can be alittlehardtograspinitially,sodon'tfeeldiscouragedifyoudon'tgetitduringthefirstread.Youshouldgothroughtherestofthechapterandexperimentwiththeexamplesonyourown,butifyoufeelyoudon'tfullyunderstandtheconcept,youcancomebacktoitlaterwhenthetopicsdiscussedpreviouslyinthischapterhavehadachancetosinkin.

Beforemovingontoclosures,let'sfirstreviewandexpandontheconceptofscopeinJavaScript.

Page 141: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Scopechain

Asyouknow,inJavaScript,thereisnocurlybracesscope,butthereisafunctionscope.Avariabledefinedinafunctionisnotvisibleoutsidethefunction,butavariabledefinedinacodeblock(forexampleaniforaforloop)isvisibleoutsidetheblock,forexample:

>vara=1;>functionf(){varb=1;returna;

}>f();1>b;ReferenceError:bisnotdefined

Theavariableisintheglobalspace,whilebisinthescopeofthefunctionf().So,wehavethefollowing:

Insidef(),bothaandbarevisibleOutsidef(),aisvisible,butbisnot

If you define an inner()function nested inside outer(), it will have access to variables in itsown scope, plus the scope of its parents. This is known as a scope chain, and the chain can be aslong(deep)asyouneedittobe:

varglobal=1;functionouter(){varouter_local=2;functioninner(){varinner_local=3;returninner_local+outer_local+global;}returninner();}

Let'stestiftheinner()functionhasaccesstoallvariables:

>outer();6

Page 142: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Breakingthechainwithaclosure

Let'sintroduceclosureswithanillustrationandlookatthefollowingcodeandseewhat'shappeningthere:

vara="globalvariable";varF=function(){varb="localvariable";varN=function(){

var c = "inner local";};};

First,thereistheglobalscopeG.Thinkofitastheuniverse,asifitcontainseverything:

Page 143: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Itcancontainglobalvariablessuchasa1anda2andglobalfunctionssuchasF:

Functionshavetheirownprivatespaceandcanuseittostoreothervariables,suchasb,andinnerfunctions,suchasN(forinner).Atsomepoint,youwillendupwithapicturelikethefollowing:

Page 144: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Ifyou'reatpointa,you'reinsidetheglobalspace.Ifyou'reatpointb,whichisinsidethespaceoftheFfunction,thenyouhaveaccesstotheglobalspaceandtotheFspace.Ifyou'reatpointc,whichisinsidetheNfunction,thenyoucanaccesstheglobalspace,theFspace,andtheNspace.Youcannotreachfromatob,becausebisinvisibleoutsideF.But,youcangetfromctobifyouwantorfromNtob.TheinterestingpartisthattheclosureeffecthappenswhensomehowNbreaksoutofFandendsupintheglobalspace.

Page 145: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Whathappensthen?Nisinthesameglobalspaceasa.And,asfunctionsremembertheenvironmentinwhichtheyweredefined,NwillstillhaveaccesstotheFspace,andhence,canaccessb.Thisisinteresting,becauseNiswhereaisandyetNdoeshaveaccesstob,butadoesn't.

Additionally,howdoesNbreakthechain?Bymakingitselfglobal(omittingvar)orbyhavingFdeliver(orreturn)ittotheglobalspace.Let'sseehowthisisdoneinpractice.

Closure #1

Takealookatthefollowingfunction,whichisthesameasbefore,onlyFreturnsNandalsoNreturnsb,towhichithasaccessviathescopechain:

vara="globalvariable";varF=function(){varb="localvariable";varN=function(){varc="innerlocal";

return b;};returnN;};

TheFfunctioncontainsthebvariable,whichislocal,andthereforeinaccessiblefromtheglobalspace:

>b;ReferenceError:bisnotdefined

The N function has access to its private space, to the F() function's space, and to the global space.So, it can see b. As F() is callable from the global space (it's a global function), you can call itand assign the returned value to another global variable. The result - a new global function thathasaccesstotheF()function'sprivatespace:

>varinner=F();>inner();"localvariable"

Closure#2

Thefinalresultofthenextexamplewillbethesameasthepreviousexample,butthewaytoachieveitisalittledifferent.F()doesn'treturnafunction,butinsteaditcreatesanewglobalfunction,inner(),insideitsbody.

Let'sstartbydeclaringa placeholderfortheglobalfunction-to-be.Thisisoptional,butit'salwaysgoodtodeclareyourvariables.Then,youcandefinetheF()functionasfollows:

Page 146: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varinner;//placeholdervarF=function(){varb="localvariable";varN=function(){returnb;};inner=N;};

Now,let'sseewhathappensifyouinvokeF():

>F();

Anewfunction,N(),isdefinedinsideF()andassignedtotheglobalinnerfunction.Duringdefinitiontime,N()wasinsideF(),soithadaccesstotheF()function'sscope.Theinner()functionwillkeepitsaccesstotheF()function'sscope,eventhoughit'spartoftheglobalspace,forexample:

>inner();"localvariable".

Adefinitionandclosure#3

Everyfunctioncanbeconsideredaclosure.Thisisbecauseeveryfunctionmaintainsasecretlinktotheenvironment(thescope)inwhichitwascreated.But,mostofthetime,thisscopeisdestroyedunlesssomethinginterestinghappens(asshownintheprecedingcode)thatcausesittobemaintained.

Basedonwhatyou'veseensofar,youcansaythataclosureiscreatedwhenafunctionkeepsalinktoitsparentscopeevenaftertheparenthasreturned.And,everyfunctionisaclosurebecause,attheveryleast,everyfunctionmaintainsaccesstotheglobalscope,whichisneverdestroyed.

Let'sseeonemoreexampleofaclosure,thistimeusingthefunctionparameters.Functionparameters behave like local variables to this function, but they are implicitly created; you don'tneedtousevarforthem.Youcancreateafunctionthatreturnsanotherfunction,whichinturnreturnsitsparent'sparameter,asfollows:

functionF(param){varN=function(){returnparam;};param++;returnN;}

Youcanusethefunctionasfollows:

>varinner=F(123);

Page 147: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>inner();124

Noticehowparam++wasincrementedafterthefunctionwasdefinedandyet,whencalled,inner()returnedtheupdatedvalue.Thisdemonstratesthatthefunctionmaintainsareferencetothescopewhereitwasdefined,andnottothevariablesandtheirvaluesfoundinthescopeduringthefunctionexecution.

Page 148: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Closuresinaloop

Let'stakealookatacanonicalrookiemistakewhenitcomestoclosures.Itcaneasilyleadtohard-to-spotbugs,becauseonthesurface,everythinglooksnormal.

Let'sloopthreetimes,eachtimecreatinganewfunctionthatreturnstheloopsequencenumber.Thenewfunctionswillbeaddedtoanarrayandthearrayisreturnedattheend.Here'sthefunction:

functionF(){vararr=[],i;for(i=0;i<3;i++){arr[i]=function(){returni;};}returnarr;}

Let'srunthefunction,assigningtheresulttothearrarray:

>vararr=F();

Nowyouhaveanarrayofthreefunctions.Let'sinvokethembyaddingparenthesesaftereacharrayelement.Theexpectedbehavioristoseetheloopsequenceprintedoutas0,1,and2.Let'stry:

>arr[0]();3>arr[1]();3>arr[2]();3

Hmm,notquiteasexpected.Whathappenedhere?Allthreefunctionspointtothesamelocalvariable:i.Why?Thefunctionsdon'tremembervalues,theyonlykeepalink(reference)totheenvironmentwheretheywerecreated.Inthiscase,theivariablehappenstoliveintheenvironmentwherethethreefunctionsweredefined.So,allfunctions,whentheyneedtoaccessthevalue,reachbacktotheenvironmentandfindthemostcurrentvalueofi.Aftertheloop,theivariable'svalueis3.So,allthreefunctionspointtothesamevalue.

Whythreeandnottwoisanothergoodquestiontothinkaboutforbetterunderstandingtheforloop.

So,howdoyouimplementthecorrectbehavior?Theansweristouseanotherclosure,asshowninthefollowingpieceofcode:

Page 149: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

functionF(){vararr=[],i;for(i=0;i<3;i++){arr[i]=(function(x){returnfunction(){returnx;};}(i));}returnarr;}

Thisgivesyoutheexpectedresultasfollows:

>vararr=F();>arr[0]();0>arr[1]();1>arr[2]();2

Here,insteadofjustcreatingafunctionthatreturnsi,youpasstheivariable'scurrentvaluetoanotherimmediatefunction.Inthisfunction,ibecomesthelocalvaluex,andxhasadifferentvalueeverytime.

Alternatively,youcanuseanormal(asopposedtoanimmediate)innerfunctiontoachievethesameresult.Thekeyistousethemiddlefunctiontolocalizethevalueofiateveryiteration,asfollows:

functionF(){

functionbinder(x){returnfunction(){returnx;};}

vararr=[],i;for(i=0;i<3;i++){arr[i]=binder(i);}returnarr;}

Page 150: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Getterandsetter

Let'sseetwomoreexamplesofusingclosures.Thefirstoneinvolvesthecreationofthegetterandsetterfunctions.Imaginethatyouhaveavariablethatshouldcontainaspecifictypeofvalueoraspecificrangeofvalues.Youdon'twanttoexposethisvariablebecauseyoudon'twantjustanypartofthecodetobeabletoalteritsvalue.Youcanprotectthisvariableinsideafunctionandprovidetwoadditionalfunctions-onetogetthevalueandonetosetit.Theonethatsetsitcouldcontainsomelogictovalidateavaluebeforeassigningittotheprotectedvariable.Let'smakethevalidationpartsimple(forthesakeofkeepingtheexampleshort)andonlyacceptnumbervalues.

Youcanplaceboththegetterandthesetterfunctionsinsidethesamefunctionthatcontainsthesecretvariablesothattheysharethesamescope:

vargetValue,setValue;

(function () {

varsecret=0;

getValue=function(){returnsecret;};

setValue=function(v){if(typeofv==="number"){secret=v;}};

}());

Inthiscase,thefunctionthatcontainseverythingisanimmediatefunction.ItdefinessetValue()andgetValue()asglobalfunctions,whilethesecretvariableremainslocalandinaccessibledirectly,asshowninthefollowingexample:

>getValue();0>setValue(123);>getValue();123>setValue(false);>getValue();123

Page 151: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iterator

Thelastclosureexample(alsothelastexampleinthischapter)showstheuseofaclosuretoaccomplishaniteratorfunctionality.

Youalreadyknowhowtoloopthroughasimplearray,buttheremightbecaseswhereyouhaveamorecomplicateddatastructurewithdifferentrulesastowhatthesequenceofvalueshas.Youcanwrapthecomplicatedwho'snextlogicintoaneasy-to-usenext()function.Then,youcansimplycallnext()everytimeyouneedtheconsecutivevalue.

Forthisexample,let'sjustuseasimplearrayandnotacomplexdatastructure.Here'saninitializationfunctionthattakesaninputarrayandalsodefinesasecretpointer,i,thatwillalwayspointtothenextelementinthearray:

functionsetup(x){vari=0;returnfunction(){returnx[i++];};}

Calling the setup() function with a data array will create the next() function for you, asfollows:

>varnext=setup(['a','b','c']);

Fromthereit'seasyandfun;callingthesamefunctionoverandoveragaingivesyouthenextelement,whichisasfollows:

>next();"a"

> next();"b">next();"c"

Page 152: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

IIFE versus blocksAs ES5 did not provide block scope, a popular pattern to achieve block scope was to useimmediatelyinvokedfunctionexpressions(IIFE),forexample:

(function(){varblock_scoped=0;}());console.log(block_scoped);//referenceerror

WithES6'ssupportforblockscopes,youcansimplyusealetorconstdeclaration.

Page 153: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Arrow functionsJavaScript uses almost all variations of arrows. With ES6, it introduces a new syntax for writingfunctions.WehavealwayswrittenfunctionexpressionsinJavaScript.ItisidiomatictowritecodelikethisinJavaScript(thisexampleisinjQuery):

$("#submit-btn").click(function(event){validateForm();submitMessage();});

ThisisatypicaljQueryeventhandler.Theeventhandlerclick()functionacceptsafunctionasaparameterandwewillsimplycreateaninlineanonymousfunctionexpressionandpassittotheclickfunction.ThisstyleofwritinganonymousfunctionexpressionsisknownasLambdafunctions.Severalotherlanguagessupportthisfeature.Thoughlambdasaremoreorlessstandardinnewlanguages,JavaScriptwasresponsibleforpopularizingtheirusage.However,thelambdasyntaxinJavaScripthasnotbeenveryconcise.ES6arrowfunctionsfillthatgapandprovideaconcisesyntaxtowritefunctions.

Arrowfunctionprovideamoreconcisesyntaxthanthetraditionalfunctionexpressions;forexample,considerthefollowingpieceofcode:

constnum=[1,2,3]const squares = num.map(function(n){

returnn*n;});console.log(squares);//[1,4,9]

Arrowfunctionssyntaxcansimplifythefunctiontothefollowinglineofcode:

constsquares_6=num.map(n=>n*n)

Asyoucansee,thereisnofunctionorreturnkeywordanywhere.Ifyourfunctionhasonlyoneargument,youwillendupwritingthefunctionasidentifer=>expression.

Whenyouneedmultiplearguments,youneedtowraptheargumentlistinbraces:

Noparameters:()=>{...}Oneparameter:a=>{...}Morethanoneparameters:(a,b)=>{...}

Arrowfunctionscanhaveboththestatementblockbodiesaswellasexpressionbodies:

n=>{returnn+n}//statementblockn=>n+n//expression

Bothareequivalentbutthesecondvariationisconciseandpreferred.Arrowfunctionsare

Page 154: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

alwaysanonymous.Oneimportantaspectofarrowfunctionsthatwewilldiscussalittlelateristhatarrowfunctionsdonotbindtheirownvaluesofthethiskeyword-thevalueislexicallyderivedfromthesurroundingscope.Aswehavenotyetlookedatthethiskeywordindetail,wewilldeferthediscussiontoalaterpartofthisbook.

Page 155: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Writeafunctionthatconvertsahexadecimalcolor,forexampleblue(#0000FF),intoitsRGBrepresentation,rgb(0,0,255).NameyourfunctiongetRGB()andtestitwiththefollowingcode(hint:treatthestringasanarrayofcharacters):

>vara=getRGB("#00FF00");>a;"rgb(0,255,0)"

2. Whatdoeachofthesefollowinglinesprintintheconsole?

>parseInt(1e1);> parseInt('1e1');

>parseFloat('1e1');>isFinite(0/10);>isFinite(20/0);>isNaN(parseInt(NaN));

3. Whatdoesthisfollowingcodealert?

vara=1;functionf(){functionn(){alert(a);}vara=2;n();}f();

4. Allthesefollowing examplesalert"Boo!".Canyouexplainwhy?Example1:

varf=alert;eval('f("Boo!")');

Example2:

vare;varf=alert;eval('e=f')('Boo!');

Example3:

(function(){returnalert;})()('Boo!');

Page 156: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryYou have now completed the introduction to the fundamental concepts related to functions inJavaScript.Thishaslaidthegroundworkthatwillallowyoutoquicklygrasptheconceptsofobject-orientedJavaScriptandthepatternsusedinmodernJavaScriptprogramming.Sofar,we'vebeenavoidingtheOOfeatures,butasyouhavereachedthispointinthebook,it'sonlygoingtogetmoreinterestingfromhereonin.Let'stakeamomenttoreviewthetopicsdiscussedinthischapter:

Thebasicsofhowtodefineandinvoke(call)afunctionusingeitherafunctiondeclarationsyntaxorafunction expressionFunctionparametersandtheirflexibilityBuilt-infunctions-parseInt(),parseFloat(),isNaN(),isFinite(),andeval()-andthefourfunctionstoencode/decodeaURLThe scope of variables in JavaScript-no curly braces scope, variables have only functionscopeandthescopechainFunctionsasdata-afunctionislikeanyotherpieceofdatathatyouassigntoavariableandalotofinterestingapplicationsfollowfromthis,suchas:

PrivatefunctionsandprivatevariablesAnonymousfunctionsCallbacksImmediatefunctionsFunctionsoverwritingthemselves

ClosuresArrowfunctions

Page 157: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 4. ObjectsNow that you've mastered JavaScript's primitive data types, arrays, and functions, it's time to staytruetothepromiseofthebooktitleandtalkaboutobjects.

JavaScripthasaneccentrictakeontheclassicalObject-orientedprogramming.Object-orientedprogrammingisoneofthemostpopularprogrammingparadigmsandhasbeenamainstayinmostofprogramminglanguageslikeJavaandC++.TherearewelldefinedideasproposedbyclassicalOOPthatmostoftheselanguagesadopt.JavaScript,however,hasadifferenttakeonit.WewilllookJavaScript'swayofsupportingOOP.

Inthischapter,youwilllearnthefollowingtopics:

HowtocreateanduseobjectsWhataretheconstructorfunctionsWhattypesofbuilt-inJavaScriptobjectsexistandwhattheycandoforyou

Page 158: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

From arrays to objectsAs you already know fromChapter 2, Primitive Data Types, Arrays, Loops, and Conditions, anarrayisjustalistofvalues.Eachvaluehasanindex(anumerickey)thatstartsfromzeroandincrementsbyoneforeachvalue.Considerthefollowingexample:

>varmyarr=['red','blue','yellow','purple'];>myarr;["red","blue","yellow","purple"].>myarr[0];"red">myarr[3];"purple"

Ifyouputtheindexesinonecolumnandthevaluesinanother,you'llendupwithatableofkey/valuepairsshownasfollows:

Key Value

0 red

1 blue

2 yellow

3 purple

Anobjectissimilartoanarray,butthedifferenceisthatyoudefinethekeysyourself.You'renotlimitedtousingonlynumericindexes,andyoucanusefriendlierkeyssuchasfirst_name,age,andsoon.

Let'stakealookatasimpleobjectandexamineitsparts:

varhero={breed:'Turtle',occupation:'Ninja'};

Youcanseethat:

ThenameofthevariablethatreferstotheobjectisheroInsteadof[and],whichyouusetodefineanarray,youuse{and}forobjectsYouseparatetheelements(calledproperties)containedintheobjectwithcommasThekey/valuepairsaredividedbycolons,asinkey:value

Page 159: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thekeys(namesoftheproperties)canoptionallybeplacedinquotationmarks.Forexample,thesekeysareallthesame:

varhero={occupation:1};varhero={"occupation":1};varhero={'occupation':1};

It'srecommendedthatyoudon'tquotethenamesoftheproperties(it'slesstyping),buttherearecaseswhenyoumustusequotes.Someofthecasesarestatedhere:

IfthepropertynameisoneofthereservedwordsinJavaScript(seeAppendixA,ReservedWords)Ifitcontainsspacesorspecialcharacters(anythingotherthanletters,numbers,andthe_and$characters)Ifitstartswithanumber

Inotherwords,ifthenameyouhavechosenforapropertyisnotavalidnameforavariableinJavaScript,thenyouneedtowrapitinquotes.

Havealookatthisbizarre-lookingobject:

var o = {$omething:1,'yesorno':'yes','!@#$%^&*':true};

Thisisavalidobject.Thequotesarerequiredforthesecondandthethirdproperties;otherwise,you'llgetanerror.

Laterinthischapter,you'llseeotherwaystodefineobjectsandarrays,inadditionto[]and{}.However,first,let'sintroducethisbitofterminology-defininganarraywith[]iscalledarrayliteralnotation,anddefininganobjectusingcurlybraces{}iscalledobjectliteralnotation.

Page 160: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Elements,properties,methods,andmembers

Whentalkingaboutarrays,yousaythattheycontainelements.Whentalkingaboutobjects,yousaythattheycontainproperties.Thereisn'tanysignificantdifferenceinJavaScript;it'sjusttheterminologythatpeopleareusedto,probablyfromotherprogramminglanguages.

Apropertyofanobjectcanpointtoafunction,becausefunctionsarejustdata.Propertiesthatpointtofunctionsarealsocalledmethods.Inthefollowingexample,talkisamethod:

vardog={name:'Benji',talk:function(){alert('Woof,woof!');}};

Asyouhaveseeninthepreviouschapter,it'salsopossibletostorefunctionsasarrayelementsandinvokethem,butyou'llnotseemuchcodelikethisinpractice:

>vara=[];>a[0]=function(what){alert(what);};>a[0]('Boo!');

Youcanalsoseepeopleusingthewordmemberstorefertothepropertiesofanobject,mostoftenwhenitdoesn'tmatterifthepropertyisafunctionornot.

Page 161: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Hashesandassociativearrays

Insomeprogramminglanguages,thereisadistinctionbetween:

A regular array, also called an indexed or enumerated array (the keys are numbers)Anassociativearray,alsocalledahashoradictionary(thekeysarestrings)

JavaScriptusesarraystorepresentindexedarraysandobjectstorepresentassociativearrays.IfyouwantahashinJavaScript,youuseanobject.

Page 162: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Accessinganobject'sproperties

Therearetwowaystoaccessthepropertyofanobject:

Using the square bracket notation, for example, hero['occupation']Using the dot notation, for example, hero.occupation

Thedotnotationiseasiertoreadandwrite,butitcannotalwaysbeused.Thesamerulesapplyforquotingpropertynames.Ifthenameofthepropertyisnotavalidvariablename,youcannotusethedotnotation.

Let'staketheheroobjectagain:

varhero={breed:'Turtle',occupation:'Ninja'};

Followingisanexampleforaccessingapropertywiththedotnotation:

>hero.breed;"Turtle"

Let'sseeanexampleforaccessingapropertywiththebracketnotation:

>hero['occupation'];"Ninja"

Considerthefollowingexampleforaccessinganon-existingpropertyreturnsundefined:

>'Haircoloris'+hero.hair_color;"Haircolorisundefined"

Objectscancontainanydata,includingotherobjects:

varbook={name:'Catch-22',published:1961,author:{firstname:'Joseph',lastname:'Heller'}};

Togettothefirstnamepropertyoftheobjectcontainedintheauthorpropertyofthebookobject,youcanusethefollowinglinesofcode:

>book.author.firstname;"Joseph"

Page 163: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Letseeanexampleusingthesquarebracketsnotation:

>book['author']['lastname'];"Heller"

Itworksevenifyoumixboth:

>book.author['lastname'];"Heller">book['author'].lastname;"Heller"

Anothercasewhereyouneedsquarebracketsiswhenthenameofthepropertyyouneedtoaccessisnotknownbeforehand.Duringruntime,it'sdynamicallystoredinavariable:

>varkey='firstname';>book.author[key];"Joseph"

Page 164: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Callinganobject'smethods

Youknowamethodisjustapropertythathappenstobeafunction,soyouaccessmethodsinthesamewayinwhichyouwouldaccessproperties-usingthedotnotationorusingsquarebrackets.Calling(invoking)amethodisthesameascallinganyotherfunction-youjustaddparenthesesafterthemethodname,whicheffectivelysaysExecute!:

>varhero={breed:'Turtle',occupation:'Ninja',say:function(){return'Iam'+hero.occupation;}};>hero.say();"IamNinja"

Ifthereareanyparametersthatyouwanttopasstoamethod,youwouldproceedasyouwouldwithnormalfunctions:

>hero.say('a','b','c');

Asyoucanusethearray-likesquarebracketstoaccessaproperty,itmeansyoucanalsousebracketstoaccessandinvokemethods:

>hero['say']();

This is not a common practice, unless the method name is not known at the time of writing code,butitisinsteaddefinedatruntime:

varmethod='say';hero[method]();

Note

Noquotesunlessyouhavetousethedotnotation toaccessmethodsandproperties,anddon'tquotepropertiesinyourobjectliterals.

Page 165: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Alteringproperties/methods

JavaScriptallowsyoutoalterthepropertiesandmethodsofexistingobjectsatanytime.Thisincludesaddingnewpropertiesordeletingthem.Youcanstartwithablankobjectandaddpropertieslater.Let'sseehowyoucangoaboutdoingthis.

Anobjectwithoutpropertiesisshownasfollows:

>varhero={};

Note

A"blank"object

Inthissection,youstartedwitha"blank"object,varhero={}.Blankisinquotesbecausethisobjectisnotreallyemptyanduseless.Althoughatthisstageithasnopropertiesofitsown,ithasalreadyinheritedsome.

You'lllearnmoreaboutownversusinheritedpropertieslater.So,anobjectinES3isneverreallyblankorempty.InES5though,thereisawaytocreateacompletelyblankobjectthatdoesn'tinheritanything,butlet'snotgetaheadtoomuch.

1. Followingisthecodetoaccessannon-existingproperty:

>typeofhero.breed;"undefined"

2. Addingtwopropertiesandamethod:

>hero.breed='turtle';>hero.name='Leonardo';>hero.sayName=function(){returnhero.name;};

3. Callingthemethod:

>hero.sayName();"Leonardo"

4. Deletingaproperty:

>deletehero.name;true

5. Ifyoucallthemethodagain,itwillnolongerfindthedeletednameproperty:

>hero.sayName();"undefined"

Note

Page 166: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Malleableobjects

Youcanalwayschangeanyobjectatanytime,suchasaddingandremovingpropertiesandchanging their values. However, there are exceptions to this rule. A few properties of some built-inobjectsarenotchangeable(forexample,Math.PI,asyou'llseelater).Also,ES5allowsyoutopreventchangestoobjects.You'lllearnmoreaboutitinAppendixC,Built-inObjects.

Page 167: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingthethisvalue

Inthepreviousexample, thesayName()methodusedhero.nametoaccessthenamepropertyoftheheroobject.Whenyou'reinsideamethodthough,thereisanotherwaytoaccesstheobjectthemethodbelongsto.Thismethodisusingthespecialvaluethis:

>varhero={name:'Rafaelo',sayName:function(){returnthis.name;}};>hero.sayName();"Rafaelo"

So,whenyousaythis,you'reactuallysaying-thisobjectorthecurrentobject.

Page 168: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Constructorfunctions

Thereisanotherwaytocreateobjects-usingconstructorfunctions.Let'slookatanexample:

function Hero() {this.occupation='Ninja';}

Inordertocreateanobjectusingthisfunction,youcanusethenewoperatorasfollows:

>varhero=newHero();>hero.occupation;"Ninja"

Abenefitofusingconstructorfunctionsisthattheyacceptparameters,whichcanbeusedwhencreating new objects. Let's modify the constructor to accept one parameter and assign it to thenameproperty:

functionHero(name){this.name=name;this.occupation='Ninja';this.whoAreYou=function(){return"I'm"+this.name+"andI'ma"+this.occupation;};}

Now, you can create different objects using the same constructor:

>varh1=newHero('Michelangelo');>varh2=newHero('Donatello');>h1.whoAreYou();"I'mMichelangeloandI'maNinja">h2.whoAreYou();"I'mDonatelloandI'maNinja"

Note

Byconvention,youshouldcapitalizethefirstletterofyourconstructorfunctionssothatyouhaveavisualcluethattheyarenotintendedtobecalledasregularfunctions.

Ifyoucallafunctionthatisdesignedtobeaconstructorbutyouomitthenewoperator,itisnotanerror.However,itdoesn'tgiveyoutheexpectedresult:

>varh=Hero('Leonardo');>typeofh;"undefined"

Page 169: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Whathappenedhere?Thereisnonewoperator,soanewobjectwasnotcreated.Thefunctionwascalledlikeanyotherfunction,sothevariablehcontainsthevaluethatthefunctionreturns.Thefunctiondoesnotreturnanything(there'snoreturnfunction),soitactuallyreturnsundefined,whichgetsassignedtothevariableh.

Inthiscase,whatdoesthisreferto?Itreferstotheglobalobject.

Page 170: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theglobalobject

Youhavealreadylearnedabitaboutglobalvariables(andhowyoushouldavoidthem).YoualsoknowthatJavaScriptprogramsruninsideahostenvironment(thebrowser,forexample).Nowthatyouknowaboutobjects,it'stimeforthewholetruth,thehostenvironmentprovidesaglobalobject,andallglobalvariablesareaccessibleaspropertiesoftheglobalobject.

Ifyourhostenvironmentisthewebbrowser,theglobalobjectiscalledwindow.Anotherwaytoaccesstheglobalobject(andthisisalsotrueinmostotherenvironments)istousethiskeywordoutsideaconstructorfunction,forexampleintheglobalprogramcodeoutsideanyfunction.

As an illustration, you can declare a global variable outside any function as follows:

>vara=1;

Then,youcanaccessthisglobalvariableinvariousways:

AsavariableaAsapropertyoftheglobalobject,forexample,window['a']orwindow.aAsapropertyoftheglobalobjectreferredtoasthis:

>vara=1;>window.a;1>this.a;1

Let'sgobacktothecasewhereyoudefineaconstructorfunctionandcallitwithoutthenewoperator.Insuchcases,thisreferstotheglobalobjectandallthepropertiessettothisbecomepropertiesofwindow.

Declaringaconstructorfunctionandcallingitwithoutnewreturns"undefined":

>functionHero(name){this.name=name;}>varh=Hero('Leonardo');

> typeof h;"undefined">typeofh.name;TypeError:Cannotreadproperty'name'ofundefined

AsyouhadthiskeywordinsidethefunctionHero,aglobalvariable(apropertyoftheglobalobject)callednamewascreated:

>name;"Leonardo"

> window.name;

Page 171: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"Leonardo"

Ifyoucallthesameconstructorfunctionusingnew,thenanewobjectisreturned,andthisreferstoit:

>varh2=newHero('Michelangelo');>typeofh2;"object">h2.name;"Michelangelo"

Thebuilt-inglobalfunctionsyouhaveseeninChapter3,Functions,canalsobeinvokedasmethods of the window object. So, the following two calls have the same result:

>parseInt('101dalmatians');101>window.parseInt('101dalmatians')101

Page 172: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theconstructorproperty

Whenanobjectiscreated,aspecialpropertyisassignedtoitbehindthescenes-theconstructorproperty.Itcontainsareferencetotheconstructorfunctionusedtocreatethisobject.

Continuingfromthepreviousexample:

>h2.constructor;functionHero(name){this.name=name;

}

Astheconstructorpropertycontainsareferencetoafunction,youmightaswellcallthisfunctiontoproduceanewobject.Thefollowingcodeislikesaying,"Idon'tcarehowobjecth2wascreated,butIwantanotheronejustlikeit":

>varh3=newh2.constructor('Rafaello');>h3.name;"Rafaello"

Ifanobjectwascreatedusingtheobjectliteralnotation,itsconstructoris thebuilt-inObject()constructorfunction(thereismoreaboutthislaterinthischapter):

>varo={};>o.constructor;functionObject(){[nativecode]}>typeofo.constructor;"function"

Page 173: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theinstanceofoperator

Withtheinstanceofoperator,youcantestwhetheranobjectwascreatedwithaspecificconstructorfunction:

>functionHero(){}>varh=newHero();>varo={};>hinstanceofHero;true>hinstanceofObject;true>oinstanceofObject;true

Notethatyoudon'tputparenthesesafterthefunctionname(youdon'tusehinstanceofHero()).Thisisbecauseyou'renotinvokingthisfunction,butjustreferringtoitbyname,aswithanyothervariable.

Page 174: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Functionsthatreturnobjects

Inadditiontousingconstructorfunctionsandthenewoperatortocreateobjects,youcanalsouseanormalfunctiontocreateobjectswithoutthenewoperator.Youcanhaveafunctionthatdoesabitofpreparatoryworkandhasanobjectasareturnvalue.

Forexample,here'sasimplefactory()functionthatproducesobjects:

functionfactory(name){return{name:name};}

Considerthefollowingexampleusingthefactory()function:

>varo=factory('one');>o.name;"one">o.constructor;functionObject(){[nativecode]}

Infact,youcanalsouseconstructorfunctionsandreturnobjectsdifferentfromthiskeyword.Thismeansyoucanmodifythedefaultbehavioroftheconstructorfunction.Let'sseehow.

Here'sthenormalconstructorscenario:

> function C() {this.a=1;}>varc=newC();>c.a;1

However,now,lookatthisscenario:

>functionC2(){this.a=1;return{b:2};}

> var c2 = new C2();>typeofc2.a;"undefined">c2.b;2

Whathappenedhere?Insteadofreturningthethisobject,whichcontainsthepropertya,theconstructorreturnedanotherobjectthatcontainsthepropertyb.Thisispossibleonlyifthereturn

Page 175: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

valueisanobject.Otherwise,ifyoutrytoreturnanythingthatisnotanobject,theconstructorwillproceedwithitsusualbehaviorandreturnthis.

Ifyouthinkabouthowobjectsarecreatedinsideconstructorfunctions,youcanimaginethatavariable called this is defined at the top of the function and then returned at the end. Consider thefollowing code:

functionC(){//varthis={};//pseudocode,youcan'tdothisthis.a=1;//returnthis;}

Page 176: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Passingobjects

Whenyouassignanobjecttoadifferentvariable orpassittoafunction,youonlypassareferencetothatobject.Consequently,ifyoumakeachangetothereference,you'reactuallymodifyingtheoriginalobject.

Here'sanexampleofhowyoucanassignanobjecttoanothervariableandthenmakeachangetothecopy.Asaresult,the originalobjectisalsochanged:

>varoriginal={howmany:1};>varmycopy=original;>mycopy.howmany;1>mycopy.howmany=100;100>original.howmany;100

Thesamethingapplieswhenpassingobjectstofunctions:

>varoriginal={howmany:100};>varnullify=function(o){o.howmany=0;};>nullify(original);>original.howmany;0

Page 177: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Comparingobjects

Whenyoucompareobjects,you'llgettrueonlyifyoucomparetworeferencestothesameobject.Ifyoucomparetwodistinctobjectsthathappentohavetheexactsamemethodsandproperties,theresultwouldbefalse.

Let'screatetwoobjectsthatlookthesame:

>varfido={breed:'dog'};>varbenji={breed:'dog'};

Comparingthemreturnsfalse:

>benji===fido;false>benji==fido;

false

Youcancreateanewvariable,mydog,andassignoneoftheobjectstoit.Thisway,thevariablemydogactuallypointstothesameobject:

>varmydog=benji;

In this case, benji is mydog because they are the same object (changing the mydog variable'sproperties will change the benji variable's properties). The comparison returns true:

>mydog===benji;true

Asfidoisadifferentobject,itdoesnotcomparetomydog:

>mydog===fido;false

Page 178: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ObjectsintheWebKitconsole

Beforedivingintothebuilt-inobjectsinJavaScript,let'squicklysayafewwordsaboutworkingwithobjectsintheWebKitconsole.

Afterplayingaroundwiththeexamplesinthischapter,youmighthavealreadynoticedhowobjectsaredisplayedintheconsole.Ifyoucreateanobjectandtypeitsname,you'llgetanarrowpointingtothewordobject.

Theobjectisclickableandexpandstoshowyoualistofallofthepropertiesoftheobject.Ifaproperty is also an object, there is an arrow next to it too, so you can expand this as well. This ishandyasitgivesyouaninsightintoexactlywhatthisobjectcontains.Considerthefollowingexample:

Note

Youcanignore__proto__fornow;there'smore aboutitinthenextchapter.

Loggingusingtheconsole.logmethod

Theconsolealsooffersyouanobjectcalledconsoleandafewmethods,suchasconsole.log()andconsole.error(),whichyoucanusetodisplayanyvalueyouwantintheconsole.

Page 179: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theconsole.log()methodisconvenientwhenyouwanttoquicklytestsomething,aswellaswhenyouwanttodumpsomeintermediatedebugginginformationinyourrealscripts.Here'showyoucanexperimentwithloops,forexample:

> for (var i = 0; i < 5; i++) {console.log(i);}01234

Page 180: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6objectliterals

ES6introducesamuchsuccinctsyntaxwhileusingobjectliterals.ES6offersseveralshorthandsforpropertyinitializationandfunctiondefinitions.ES6shorthandscloselyresembleafamiliarJSONsyntax.Considerthefollowingcodefragment:

leta=1letb=2letval={a:a,b:b}console.log(val)//{"a":1,"b":2}

This is a typical way to assign property values. If the name of the variable and the property key isthesame,ES6allowsyoutouseshorthandsyntax.Theprecedingcodecanbewrittenasfollows:

leta=1letb=2letval={a,b}console.log(val)//{"a":1,"b":2}

Similarsyntaxisavailableformethoddefinitionsaswell.Aswehavediscussed,methodsaresimplypropertiesofanobjectwhosevaluesarefunctions.Considerthefollowingexample:

varobj={prop:1,modifier:function(){

console.log(this.prop);}}

ThereisacompactwaytodefinemethodsinES6.Yousimplydropthefunctionkeywordand:.TheequivalentcodeinES6wouldlooklikethefollowing:

varobj={prop:1,modifier(){console.log(this.prop);}}

ES6allowsyoutocomputethekeyofaproperty.UntilES6,youcouldonlyusefixedpropertynames.Hereisanexample:

varobj={prop:1,modifier:function(){console.log(this.prop);}}obj.prop=2;obj.modifier();//2

Page 181: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Asyoucansee,wearelimitedtousingfixedkey names:propandmodifierinthiscase.However,ES6allowsyoutousecomputedpropertykeys.Itispossibletocreatepropertykeysdynamicallyusingvaluesreturnedbyafunctionaswell:

letvehicle="car"functionvehicleType(){return"truck"}letcar={[vehicle+"_model"]:"Ford"}lettruck={[vehicleType()+"_model"]:"Mercedez"}console.log(car)//{"car_model":"Ford"}console.log(truck)//{"truck_model":"Mercedez"}

Weareusingthevalueofvariablevehicletoconcatenatewithafixedstringtoderivethepropertykeywhilecreatingthecarobject.Inthesecondsnippet,wearecreatingapropertybyconcatenatingafixedstringwiththevaluereturnedbyafunction.Thiswayofcomputingpropertykeysprovidesgreatflexibilitywhilecreatingobjects,andalotofboilerplateandrepetitivecodecanbeeliminated.

Thissyntaxisapplicabletomethoddefinitionaswell:

letobject_type="Vehicle"letobj={["get"+object_type](){return"Ford"}}

Page 182: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object properties and attributesEach object has a few properties. Each property, in turn, has a key and attributes. A property'sstateisstoredintheseattributes.Allpropertieshavethefollowingattributes:

Enumerable(boolean):Thisindicatesifyoucanenumeratethepropertiesoftheobject.Systempropertiesarenon-enumerablewhileuserpropertiesareenumerable.Unlessthereisastrongreason,thispropertyshouldremainuntouched.Configurable(boolean):Ifthisattributeisfalse,thepropertycannotbedeletedoredited(itcannotchangeanyofitsattribute).

YoucanusetheObject.getOwnPropertyDescriptor()methodtoretrieveanobject'sownproperties:

letobj={age:25}console.log(Object.getOwnPropertyDescriptor(obj,'age'));//{"value":25,"writable":true,"enumerable":true,"configurable":true}

Meanwhile,thepropertycanbedefinedusingtheObject.defineProperty()method:

letobj={age:25}Object.defineProperty(obj,'age',{configurable:false})console.log(Object.getOwnPropertyDescriptor(obj,'age'));//{"value":25,"writable":true,"enumerable":true,"configurable":false}

Thoughyouwouldneverusethesemethods,itisimportanttounderstandobjectpropertiesandattributes.Inthenextsection,wewilldiscusshowsomeoftheobjectmethodsareusedincontextofsomeoftheseproperties.

Page 183: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6 object methodsES6 introduces a few static helper methods for objects. Object.assign is a helper method thatreplaces popular mixins to perform a shallow copy of an object.

Page 184: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CopypropertiesusingObject.assign

Thismethodisusedtocopypropertiesofthetargetobjectintothesourceobject.Inotherwords,thismethodmergesthesourceobjectwiththetargetobjectandmodifiesthetargetobject:

leta={}Object.assign(a,{age:25})console.log(a)//{"age":25}

ThefirstparametertoObject.assignisthetargetonwhichsourcepropertiesarecopied.Thesametargetobjectisreturnedtothecaller.Existingpropertiesareoverwritten,whilepropertiesthataren'tpartofthesourceobjectareignored:

leta={age:23,gender:"male"}Object.assign(a,{age:25})//ageoverwritten,butgenderignoredconsole.log(a)//{"age":25,"gender":"male"}

Object.assigncantakemultiplesourceobjects.YoucanwriteObject.assign(target,source1,source2).Hereisanexample:

console.log(Object.assign({a:1,b:2},{a:2},{c:4},{b:3}))//Object{//"a":2,//"b":3,//"c":4//

Inthissnippet,weareassigningpropertiesfrommultiplesourceobjects.Also,noticehowObject.assign()returnsthetargetobject,whichweinturnuseinsideconsole.log().

Onepointtonoteisthatonlyenumerableown(non-inherited)propertiescanbecopiedusingObject.assign().Propertiesfromtheprototypechain(willbediscussedlaterinthischapterwhenwetalkaboutInheritance)arenotconsidered.Ourearlierdiscussionofenumerablepropertieswillhelpyouunderstandthisdistinction.

Inthefollowingexample,wewillcreateanon-enumerablepropertyusingdefineProperty()andvalidatethefactthatObject.assign()ignoresthatproperty:

leta={age:23,gender:"male"}Object.defineProperty(a,'superpowers',{enumberable:false,value:

'ES6'})console.log(

Thepropertydefinedassuperpowershastheenumerableattributesettofalse.Whilecopyingproperties,thispropertyisignored.

Page 185: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ComparevalueswithObject.is

ES6providesaslightlyprecisewayofcomparingvalues.Wehavediscussedthestrictequalityoperator===.However,forNaNand-0and+0,thestrictequalityoperatorbehavesinconsistently.Hereisanexample:

console.log(NaN===NaN)//falseconsole.log(-0===+0)//true//ES6Object.isconsole.log(Object.is(NaN,NaN))//true

console.log(Object.is(-0,+0)) //false

Apartfromthesetwocases,Object.is()cansafelybereplacedwiththe===operator.

Page 186: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

DestructuringYou will be working with objects and arrays all the time when you code. JavaScript object andarraynotationsresembletheJSONformat.Youwilldefineobjectsandarrays,andthenretrieveelementsfromthem.ES6givesaconvenientsyntaxthatsignificantlyimprovesthewayweaccessproperties/membersfromobjectsandarrays.Let'sconsideratypicalcodeyouwouldoftenwrite:

varconfig={server: 'localhost',

port:'8080'}varserver=config.server;varport=config.port;

Here,weextractedvaluesofserverandportfromtheconfigobjectandassignedthemtolocalvariables.Prettystraightforward!However,whenthisobjecthasabunchofproperties,someofthemnested,thissimpleoperationcangetverytedioustowrite.

ES6destructuringsyntaxallowsanobjectliteralontheleft-handsideofanassignmentstatement.Inthefollowingexample,wewilldefineanobjectconfigwithafewproperties.Later,wewillusedestructuringtoassigntheobjectconfigtoassignvaluestoindividualpropertiesontheleft-handsideoftheassignmentstatement:

letconfig={server:'localhost',port:'8080',timeout:900,}let{server,port}=configconsole.log(server,port)//"localhost""8080"

Asyoucanseeserverandportarelocalvariablesthatgotassignedpropertiesfromtheconfigobjectbecausethenameofthepropertieswerethesameasthatofthelocalvariables.Youcanalsopickparticularpropertieswhileyouassignthemtolocalvariables.Hereisanexample:

let{timeout:t}=configconsole.log(t)//900

Here,weareonlypickingtimeoutfromtheconfigobjectandassignittoalocalvariablet.

Youcanalsousethedestructuringsyntaxtoassignvaluestoalreadydeclaredvariables.Inthiscase,youhavetoputparenthesesaroundtheassignment:

letconfig={server: 'localhost',

port:'8080',timeout:900,

Page 187: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}letserver='127.0.0.1';letport='80';({server,port}=config)//assignmentsurroundedby()console.log(server,port)//"localhost""8080"

Asthedestructuringexpressionevaluatestotheright-handsideoftheexpression,it'spossibletouseitanywhereyouwouldexpectavalue.Forexample,inafunctioncall,asshownhere:

letconfig={server:'localhost',port:'8080',timeout:900,}

let server='127.0.0.1';letport='80';lettimeout='100';

functionstartServer(configValue){console.log(configValue)}startServer({server,port,timeout}=config)

Ifyouspecifyalocalvariablewithapropertynamethatdoesnotexistintheobject,thelocalvariablegetsanundefinedvalue.However,whileusingvariablesinthe destructuringassignment,youcanoptionallyspecifydefaultvalues:

letconfig={server:'localhost',port:'8080'}let{server,port,timeout=0}=configconsole.log(timeout)

Inthisexample,foranon-existentpropertytimeout,weprovidedadefaultvaluetopreventgetting undefined values assigned to local variables.

Destructuringworksonarraysaswell,andthesyntaxisalsoverysimilar tothatoftheobjects.Wejustneedtoreplaceobjectliteralsyntaxwitharray:literals:

constarr=['a','b']const[x,y]=arrconsole.log(x,y)/"a""b"

Asyoucansee,thisistheexactsamesyntaxwesawearlier.Wedefinedanarrayarrandlaterusedthedestructuringsyntaxtoassignelementsofthatarraytotwolocalvariables,xandy.Here,theassignmenthappensbasedontheorderofelementsinthearray.Asyouonlycareaboutthepositionofelements,youcanskipsomeofthemifyouwantto.Hereisanexample:

constdays=['Thursday','Friday','Saturday','Sunday']

Page 188: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

const[,,sat,sun]=daysconsole.log(sat,sun)//"Saturday""Sunday"

Here,weknowthatweneedelementsfrompositions2and3(anarray'sindexstartsfrom0),andhence,weignoreelementsatpositions0and1.Arraydestructuringcaneliminatetheuseofatempvariablewhileswappingvaluesoftwovariables.Considerthefollowing:

leta=1,b=2;[b,a]=[a,b]console.log(a,b)//21

Youcanusetherestoperator(...)toextractremainingelementsandassignthemtoanarray.Therestoperatorcanonlybeusedasthelastoperatorduringdestructuring:

const[x,...y]=['a','b','c'];//x='a';y=['b','c']

Page 189: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Built-in objectsEarlier in this chapter, you came across the Object() constructor function. It's returned when youcreate objects with the object literal notation and access their constructor property. Object()is one of the built-in constructors; there are a few others, and in the rest of this chapter you'll seeallofthem.

Thebuilt-inobjectscanbedividedintothreegroups:

Datawrapperobjects:TheseareObject,Array,Function,Boolean,Number,andString.TheseobjectscorrespondtothedifferentdatatypesinJavaScript.Thereisadatawrapperobjectforeverydifferentvaluereturnedbytypeof(discussedinChapter2,PrimitiveDataTypes,Arrays,Loops,andConditions),withtheexceptionofundefinedandnull.Utilityobjects:TheseareMath,Date,andRegExp,andcancomeinhandy.Errorobjects:TheseincludethegenericErrorobjectaswellasothermorespecificobjectsthatcanhelpyourprogramrecoveritsworkingstatewhensomethingunexpectedhappens.

Onlyahandfulofmethodsofthebuilt-inobjectswillbediscussedinthischapter.Forafullreference,seeAppendixC,Built-inObjects.

Ifyou'reconfusedaboutwhatabuilt-inobjectisandwhatabuilt-inconstructoris,well,theyarethesamething.Inamoment,you'llseehowfunctionsand,therefore,constructorfunctions,arealsoobjects.

Page 190: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object

ObjectistheparentofallJavaScriptobjects,whichmeansthateveryobjectyoucreateinheritsfromit.Tocreateanewemptyobject,youcanusetheliteralnotationortheObject()constructorfunction.Thefollowingtwolinesare equivalent:

>varo={};>varo=newObject();

Asmentionedbefore,anempty(orblank)objectisnotcompletelyuseless,becauseitalreadycontainsseveralinheritedmethodsandproperties.Inthisbook,emptymeansanobjectlike{}thathasnopropertiesofitsown,otherthantheonesitautomaticallygets.Let'slookatafewofthepropertiesthatevenblankobjectsalreadyhave:

Theo.constructorpropertyreturnsareferencetotheconstructorfunctionTheo.toString()isamethodthatreturnsastringrepresentationoftheobjectTheo.valueOf()returnsasingle-valuerepresentationoftheobject;often,thisistheobjectitself

Let'sseethesemethodsinaction.First,createanobject:

>varo=newObject();

CallingtoString()returnsastringrepresentationoftheobject:

>o.toString();"[objectObject]"

ThetoString()methodwillbecalledinternallybyJavaScriptwhenanobjectisusedinastringcontext.Forexample,alert()worksonlywithstrings,soifyoucallthealert()functionpassinganobject,thetoString()methodwillbecalledbehindthescenes.Thesetwolinesproducethesameresult:

>alert(o);>alert(o.toString());

Anothertypeofstringcontextisthestringconcatenation.Ifyoutrytoconcatenateanobjectwithastring,theobject'stoString()methodiscalledfirst:

>"Anobject:"+o;"Anobject:[objectObject]"

ThevalueOf()methodisanothermethodthatallobjectsprovide.Forthesimpleobjects(whoseconstructorisObject()),thevalueOf()methodreturnstheobjectitself:

>o.valueOf()===o;true

Page 191: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Tosummarize:

Youcancreateobjectseitherwithvaro={};(objectliteralnotation,thepreferredmethod)orwithvaro=newObject();Anyobject,nomatterhowcomplex,inheritsfromtheObjectobjectandtherefore,offersmethodssuchastoString()andpropertiessuchasaconstructor

Page 192: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array

Array()isabuilt-infunctionthatyoucanuseasaconstructortocreatearrays:

>vara=newArray();

Thisisequivalenttothearrayliteralnotation:

>vara=[];

No matter how the array is created, you can add elements to it as usual:

>a[0]=1;>a[1]=2;>a;[1,2]

WhenusingtheArray()constructor,youcanalsopassvaluesthatwillbeassignedtothenewarray'selements:

>vara=newArray(1,2,3,'four');>a;[1,2,3,"four"]

Anexceptiontothisiswhenyoupassasinglenumbertotheconstructor.Inthiscase,thenumberisconsideredtobethelengthofthearray:

>vara2=newArray(5);>a2;[undefinedx5]

Asarraysarecreatedwithaconstructor,doesthismeanthatarraysareinfactobjects?Yes,andyoucanverifythisusingthetypeofoperator:

>typeof[1,2,3];"object"

Asarraysareobjects,thismeansthattheyinherit thepropertiesandmethodsoftheparentobject:

>vara=[1,2,3,'four'];>a.toString();"1,2,3,four">a.valueOf();[1,2,3,"four"]>a.constructor;functionArray(){[nativecode]}

Arraysareobjects,butofaspecialtypebecause:

Thenamesoftheirpropertiesareautomaticallyassignedusingnumbersstartingfrom0.

Page 193: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theyhavealengthpropertythatcontainsthenumberofelementsinthearray.Theyhavemorebuilt-inmethodsinadditiontothoseinheritedfromtheparentobject.

Let'sexaminethedifferencesbetweenanarrayandanobject,startingbycreatingtheemptyarraya and the empty object o:

>vara=[],o={};

Arrayobjectshavealengthpropertyautomaticallydefinedforthem,whilenormalobjectsdonot:

>a.length;0>typeofo.length;"undefined"

It'soktoaddbothnumericandnon-numericpropertiestobotharraysandobjects:

> a[0] = 1;>o[0]=1;>a.prop=2;>o.prop=2;

Thelengthpropertyisalwaysuptodatewiththenumberofnumericproperties,whileitignoresthenon-numericones:

>a.length;1

The length property can also be set by you. Setting it to a greater value than the current numberof items in the array makes room for additional elements. If you try to access these non-existingelements,you'llgetthevalueundefined:

>a.length=5;5>a;[1,undefinedx4]

Settingthelengthpropertytoalowervalueremovesthetrailingelements:

>a.length=2;2>a;[1,undefinedx1]

Afewarraymethods

Inadditiontothemethodsinheritedfromtheparentobject,arrayobjectsalsohavespecializedmethodsforworkingwitharrays,suchassort(),join(),andslice(),amongothers(see

Page 194: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

AppendixC,Built-inObjects,forthecompletelist).

Let'stakeanarrayandexperimentwithsomeofthesemethods:

>vara=[3,5,1,7,'test'];

Thepush()methodappendsanewelementtotheendofthearray.Thepop()methodremovesthelastelement.Thea.push('new')methodworkslikea[a.length]='new',anda.pop()islikea.length-.

The push() method returns the length of the changed array, whereas pop() returns the removedelement:

>a.push('new');6>a;[3,5,1,7,"test","new"]>a.pop();"new">a;[3,5,1,7,"test"]

Thesort()methodsortsthearrayandreturnsit.Inthenextexample,aftersort,bothaandbpointtothesamearray:

>varb=a.sort();>b;[1,3,5,7,"test"]>a===b;true

Thejoin()methodreturnsastringcontainingthevaluesofalltheelementsinthearraygluedtogetherusingthestringparameterpassedtojoin():

>a.join('isnot');"1isnot3isnot5isnot7isnottest"

Theslice()methodreturnsapieceofthearraywithoutmodifyingthesourcearray.Thefirstparametertoslice()is thestartindex(zero-based),andthesecondistheendindex(bothindicesarezero-based).Startindexisincluded,whiletheendindexisnot.Takealookatthefollowingexample:

>b=a.slice(1,3);[3,5]>b=a.slice(0,1);[1]

> b = a.slice(0, 2);[1,3]

Page 195: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Afteralltheslicing,thesourcearrayisstillthesame:

>a;[1,3,5,7,"test"]

Thesplice()methodmodifiesthesourcearray. Itremovesaslice,returnsit,andoptionallyfillsthegapwithnewelements.Thefirsttwoparametersdefinethestartindexandlength(numberofelements)oftheslicetoberemoved;theotherparameterspassthenewvalues:

>b=a.splice(1,2,100,101,102);[3,5]>a;[1,100,101,102,7,"test"]

Fillingthegapwithnewelementsisoptional,soyoucanskipit:

>a.splice(1,3);[100,101,102]>a;[1,7,"test"]

Page 196: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6 array methodsArrays get a bunch of useful methods. Libraries such as lodash and underscore provided featuresmissinginthelanguagesofar.Withthenewhelpermethods,arraycreationandmanipulationismuchmorefunctionalandeasytocode.

Page 197: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array.from

Convertingarray-likevaluestoarrayshasalwaysbeenabitofachallengeinJavaScript.Peoplehaveemployedseveralhacksandwrittenlibrariestojustletyouhandlearrayseffectively.

ES6introducesaveryhelpfulmethodtoconvertarray-likeobjectsanditerablevaluesintoarrays.Array-likevaluesareobjectsthathavealengthpropertyandindexedelements.Everyfunctionhasanimplicitargumentsvariablethatcontainsalistofallargumentspassedtothefunction.Thisvariableisanarray-likeobject.BeforeES6,theonlywaywecouldconverttheargumentsobjecttoanarraywastoiteratethroughitandcopythevaluesovertoanewarray:

functiontoArray(args){varresult=[];for(vari=0,len=args.length;i<len;i++){result.push(args[i]);}returnresult;}functiondoSomething(){varargs=toArray(arguments);console.log(args)}doSomething("hellow","world")//Array[//"hellow",//"world"

//]

Here,wearecreatinganewarraytocopyoverallelementsoftheargumentsobject.Thisiswastefulandneedsalotofunnecessarycoding.Array.from()isaconcisewaytoconvertarray-likeobjectsintoarrays.WecanconvertthisexampletoamoresuccinctoneusingArray.from():

functiondoSomething(){console.log(Array.from(arguments))}doSomething("hellow","world")//Array[//"hellow",//"world"//]

YoucanprovideyourownmappingschemewhilecallingArray.from()byprovidingamappingfunction.Thisfunctionisinvokedonalltheelementsoftheobjectandconvertsit.Thisisausefulconstructformanycommonusecases,forexample:

functiondoSomething(){console.log(Array.from(arguments,function(elem){returnelem+"mapped";}));

Page 198: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}

Inthisexample,wearedeconstructingtheargumentsobjectusingArray.fromandforeachelementinargumentsobject,wearecallingafunction.

Page 199: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CreatingarraysusingArray.of

CreatinganarrayusingtheArray()constructorcausesabitofaproblem.Theconstructorbehavesdifferentlybasedonthenumberandtypeofarguments.WhenyoupassasinglenumericvaluetotheArray()constructor,anarrayofundefinedelementsiscreated,withthevalueofthelengthassignedtothevalueoftheargument:

letarr=newArray(2)console.log(arr)//[undefined,undefined]console.log(arr.length)//2

Ontheotherhand,ifyou passonlyonenon-numericvalue,itbecomesthe onlyiteminthearray:

letarr=newArray("2")console.log(arr)//["2"]console.log(arr.length)//1

Thisisnotall.Ifyoupassmultiplevalues,theybecomeelementsofthearray:

letarr=newArray(1,"2",{obj:"3"})console.log(arr.length)//3

So,clearly,thereneedstobeabetterwaytocreatearraystoavoidsuchconfusion.ES6introducestheArray.ofmethodthatworksliketheArray()constructor, butguaranteesonestandardbehavior.Array.ofcreatesanarrayfromitsarguments,regardlessoftheirnumberandtype:

letarr=Array.of(1,"2",{obj:"3"})console.log(arr.length)//3

Page 200: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array.prototypemethods

ES6introducesseveralinterestingmethodsaspartofarrayinstances.Thesemethodshelpwitharrayiterationandsearchingelementsinthearray,bothofwhichareveryfrequentandusefuloperations.

Herearethemethodsusedforiteratingoverarrays:

Array.prototype.entries()

Array.prototype.values()

Array.prorotype.keys()

Allthreemethodsreturnaniterator.ThisiteratorcanbeusedtocreatearraysusingArray.from()andcanbeusedinforloopsforiteration:

letarr=['a','b','c']for(constindexofarr.keys()){console.log(index)//012}for(constvalueofarr.values()){console.log(value)//abc}for(const[index,value]ofarr.entries()){console.log(index,value)}//0"a"//1"b"//2"c"

Similarly,therearenewmethodsforsearchingwithinarrays.Lookingfor anelementinanarrayusuallyinvolvediteratingthroughtheentirelistandcomparingthemwithavalue,astherewerenobuilt-inmethodsforthis.ThoughindexOf()andlastIndexOf()helpedfindasinglevalue,therewasnowaytofindelementsbasedoncomplexconditions.WithES6,thefollowingbuild-inmethodshelpwiththiskeyword.

Array.prototype.find

Array.prototype.findIndex

Boththesemethodsaccepttwoarguments-firstisthecallbackfunction(whichcontainsthepredicatecondition)and thesecondisanoptionalthiskeyword.Thecallbackacceptsthreearguments:thearrayelement,indexofthatelement,andthearray.Thecallbackreturnstrueiftheelementmatchesthepredicate:

letnumbers=[1,2,3,4,5,6,7,8,9,10];console.log(numbers.find(n=>n>5));//6console.log(numbers.findIndex(n=>n>5));//5

Page 201: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Function

Youalreadyknowthatfunctionsareaspecialdatatype.However,itturnsoutthatthere'smoretoitthanthat:functionsare actuallyobjects.Thereisabuilt-inconstructorfunctioncalledFunction()thatallowsforanalternative(butnotnecessarilyrecommended)waytocreateafunction.

Thefollowingexampleshowsthreewaystodefineafunction:

>functionsum(a,b){//functiondeclarationreturna+b;}

> sum(1, 2);3>varsum=function(a,b){//functionexpressionreturna+b;};>sum(1,2)3>varsum=newFunction('a','b','returna+b;');>sum(1,2)3

WhenusingtheFunction()constructor,youpasstheparameternamesfirst(asstrings)andthenthesourcecodeforthebodyofthefunction(againasastring).TheJavaScriptengineneedstoevaluatethesourcecodeyoupassandcreatethenewfunctionforyou.Thissourcecodeevaluationsuffersfromthesamedrawbacksastheeval()function,sodefiningfunctionsusingtheFunction()constructorshouldbeavoidedwhenpossible.

IfyouusetheFunction()constructortocreatefunctionsthathavelotsofparameters,bearinmindthattheparameterscanbepassedasasinglecomma-delimitedlist;so,forexample,thesearethesame:

>varfirst=newFunction('a,b,c,d','returnarguments;');>first(1,2,3,4);[1,2,3,4]>varsecond=newFunction(

'a, b, c','d','returnarguments;');>second(1,2,3,4);[1,2,3,4]>varthird=newFunction('a','b',

Page 202: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

'c','d','returnarguments;');>third(1,2,3,4);[1,2,3,4]

Note

DonotusetheFunction()constructor.Aswitheval()andsetTimeout()(discussedlaterinthebook),alwaystrytostayawayfrompassingJavaScriptcodeasastring.

Propertiesoffunctionobjects

Likeanyotherobject,functionshaveaconstructorpropertythatcontainsareferencetotheFunction()constructor function.Thisistruenomatterwhichsyntaxyouusedtocreatethefunction:

>functionmyfunc(a){returna;}

> myfunc.constructor;functionFunction(){[nativecode]}

Functionsalsohavealengthproperty,whichcontainsthenumberofformalparametersthefunctionexpects:

>functionmyfunc(a,b,c){returntrue;}>myfunc.length;3

Usingtheprototypeproperty

Oneofthemostwidelyusedpropertiesoffunctionobjectsistheprototypeproperty.You'llseethispropertydiscussedindetailinthenextchapter,butfornow,let'sjustsay:

TheprototypepropertyofafunctionobjectpointstoanotherobjectItsbenefitsshineonlywhenyouusethisfunctionasaconstructorAllobjectscreatedwiththisfunctionkeepareferencetotheprototypepropertyandcanuseitspropertiesastheirown

Let'slookataquickexampletodemonstratetheprototypeproperty.Takeasimpleobjectthathasapropertynameandamethodsay()method:

varninja={name:'Ninja',say:function(){return'Iama'+this.name;

Page 203: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}};

Whenyoucreateafunction(evenonewithoutabody),youcanverifythat itautomaticallyhasaprototypepropertythatpointstoanewobject:

>functionF(){}>typeofF.prototype;"object"

Itgetsinterestingwhenyoumodifytheprototypeproperty.Youcanaddpropertiestoit,oryoucanreplacethedefaultobjectwithanyotherobject.Let'sassignninjato theprototype:

>F.prototype=ninja;

Now,andhere'swherethemagichappens,usingtheF()functionasaconstructorfunction,youcancreateanewobject,baby_ninja,whichwillhaveaccesstothepropertiesofF.prototype(whichpointstoninja)asifitwereitsown:

>varbaby_ninja=newF();>baby_ninja.name;"Ninja">baby_ninja.say();"IamaNinja"

Therewillbemuchmoreonthistopiclater.Infact,thenextchapterisallabouttheprototypeproperty.

Methodsoffunctionobjects

Functionobjects,beingadescendantofthetopparentobject,getthedefaultmethodssuchastoString().Wheninvokedonafunction,thetoString()methodreturnsthesourcecodeofthefunction:

>functionmyfunc(a,b,c){returna+b+c;}>myfunc.toString();"functionmyfunc(a,b,c){returna+b+c;}"

Ifyoutrytopeekintothesourcecodeofthebuilt-infunctions,you'llgetthe[nativecode]stringinsteadofthebodyofthefunction:

> parseInt.toString();"functionparseInt(){[nativecode]}"

Asyoucansee,youcanusetoString()todifferentiatebetweennativemethodsanddeveloper-

Page 204: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

definedones.

Note

Thebehaviorofthefunction'stoString()isenvironmentdependent,anditdiffersamongbrowsersintermsofspacingandnewlines.

Callandapply

Functionobjectshavecall()andapply()methods.Youcanusethemtoinvokeafunctionandpassanyargumentstoit.

Thesemethodsalsoallowyourobjectstoborrowmethodsfromotherobjectsandinvokethemastheirown.Thisisaneasyandpowerfulwaytoreusecode.

Let'ssayyouhaveasome_objobject,whichcontainsthesay()method:

varsome_obj={name:'Ninja',say:function(who){return'Haya'+who+',Iama'+this.name;}};

Youcancallthesay()method,whichinternallyusesthis.nametogainaccesstoitsownnameproperty:

>some_obj.say('Dude');"HayaDude,IamaNinja"

Now,let'screateasimpleobject,my_obj,whichonlyhasanameproperty:

>varmy_obj={name:'Scriptingguru'};

Themy_objlikesthesome_objobject'ssay()methodsomuchthatitwantstoinvokeitasitsown.Thisispossibleusingthecall()methodofthesay()functionobject:

>some_obj.say.call(my_obj,'Dude');"HayaDude,IamaScriptingguru"

Itworked!Butwhathappenedhere?Youinvokedthecall()methodofthesay()functionobjectbypassingtwoparameters-themy_objobjectandtheDudestring.Theresultisthatwhensay()isinvoked,thereferencestothethisvaluethatitcontainspointtomy_obj.Thisway,this.namedoesn'treturnNinja,butScriptingguruinstead.

Ifyouhavemoreparameterstopasswheninvokingthecall()method,youjustkeepaddingthem:

Page 205: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

some_obj.someMethod.call(my_obj,'a','b','c');

Ifyoudon'tpassanobjectasafirstparametertocall()oryoupassnull,theglobalobjectisassumed.

Themethodapply()worksthesamewayascall(),butwiththedifferencethatallparametersyouwanttopasstothemethodoftheotherobjectarepassedasanarray.Thefollowingtwolinesareequivalent:

some_obj.someMethod.apply(my_obj,['a','b','c']);some_obj.someMethod.call(my_obj,'a','b','c');

Continuingthepreviousexample,youcanusethefollowinglineofcode:

>some_obj.say.apply(my_obj,['Dude']);"HayaDude,IamaScriptingguru"

Theargumentsobjectrevisited

Inthepreviouschapter,youhaveseenhow,frominsideafunction,youhaveaccesstosomethingcalledarguments,whichcontainsthevaluesofalltheparameterspassedtothefunction:

>functionf(){return arguments;

}>f(1,2,3);[1,2,3]

Theargumentslookslikeanarray,butitisactuallyanarray-likeobject.Itresemblesanarraybecauseitcontainsindexedelementsandalengthproperty.However,thesimilarityendsthere,asargumentsdoesn'tprovideanyofthearraymethods,suchassort()or slice().

However,youcanconvertargumentstoanarrayandbenefitfromallthe arraygoodies.Here'swhatyoucando,practicingyournewly-learnedcall()method:

>functionf(){varargs=[].slice.call(arguments);returnargs.reverse();}

>f(1,2,3,4);[4,3,2,1]

Asyoucansee,youcanborrowslice()using[].sliceorthemoreverboseArray.prototype.slice.

Page 206: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Lexical this in arrow functionsWe discussed ES6 arrow functions and the syntax in detail in the last chapter. However, animportantaspectofarrowfunctionsisthattheybehavedifferentlyfromnormalfunctions.Thedifferenceissubtlebutimportant.Arrowfunctionsdonothavetheirownvalueofthis.Thevalueofthisinanarrowfunctionisinheritedfromtheenclosing(lexical)scope.

Functionshaveaspecialvariablethisthatreferstotheobjectviawhich themethodwasinvoked.Asthevalueofthisisdynamicallygivenbasedonthefunctioninvocation,itissometimescalleddynamicthis.Afunctionisexecutedintwoscopes-lexicalanddynamic.Alexicalscopeisascopethatsurroundsthefunctionscope,andthedynamicscopeisthescopethatcalledthefunction(usuallyanobject)

InJavaScript,traditionalfunctionsplayseveralroles.Theyarenon-methodfunctions(akasubroutinesorfunctions),methods(partofanobject),andconstructors.Whenfunctionsdothedutyofasubroutine,thereisasmallproblemduetodynamicthis.Assubroutinesarenotcalledonanobject,thevalueofthisisundefinedinastrictmodeandsettothe globalscopeotherwise.Thismakeswritingcallbacksdifficult.Considerthefollowingexample:

vargreeter={default:"Hello",greet:function(names){names.forEach(function(name){console.log(this.default+name);//Cannotreadproperty'default'ofundefined})}}console.log(greeter.greet(['world','heaven']))

WearepassingasubroutinetotheforEach()functiononthenamesarray.Thissubroutinehasanundefinedvalueofthis,andunfortunately,itdoesnothaveaccesstothisoftheoutermethodgreet.Clearly,thissubroutineneedsalexicalthis,derivethisfromthesurroundingscopeofthegreetmethod.Traditionally,tofixthislimitation,weassignthelexicalthisintoavariable,whichisthenaccessibletothesubroutineviaclosure.

Wecanfixtheearlierexampleasfollows:

vargreeter={default:"Hello",greet:function(names){letthat=thisnames.forEach(function(name){console.log(that.default+name);})}

Page 207: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}console.log(greeter.greet(['world','heaven']))

Thisisareasonablehacktosimulatelexicalthis.However,theproblemwithsuchhacksisthatitcreatestoomuchnoiseforthepersonwritingorreviewingthiscode.First,youhavetounderstandthequirkofthebehaviorofthis.Evenifyouunderstandthisbehaviorwell,youwillneedtocontinuouslyremainonthelookoutforsuchhacksinyourcode.

Arrowfunctionshavelexicalthisanddonotrequiresuchahack.Theyaremoresuitedassubroutinesbecauseofthis.Wecancoverttheprecedingexampletouse lexicalthisusingthearrowfunction:

vargreeter={default:"Hello",greet:function(names){

names.forEach(name=> {console.log(this.default+name);//lexical'this'availableforthissubroutine})}}console.log(greeter.greet(['world','heaven']))

Page 208: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inferringobjecttypes

Youcanseethatyouhavethisarray-likeargumentsobjectlookingsomuchlikeanarrayobject.Howcanyoureliablytellthedifferencebetween thetwo?Additionally,typeofreturnsanobjectwhenusedwitharrays.Therefore,howcanyoutellthedifferencebetweenanobjectandanarray?

ThesilverbulletistheObjectobject'stoString()method.Itgivesyoutheinternalclassnameusedtocreateagivenobject:

>Object.prototype.toString.call({});"[objectObject]">Object.prototype.toString.call([]);"[objectArray]"

YouhavetocalltheoriginaltoString()methodasdefinedintheprototypeoftheObjectconstructor.Otherwise,ifyoucalltheArrayfunction'stoString(),itwillgiveyouadifferentresult,asit'sbeenoverriddenforthespecificpurposesofthearrayobjects:

>[1,2,3].toString();"1,2,3"

Theprecedingcodeissameas:

>Array.prototype.toString.call([1,2,3]);"1,2,3"

Let'shavesomemorefunwithtoString().Makeahandyreferencetosavetyping:

> var toStr = Object.prototype.toString;

Thefollowingexampleshowshowwecandifferentiatebetweenanarray andthearray-likeobjectarguments:

>(function(){returntoStr.call(arguments);}());"[objectArguments]"

YoucaneveninspectDOMelements:

>toStr.call(document.body);"[objectHTMLBodyElement]"

Page 209: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Boolean

Yourjourneythroughthe built-inobjectsinJavaScriptcontinues,andthenextthreearefairlystraightforward.TheyareBoolean,number,andstring.Theymerelywraptheprimitivedatatypes.

YoualreadyknowalotaboutBooleansfromChapter2,PrimitiveDataTypes,Arrays,Loops,andConditions.Now,let'smeettheBoolean()constructor:

>varb=newBoolean();

It'simportanttonotethatthiscreatesanewobject,b,andnotaprimitiveBooleanvalue.Togettheprimitivevalue,youcancallthevalueOf()method(inheritedfromObjectclassandcustomized):

>varb=newBoolean();>typeofb;"object">typeofb.valueOf();"boolean">b.valueOf();false

Overall,objectscreatedwiththeBoolean()constructorarenottoouseful,astheydon'tprovideanymethodsorpropertiesotherthantheinheritedones.

TheBoolean()function,whencalledasanormalfunctionwithoutnew,convertsnon-BooleanstoBooleans(whichislikeusingadoublenegation!!value):

>Boolean("test");true>Boolean("");false>Boolean({});true

Apartfromthesixfalsevalues,everythingelseistrueinJavaScript,includingallobjects.ThisalsomeansthatallBooleanobjectscreatedwithnewBoolean()arealsotrue,astheyareobjects:

>Boolean(newBoolean(false));true

Thiscanbeconfusing,andsinceBooleanobjectsdon'tofferanyspecialmethods,it'sbesttojuststickwithregularprimitiveBooleanvalues.

Page 210: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Number

SimilartoBoolean(),theNumber()functioncanbeusedas:

Aconstructorfunction(withnew)tocreateobjects.Anormalfunctioninordertotrytoconvertanyvaluetoanumber.Thisissimilartotheuseof parseInt() or parseFloat():

>varn=Number('12.12');>n;12.12>typeofn;"number">varn=newNumber('12.12');>typeofn;"object"

Asfunctionsareobjects,theycanalsohaveproperties.TheNumber()functionhasconstantbuilt-inpropertiesthatyoucannotmodify:

>Number.MAX_VALUE;1.7976931348623157e+308>Number.MIN_VALUE;5e-324>Number.POSITIVE_INFINITY;Infinity>Number.NEGATIVE_INFINITY;-Infinity>Number.NaN;NaN

Thenumberobjectsprovidethreemethods-toFixed(),toPrecision(),andtoExponential()(seeAppendixC,Built-inObjects,formoredetails):

>varn=newNumber(123.456);>n.toFixed(1);"123.5"

NotethatyoucanusethesemethodswithoutexplicitlycreatingaNumberobjectfirst.Insuchcases,theNumberobjectiscreated(anddestroyed)foryoubehindthescenes:

>(12345).toExponential();"1.2345e+4"

Likeallobjects,theNumberobjectalsoprovidethetoString()method.WhenusedwithNumberobject,thismethodacceptsanoptionalradixparameter(10beingthedefault):

>varn=newNumber(255);>n.toString();"255"

Page 211: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>n.toString(10);"255">n.toString(16);"ff">(3).toString(2);"11">(3).toString(10);"3"

Page 212: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

String

YoucanusetheString()constructorfunctiontocreatestringobjects.Stringobjectsprovideconvenientmethodsfortextmanipulation.

Here'sanexamplethatshowsthedifferencebetweenaStringobjectandaprimitivestringdatatype:

>varprimitive='Hello';>typeofprimitive;"string">varobj=newString('world');>typeofobj;"object"

AStringobjectissimilartoanarrayofcharacters.Stringobjectshaveanindexedpropertyforeachcharacter(introducedinES5,butlongsupportedinmanybrowsers,exceptoldIEs),andtheyalsohavealengthproperty.

>obj[0];"w">obj[4];

"d">obj.length;5

ToextracttheprimitivevaluefromtheStringobject,youcanusethevalueOf()ortoString()methodinheritedfromObject.You'llprobablyneverneedtodothis,astoString()iscalledbehindthescenesifyouuseanobjectinaprimitivestringcontext:

>obj.valueOf();"world">obj.toString();

"world">obj+"";"world"

Theprimitivestringsarenotobjects,sotheydon'thaveanymethodsorproperties.However,JavaScriptalsooffersyouthesyntaxtotreatprimitivestringsasobjects(justlikeyoualreadysawwithprimitivenumbers).

Inthefollowingexample,Stringobjectsarebeingcreated(andthendestroyed)behindthesceneseverytimeyoutreataprimitivestringasifitwereanobject:

>"potato".length;6

> "tomato"[0];"t"

Page 213: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>"potatoes"["potatoes".length-1];"s"

HereisonefinalexampletoillustratethedifferencebetweenaprimitivestringandaStringobject.Inthisexample,weareconvertingthemtoBoolean.Theemptystringisafalsyvalue,butanystringobjectistruthy(becauseallobjectsaretruthy):

>Boolean("");false>Boolean(newString(""));true

Similar to Number() and Boolean(), if you use the String() function without new, it convertsthe parameter to a primitive:

>String(1);"1"

IfyoupassanobjecttoString(),thisobject'stoString()methodwillbecalledfirst:

>String({p:1});"[objectObject]">String([1,2,3]);"1,2,3">String([1,2,3])===[1,2,3].toString();true

Afewmethodsofstringobjects

Let'sexperimentwithafewofthemethodsyoucancallonstringobjects(seeAppendixC,Built-inObjects,forthecompletelist).

Startoffbycreatingastringobject:

>vars=newString("Couchpotato");

ThetoUpperCase()andtoLowerCase()methodstransformthecapitalizationofthestring:

>s.toUpperCase();"COUCHPOTATO">s.toLowerCase();"couchpotato"

ThecharAt()methodtellsyouthecharacterfoundatthepositionyouspecify,whichisthesameasusingsquarebrackets(treatingastringasanarrayofcharacters):

>s.charAt(0);"C">s[0];"C"

Page 214: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Ifyoupassanon-existentpositiontocharAt(),yougetanemptystring:

>s.charAt(101);""

TheindexOf()methodallowsyoutosearchwithinastring.Ifthereisamatch,themethodreturnsthepositionatwhichthefirstmatchisfound.Thepositioncountstartsat0,sothesecondcharacterinCouchisoatposition1:

>s.indexOf('o');1

Youcanoptionallyspecifywhere(atwhatposition)tostartthesearch.Thefollowingfindsthesecondo,becauseindexOf()isinstructedtostartthesearchatposition2:

>s.indexOf('o',2);7

ThelastIndexOf()startsthesearchfromtheendofthestring(butthepositionofthematchisstillcountedfromthebeginning):

>s.lastIndexOf('o');11

You can search , not only for characters, but also for strings, and the search is case sensitive:

>s.indexOf('Couch');0

Ifthereisnomatch,thefunctionreturnsposition-1:

>s.indexOf('couch');-1

Foracase-insensitivesearch,youcantransformthestringtolowercasefirstandthensearch:

>s.toLowerCase().indexOf('couch'.toLowerCase());0

Ifyouget0,thismeansthatthematchingpartofthestringstartsatposition0.Thiscancauseconfusionwhenyoucheckwithif,becauseifconvertstheposition0toaBooleanfalsevalue.So,whilethisissyntacticallycorrect,itislogicallywrong:

if(s.indexOf('Couch')){...}

TheproperwaytocheckwhetherastringcontainsanotherstringistocomparetheresultofindexOf()tothenumber-1:

if(s.indexOf('Couch')!==-1){...}

Page 215: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theslice()andsubstring()returnapieceofthestringwhenyouspecifythestartandendpositions:

>s.slice(1,5);"ouch">s.substring(1,5);"ouch"

Notethatthesecondparameteryoupassistheendposition,notthelength ofthepiece.Thedifferencebetweenthesetwomethodsishowtheytreatnegativearguments.substring()treatsthemaszeros,whileslice()addsthemtothelengthofthestring.So,ifyoupassparameters(1,-1)tobothmethods,it'sthesameassubstring(1,0)andslice(1,s.length-1):

>s.slice(1,-1);"ouchpotat">s.substring(1,-1);"C"

There'salsothenon-standardmethodsubstr(),butyoushouldtrytoavoiditinfavorofsubstring().

Thesplit()methodcreatesanarrayfromthestringusinganotherstringthatyoupassasaseparator:

>s.split("");["Couch","potato"]

Thesplit()methodistheoppositeofthejoin()method,whichcreatesastringfromanarray:

>s.split('').join('');"Couchpotato"

Theconcat()gluesstringstogether,inthesamewayinwhichthe+operatordoesforprimitivestrings:

>s.concat("es");"Couch potatoes"

Notethatwhilesomeoftheprecedingmethodsdiscussedreturnnewprimitivestrings,noneofthemmodifythesourcestring.Afterallthemethodcallslistedpreviously,theinitialstringisstillthesame:

>s.valueOf();"Couchpotato"

YouhaveseenhowtouseindexOf()andlastIndexOf()tosearchwithinstrings,buttherearemorepowerfulmethods(search(),match(),andreplace())thattakeregularexpressionsasparameters.You'llseetheselaterintheRegExp()constructorfunction.

Page 216: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Atthispoint,you'redonewithallofthedatawrapperobjects,solet'smoveontotheutilityobjectsMath,Date,andRegExp.

Page 217: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Math

Mathisalittledifferentfromtheotherbuilt-inglobalobjectsyouhaveseenpreviously.It'snotafunction,and,therefore,cannotbeusedwithnewtocreateobjects.Mathisabuilt-inglobalobjectthatprovidesanumberofmethodsandpropertiesformathematicaloperations.

TheMathobject'spropertiesareconstants,soyoucan'tchangetheirvalues.Theirnamesareallinuppercasetoemphasizethedifferencebetweenthemandanormalproperty(similartotheconstantpropertiesoftheNumber()constructor).Let'sseeafewoftheseconstantproperties:

TheconstantPI:

>Math.PI;3.141592653589793

Squarerootof2:

>Math.SQRT2;1.4142135623730951

Euler'sconstant:

>Math.E;2.718281828459045

Naturallogarithmof2:

>Math.LN2;0.6931471805599453

Naturallogarithmof10:

>Math.LN10;2.302585092994046

Now,youknowhowtoimpressyourfriendsthenexttimethey(forwhateverreason)startwondering,"Whatwasthevalueofe?Ican'tremember."JusttypeMath.Eintheconsoleandyouhavetheanswer.

Let'stakealookatsome ofthemethodstheMathobjectprovides(thefulllistisinAppendixC,Built-inObjects).

Generatingrandomnumbers:

>Math.random();0.3649461670235814

Therandom()functionreturnsanumberbetween0and1,soifyouwantanumberbetween,let'ssay,0and100,youcanusethefollowinglineofcode:

Page 218: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>100*Math.random();

Fornumbersbetweenanytwovalues,usetheformula((max-min)*Math.random())+min.Forexample,arandomnumberbetween2and10canbeobtainedusingtheformulaasfollows:

>8*Math.random()+2;9.175650496668485

Ifyouonlyneedaninteger,youcanuseoneofthefollowingroundingmethods:

floor()torounddownceil()toroundupround()toroundtothenearest

Forexample,togeteither0or1,youcanusethefollowinglineofcode:

>Math.round(Math.random());

Ifyouneedthelowestorthehighestamongasetofnumbers,youhavethemin()andmax()methods.So,ifyouhave aformonapagethatasksforavalidmonth,you canmakesurethatyoualwaysworkwithsanedata(avaluebetween1and12):

>Math.min(Math.max(1,input),12);

TheMathobjectalsoprovidestheabilitytoperformmathematicaloperationsforwhichyoudon'thaveadesignatedoperator.Thismeansthatyoucanraisetoapowerusingpow(),findthesquarerootusingsqrt(),andperformallthetrigonometricoperations-sin(),cos(),atan(),andsoon.

Forexample,tocalculate2tothepowerof8,youcanusethefollowinglineofcode:

>Math.pow(2,8);256

To calculate the square root of 9, you can use the following line of code:

>Math.sqrt(9);3

Page 219: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Date

Date()isaconstructorfunctionthatcreatesdate objects.Youcancreateanewobjectbypassing:

Nothing (defaults to today's date)Adate-likestringSeparatevaluesfor day,month,time,andsoonAtimestamp

Hereisanobjectinstantiatedwithtoday'sdate/time(usingthebrowser'stimezone):

> new Date();WedFeb27201323:49:28GMT-0800(PST)

TheconsoledisplaystheresultofthetoString()methodcalledontheDateobject,soyougetthislongstringWedFeb27201323:49:28GMT-0800(PST)asarepresentationofthedateobject.

HereareafewexamplesofusingstringstoinitializeaDateobject.Notehowmanydifferentformatsyoucanusetospecifythedate:

>newDate('20151112');ThuNov12201500:00:00GMT-0800(PST)>newDate('112016');FriJan01201600:00:00GMT-0800(PST)>newDate('1mar20165:30');TueMar01201605:30:00GMT-0800(PST)

TheDateconstructorcanfigureoutadatefromdifferentstrings,butthisisnotreallyareliablewayofdefiningaprecisedate,forexample,whenpassinguserinputtotheconstructor.AbetterwayistopassnumericvaluestotheDate()constructorrepresenting:

YearMonth-0(January)to11(December)Day-1to31Hour-0to23Minutes-0to59Seconds-0to59Milliseconds-0to999

Let'slookatsomeexamples.

Passingalltheparametersbywritingthefollowinglineofcode:

>newDate(2015,0,1,17,05,03,120);TueJan01201517:05:03GMT-0800(PST)

Page 220: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Passingdateandhourbywritingthefollowinglineofcode:

>newDate(2015,0,1,17);TueJan01201517:00:00GMT-0800(PST)

Watchoutforthefactthatthemonthstartsfrom0,so1isFebruary:

>newDate(2016,1,28);SunFeb28201600:00:00GMT-0800(PST)

Ifyoupassavaluegreaterthantheoneallowed,yourdateoverflowsforward.Asthere'snoFebruary30in2016,thismeansithastobeMarch1(2016isaleapyear):

>newDate(2016,1,29);MonFeb29201600:00:00GMT-0800(PST)>newDate(2016,1,30);TueMar01201600:00:00GMT-0800(PST)

Similarly,December32becomesJanuary1ofthenextyear:

>newDate(2012,11,31);MonDec31201200:00:00GMT-0800(PST)>newDate(2012,11,32);TueJan01201300:00:00GMT-0800(PST)

Finally,adateobjectcanbeinitializedwithatimestamp(thenumberofmillisecondssincetheUNIXepoch,where0millisecondsisJanuary1,1970):

>newDate(1357027200000);TueJan01201300:00:00GMT-0800(PST)

IfyoucallDate()withoutnew,yougetastringrepresentingthecurrentdate,whetherornotyoupassanyparameters.Thefollowingexamplegivesthecurrenttime(currentwhenthisexamplewasrun):

>Date();WedFeb27201323:51:46GMT-0800(PST)>Date(1,2,3,"itdoesn'tmatter");WedFeb27201323:51:52GMT-0800(PST)>typeofDate();"string">typeofnewDate();"object"

Methodstoworkwithdateobjects

Onceyou'vecreatedadateobject,therearelotsofmethodsyoucancallonthatobject.Mostofthemethodscanbedividedintoset*()andget*()methods,forexample,getMonth(),setMonth(),getHours(),setHours(),andsoon.Let'sseesomeexamples.

Page 221: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Creatingadateobjectbywritingthefollowingcode:

>vard=newDate(2015,1,1);>d.toString();SunFeb01201500:00:00GMT-0800(PST)

SettingthemonthtoMarch(monthsstartfrom0):

>d.setMonth(2);1425196800000>d.toString();SunMar01201500:00:00GMT-0800(PST)

Gettingthemonthbywritingthefollowingcode:

>d.getMonth();2

Inadditiontoallthemethodsofdateobjects,therearealsotwomethods(plusonemoreaddedinES5)thatarepropertiesoftheDate()function/object.Thesedonotneed adateobject;theyworkjustliketheMathobjectmethods.Inclass-basedlanguages,suchmethodswouldbecalledstaticbecausetheydon'trequireaninstance.

TheDate.parse()methodtakesastringandreturnsatimestamp:

>Date.parse('Jan11,2018');1515657600000

The Date.UTC() method takes all the parameters for year, month, day, and so on, and produces atimestamp inUniversal Time (UT):

>Date.UTC(2018,0,11);1515628800000

AsthenewDate()constructorcanaccepttimestamps,youcanpasstheresultofDate.UTC()toit.Usingthefollowingexample,youcanseehowUTC()workswithUniversalTime,whilenewDate()workswithlocaltime:

>newDate(Date.UTC(2018,0,11));WedJan10201816:00:00GMT-0800(PST)>newDate(2018,0,11);ThuJan11201800:00:00GMT-0800(PST)

TheES5additiontotheDateconstructoristhenow()method,whichreturnsthecurrenttimestamp.ItprovidesamoreconvenientwaytogetthetimestampinsteadofusingthegetTime()methodonaDateobjectasyouwouldinES3:

>Date.now();1362038353044

Page 222: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>Date.now()===newDate().getTime();true

Youcanthinkoftheinternalrepresentationofthe datebeinganintegertimestampandallothermethodsbeingsugarontopofit.So,itmakessensethatvalueOf()isatimestamp:

>newDate().valueOf();1362418306432

Also,datescasttointegerswiththe+operator:

>+newDate();1362418318311

Calculatingbirthdays

Let'slookatonefinalexampleofworkingwithDateobjects.Iwascuriousaboutwhichdaymybirthdayfallsonin2016:

>vard=newDate(2016,5,20);>d.getDay();1

Startingthecountfrom0 (Sunday),1meansMonday.Isthatso?

>d.toDateString();"MonJun202016"

ok,goodtoknow,butMondayisnotnecessarilythebestdayforaparty.So,howaboutaloopthatshowshowmanytimesJune20isaFridayfromyear2016toyear3016,orbetteryet,let'sseethedistributionofallthedaysoftheweek.Afterall,withalltheprogressinDNAhacking,we'reallgoingtobealiveandkickingin3016.

First,let'sinitializeanarraywithsevenelements,oneforeachdayoftheweek.Thesewillbeusedascounters.Then,asaloopgoesupto3016,let'sincrementthecounters:

varstats=[0,0,0,0,0,0,0];

Hereistheloop:

for(vari=2016;i<3016;i++){stats[newDate(i,5,20).getDay()]++;}

Hereistheresult:

>stats;[140, 146, 140, 145, 142, 142, 145]

142Fridaysand145Saturdays.Woo-hoo!

Page 223: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

RegExp

Regularexpressionsprovideapowerfulwaytosearchandmanipulatetext.Differentlanguageshavedifferentimplementations(thinkdialects)oftheregularexpressionsyntax.JavaScriptusesthePerl5syntax.

Insteadofsayingregular expression,peopleoftenshortenittoregexorregexp.

Aregularexpressionconsistsof:

ApatternyouusetomatchtextZeroormoremodifiers(alsocalledflags)thatprovidemoreinstructionsonhowthepatternshouldbeused

Thepatterncanbeassimpleasliteraltexttobematchedverbatim,butthat'srare,andinsuchcasesyou'rebetteroffusingindexOf().Mostofthetime,thepatternismorecomplexandcouldbedifficulttounderstand.Masteringregularexpressions'patternsisalargetopic,whichwon'tbediscussedinfulldetailhere.Instead,you'llseewhatJavaScriptprovidesintermsofsyntax,objects, and methods in order to support the use of regular expressions. You can also refer toAppendixD,RegularExpressions,tohelpyouwhenyou'rewritingpatterns.

JavaScriptprovidestheRegExp()constructor,whichallowsyoutocreateregularexpressionobjects:

>varre=newRegExp("j.*t");

Thereisalsothemoreconvenientregexpliteralnotation:

>varre=/j.*t/;

Intheprecedingexample,j.*tistheregularexpressionpattern.Itmeans"matchesanystringthatstartswithj,endswitht,andhaszeroormorecharactersinbetween".Theasterisk(*)means"zeroormoreofthepreceding,"andthedot(.)means"anycharacter".ThepatternneedstobequotedwhenpassedtoaRegExp()constructor.

PropertiesofRegExpobjects

Regularexpressionobjectshavethefollowingproperties:

global:Ifthispropertyisfalse,whichisthedefault,thesearchstopswhenthefirstmatchisfound.Setthistotrueifyouwantallmatches.ignoreCase:Whenthematchiscaseinsensitive,thispropertydefaultstofalse(meaningthedefaultisacase-sensitivematch).multiline:Searchmatchesthatmayspanovermorethanonelinedefaulttofalse.lastIndex:Thepositionatwhichtostartthesearch;thisdefaultsto0.

Page 224: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

source:ThiscontainstheRegExppattern.

Noneoftheseproperties,exceptforlastIndex,canbechangedoncetheobjecthasbeencreated.

Thefirstthreeitemsintheprecedinglistrepresenttheregexmodifiers.Ifyoucreatearegexobjectusingtheconstructor,youcanpassanycombinationofthefollowingcharactersasasecondparameter:

gforglobaliforignoreCasemformultiline

Theseletterscanbeinanyorder.Ifaletterispassed,thecorrespondingmodifierpropertyissettotrue.Inthefollowingexample,allmodifiersaresettotrue:

>varre=newRegExp('j.*t','gmi');

Let'sverify:

>re.global;true

Once set, the modifier cannot be changed:

>re.global=false;>re.global;true

Tosetanymodifiersusingtheregexliteral,youaddthemaftertheclosingslash:

>varre=/j.*t/ig;>re.global;true

MethodsofRegExpobjects

Regexobjectsprovidetwomethodsyoucanusetofindmatches-test()andexec().Theybothacceptastringparameter.Thetest()methodreturnsaBoolean(truewhenthere'samatch,falseotherwise),whileexec()returnsanarrayofmatchedstrings.Obviously,exec()isdoingmorework,sousetest()onlyifyoureallyneedtodosomethingwiththematches.Peopleoftenuseregularexpressionstovalidatedata.Inthiscase,test()shouldbeenough.

Inthefollowingexample,thereisnomatchbecauseofthecapitalJ:

>/j.*t/.test("Javascript");false

Page 225: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Acase-insensitivetestgivesapositiveresult:

>/j.*t/i.test("Javascript");true

Thesametestusingexec()returnsanarray,andyoucanaccessthefirstelementasshownhere:

>/j.*t/i.exec("Javascript")[0];"Javascript"

Stringmethodsthatacceptregularexpressionsasarguments

Previouslyinthischapter,youlearnedaboutstringobjectsandhowyoucanusetheindexOf()andlastIndexOf()methodstosearchwithintext.Usingthesemethods,youcanonlyspecifyliteralstringpatternstosearch.Amorepowerfulsolutionwouldbetouseregularexpressionstofindtext.Stringobjectsofferyouthisability.

Stringobjectsprovidethefollowingmethodsthatacceptregularexpressionobjectsasparameters:

match():Returnsanarrayofmatchessearch():Returnsthepositionofthefirstmatchreplace():Allowsyoutosubstitutematchedtextwithanotherstringsplit():Acceptsaregexpwhensplittingastringintoarrayelements

search()andmatch()

Let'slookatsomeexamplesofusingthesearch()andmatch()methods. First,youcreateastringobject:

>vars=newString('HelloJavaScriptWorld');

Usingmatch(),yougetanarraycontainingonlythefirstmatch:

>s.match(/a/);["a"]

Usingthegmodifier,youperformaglobalsearch,sotheresultarraycontainstwoelements:

>s.match(/a/g);["a","a"]

Acase-insensitivematchisasfollows:

>s.match(/j.*a/i);["Java"]

Thesearch()methodgivesyouthepositionofthematchingstring:

>s.search(/j.*a/i);

Page 226: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

5

replace()

Thereplace()methodallowsyoutoreplacethematchedtextwithsomeotherstring.Thefollowingexampleremovesallcapitalletters(itreplacesthemwithblankstrings):

>s.replace(/[A-Z]/g,'');"elloavacriptorld"

Ifyouomitthegmodifier,you'reonlygoingtoreplacethefirstmatch:

>s.replace(/[A-Z]/,'');"elloJavaScriptWorld"

Whenamatchisfound,ifyouwanttoincludethematchedtextinthereplacementstring,youcanaccessitusing$&.Here'showtoaddanunderscorebeforethematchwhilekeepingthematch:

>s.replace(/[A-Z]/g,"_$&");"_Hello_Java_Script_World"

Whentheregularexpressioncontainsgroups(denotedbyparentheses),thematchesofeachgroupareavailableas$1forthefirstgroup,$2thesecond,andsoon:

>s.replace(/([A-Z])/g,"_$1");"_Hello_Java_Script_World"

Imagineyouhavearegistrationformonyourwebpagethatasksforane-mailaddress,username,and password. The user enters their e-mail IDs, and then, your JavaScript kicks in and suggeststheusername,takingitfromthee-mailaddress:

>varemail="[email protected]";>varusername=email.replace(/(.*)@.*/,"$1");>username;"stoyan"

Replacecallbacks

Whenspecifyingthereplacement,youcanalsopassafunctionthatreturnsastring.Thisgivesyoutheabilitytoimplementanyspeciallogicyoumayneedbeforespecifying thereplacements:

>functionreplaceCallback(match){return"_"+match.toLowerCase();}

>s.replace(/[A-Z]/g,replaceCallback);"_hello_java_script_world"

Thecallbackfunctionreceivesanumberofparameters(thepreviousexampleignoresallbutthefirstone):

Page 227: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ThefirstparameteristhematchThelastisthestringbeingsearchedTheonebeforelastisthepositionofthematchTherestoftheparameterscontainanystringsmatchedbyanygroupsinyourregexpattern

Let's test this. First, let's create a variable to store the entire arguments array passed to thecallbackfunction:

>varglob;

Next,definearegularexpressionthathasthreegroupsandmatchese-mailaddressesintheformatsomething@something.something:

>varre=/(.*)@(.*)\.(.*)/;

Finally,let'sdefineacallbackfunctionthatstorestheargumentsinglobandthenreturnsthereplacement:

varcallback=function(){glob=arguments;returnarguments[1]+'at'+arguments[2]+'dot'+arguments[3];};

Now,performatest:

>"[email protected]".replace(re,callback);"stoyanatphpieddotcom"

Here'swhatthecallbackfunctionreceivedasarguments:

>glob;["[email protected]","stoyan","phpied","com",0,"[email protected]"]

split()

Youalreadyknowaboutthesplit()method,whichcreatesanarrayfromaninputstringandadelimiterstring.Let'stakeastringofcomma-separatedvaluesandsplitit:

>varcsv='one,two,three,four';>csv.split(',');["one","two","three","four"]

Becausetheinputstringhappenstohaverandominconsistentspacesbeforeandafterthecommas,thearrayresulthasspacestoo.Witharegularexpression,youcanfixthisusing\s*,whichmeanszeroormorespaces:

>csv.split(/\s*,\s*/);

Page 228: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

["one","two","three","four"]

PassingastringwhenaRegExpisexpected

Onelastthingtonoteisthatthefourmethodsthat youhavejustseen(split(),match(),search(),andreplace())canalsotakestringsasopposedtoregularexpressions.Inthiscase,thestringargumentisusedtoproduceanewregexasifitwerepassedtonewRegExp().

Anexampleofpassinga stringtoreplaceisshownasfollows:

>"test".replace('t','r');"rest"

Theprecedinglinesofcodearethesameasthefollowingone:

>"test".replace(newRegExp('t'),'r');"rest"

When you pass a string, you cannot set modifiers the way you do with a normal constructor orregexliteral.There'sacommonsourceoferrorswhenusingastringinsteadofaregularexpressionobjectforstringreplacements,andit'sduetothefactthatthegmodifierisfalsebydefault.Theoutcomeisthatonlythefirststringisreplaced,whichisinconsistentwithmostotherlanguagesandalittleconfusing.Hereisanexample:

>"pool".replace('o','*');"p*ol"

Mostlikely,youwanttoreplacealloccurrences:

>"pool".replace(/o/g,'*');"p**l"

Errorobjects

Errorshappen,andit'sgoodtohavethemechanismsinplacesothatyourcodecanrealizethattherehasbeenanerrorconditionandcanrecoverfromitinagracefulmanner.JavaScriptprovidesthetry,catch,andfinallystatementstohelpyoudealwitherrors.Ifanerroroccurs,anerrorobjectisthrown.Errorobjectsarecreatedusingoneofthesebuilt-inconstructors-EvalError,RangeError,ReferenceError,SyntaxError,TypeError,andURIError.AlltheseconstructorsinheritfromError.

Let'sjustcauseanerrorandseewhathappens.What'sasimplewaytocauseanerror?Justcallafunctionthatdoesn'texist.Typethisintotheconsole:

>iDontExist();

You'll get something like the following:

Page 229: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thedisplayoferrorscanvarygreatlybetweenbrowsersandotherhostenvironments.Infact,mostrecentbrowserstendtohidetheerrorsfromtheusers.However,youcannotassumethatallofyourusershavedisabledthedisplayoferrors,anditisyourresponsibilitytoensureanerror-freeexperienceforthem.Thepreviouserrorpropagatedtotheuser,becausethecodedidn'ttrytotrap(catch)thiserror.Thecodedidn'texpecttheerrorandwasnotpreparedtohandleit.Fortunately,it'strivialtotraptheerror.Allyouneedisthetrystatementfollowedbyacatchstatement.

Thiscodehidestheerrorfromtheuser:

try{iDontExist();}catch(e){//donothing}

Here you have:

Thetrystatementfollowedbyablockofcode.Thecatchstatementfollowedbyavariablenameinparenthesesandanotherblockofcode.

Therecanbeanoptionalfinallystatement(notusedinthisexample)followedbyablockofcode,whichisexecutedregardlessofwhethertherewasanerrorornot.

Inthepreviousexample, thecodeblockthatfollowsthecatchstatementdidn'tdoanything.However,thisistheplacewhereyouputthecodethatcanhelprecoverfromtheerror,oratleastgivefeedbacktotheuserthatyourapplicationisawarethattherewasaspecialcondition.

Thevariableeintheparenthesesafterthecatchstatementcontainsanerrorobject.Likeanyotherobject,itcontainspropertiesandmethods.Unfortunately,differentbrowsersimplementthesemethodsandpropertiesdifferently,buttherearetwopropertiesthatareconsistentlyimplemented-e.nameande.message.

Page 230: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Let'strythiscodenow:

try{iDontExist();}catch(e){alert(e.name+':'+e.message);}finally{alert('Finally!');}

This will present an alert() showing e.name and e.message and then another alert() sayingFinally!.

InFirefoxandChrome,thefirstalertwillsayReferenceError:iDontExistisnotdefined.InInternetExplorer,itwillbeTypeError:Objectexpected.Thistellsustwothings:

Thee.namemethodcontainsthenameoftheconstructorthatwasusedtocreatetheerrorobjectAstheerrorobjectsarenotconsistentacrosshostenvironments(browsers),itwouldbesomewhattrickytohaveyourcodeactdifferentlydependingonthetypeoferror(thevalueof e.name)

YoucanalsocreateerrorobjectsyourselfusingnewError()oranyoftheothererrorconstructorsandthenlettheJavaScriptengineknowthatthere'sanerroneousconditionusingthethrowstatement.

Forexample,imagineascenariowhereyoucallthemaybeExists()functionandafterthatmakecalculations.Youwanttotrapallerrorsinaconsistentway,nomatterwhethertheerroristhatmaybeExists()doesn'texistorthatyourcalculationsfoundaproblem.Considerthefollowingcode:

try{vartotal=maybeExists();if(total===0){thrownewError('Divisionbyzero!');}else{alert(50/total);}}catch(e){alert(e.name+':'+e.message);}finally{alert('Finally!');}

ThiscodewillalertdifferentmessagesdependingonwhetherornotmaybeExists()isdefinedandthevaluesitreturns:

IfmaybeExists()doesn'texist,yougetReferenceError:maybeExists()isnotdefinedin

Page 231: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

FirefoxandTypeError:ObjectexpectedinIEIfmaybeExists()returns0,yougetError: Divisionbyzero!IfmaybeExists()returns2,yougetanalertthatsays25

Inallcases,therewillbeasecondalertthatsaysFinally!.

Insteadofthrowingagenericerror,thrownewError('Divisionbyzero!'),youcanbemorespecificifyouchooseto,forexample,throwthrownewRangeError('Divisionbyzero!').Alternatively,youdon'tneedaconstructor;youcansimplythrowanormalobject:

throw{name:"MyError",message:"OMG!Somethingterriblehashappened"}

Thisgivesyoucross-browsercontrolovertheerrorname.

Page 232: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ExercisesLets solve the following exercise:

1. Lookatthefollowingcode:

functionF(){functionC(){returnthis;

}returnC();}varo=newF();

Doesthevalueofthisrefertotheglobalobjectortheobjecto?2. What'stheresultofexecutingthispieceofcode?

functionC(){this.a=1;returnfalse;}console.log(typeofnewC());

3. What'stheresultofexecutingthefollowingpieceofcode?

>c=[1,2,[1,2]];> c.sort();

>c.join('--');>console.log(c);

4. ImaginetheString()constructordidn'texist.Createaconstructorfunction,MyString(),thatactslikeString()ascloselyaspossible.You'renotallowedtouseanybuilt-instringmethodsorproperties,andrememberthattheString()doesn'texist.Youcanusethiscodetotestyourconstructor:

>vars=newMyString('hello');>s.length;5>s[0];"h">s.toString();"hello">s.valueOf();"hello">s.charAt(1);"e">s.charAt('2');"l">s.charAt('e');"h">s.concat('world!');

Page 233: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"helloworld!">s.slice(1,3);"el">s.slice(0,-1);"hell">s.split('e');["h","llo"]>s.split('l');["he","","o"]

Note

Youcanuseaforlooptoloopthroughtheinputstring,treatingitasanarray.

5. UpdateyourMyString()constructortoincludeareverse()method.

Note

Trytoleveragethefactthatarrayshaveareverse()method.

6. ImaginethatArray()andthearrayliteralnotationdon'texist.CreateaconstructorcalledMyArray()thatbehavesasclosetoArray()aspossible.Testitwiththefollowingcode:

>vara=newMyArray(1,2,3,"test");>a.toString();"1,2,3,test">a.length;4>a[a.length-1];"test">a.push('boo');5>a.toString();"1,2,3,test,boo">a.pop();

"boo">a.toString();"1,2,3,test">a.join(',');"1,2,3,test">a.join('isn't');"1isn't2isn't3isn'ttest"

Ifyoufoundthisexerciseamusing,don'tstopwiththejoin()method;goonwithasmanymethodsaspossible.

7. ImagineMathdidn'texist.CreateaMyMathobjectthatalsoprovides thefollowingadditionalmethods:

MyMath.rand(min,max,inclusive):Thisgeneratesarandomnumberbetweenminandmax,inclusiveifinclusiveistrue(default)MyMath.min(array):ThisreturnsthesmallestnumberinagivenarrayMyMath.max(array):Thisreturnsthelargestnumberinagivenarray

Page 234: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn Chapter 2, Primitive Data Types, Arrays, Loops, and Conditions, you saw that there are fiveprimitivedatatypes(number,string,Boolean,null,andundefined),andwealsosaidthateverythingthatisnotaprimitivepieceofdataisanobject.Now,youalsoknowthat:

Objectsarelikearrays,butyouspecifythekeysObjectscontainpropertiesPropertiescanbefunctions(functionsaredata;remembervarf=function(){};).PropertiesthatarefunctionsarealsocalledmethodsArraysareactuallyobjectswithpredefinednumericpropertiesandanauto-incrementinglengthpropertyArrayobjectshaveanumberofconvenientmethods(suchassort()orslice())Functionsarealsoobjects,andtheyhaveproperties(suchaslengthandprototype)andmethods(suchascall()andapply())

Regardingthefiveprimitivedatatypes,apartfromundefinedandnull,theotherthreehavethecorrespondingconstructorfunctions-Number(),String(),andBoolean().Usingthese,youcancreateobjects,calledwrapperobjects,whichcontainmethodsforworkingwithprimitivedataelements.

Number(),String(),andBoolean()canbeinvoked:

Withthenewoperator,tocreatenewobjects.Withoutthenewoperator,toconvertanyvaluetothecorrespondingprimitivedatatype.

Otherbuilt-inconstructorfunctionsyou'renowfamiliarwithincludeObject(),Array(),Function(),Date(),RegExp(),andError().You'realsofamiliarwithMath-aglobalobjectthatisnotaconstructor.

Now,youcanseehowobjectshaveacentralroleinJavaScriptprogramming,asprettymucheverythingisanobjectorcanbewrappedbyanobject.

Finally,let'swrapuptheliteralnotationsyou'renowfamiliarwith:

Name Literal Constructor Example

Object {} newObject() {prop:1}

Array [] newArray() [1,2,3,'test']

Regularexpression /pattern/modifiers newRegExp('pattern','modifiers') /java.*/img

Page 235: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 5. ES6 Iterators and GeneratorsSo far, we have discussed language constructs of JavaScript without looking at any specificlanguageversion.Inthischapter,however,wewillprimarilyfocusonafewlanguagefeaturesintroducedinES6.ThesefeatureshaveabigimpactonhowyouwriteJavaScriptcode.Notonlydotheyimprovethelanguagesignificantly,theyalsoofferseveralfunctionalprogrammingconstructsunavailabletoJavaScriptprogrammersthusfar.

Inthischapter,wewilltakealookatnewlyintroducediteratorsandgeneratorsinES6.Withthatknowledge,wewillproceedtotakeadetailedlookattheenhancedCollectionsconstructs.

Page 236: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

For...of loopFor...of loops are introduced in ES6 along with the iterable and iterator constructs. This newloop constructs replaces both the for...in and for...each loop constructs of ES5. As thefor...of loop supports the iteration protocol, it can be used on built-in objects such as arrays,strings, maps, sets, and so on, and custom objects that are iterables. Consider the following pieceofcodeasanexample:

constiter=['a','b'];for(constiofiter){console.log(i);}"a""b"

Thefor...ofloopworkswithiterablesandbuilt-inslikearraysareiterables.Ifyounotice,weareusingconstinsteadofvarwhenwedefinetheloopvariable.Thisisagoodpracticebecausewhenyouuseconst,afreshvariableiscreatedwithanewbindingandstoragespace.Youshoulduseconstovera vardeclarationwiththefor...ofloopwhenyoudon'tintendtomodifythevalueoftheloopvariableinsidetheblock.

Othercollectionssupportfor...oflooptoo.Forexample,asastringisasequenceofUnicodecharacters,for...ofloopworksjustfine:

for(letcof"String"){console.log(c);}//"s""t""r""i""n""g"

Themaindifferencebetweenthefor...inandfor...ofloopisthatthefor...inloopiteratesthroughallenumerablepropertiesofanobject.For...ofloophasaspecificpurpose,andthatistofollowtheiterationbehaviorbasedonhowtheobjectdefinestheiterableprotocol.

Page 237: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iterators and iterablesES6 introduces a new mechanism of iterating over data. Traversing a list of data and doingsomethingwithitisaverycommonoperation.ES6enhancestheiterationconstructs.Therearetwoprimaryconceptsinvolvedwiththischange-iteratorsanditerables.

Page 238: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iterators

AJavaScriptiteratorisanobjectthatexposesthenext()method.Thismethodreturnsthenextitemfromthecollectionintheformofanobjectthathastwoproperties-doneandvalue.Inthefollowingexample,wewillreturnaniteratorfromanarraybyexposingthenext()method:

//Takeanarrayandreturnaniteratorfunctioniter(array){varnextId=0;return{next:function(){if(nextId<array.length){return{value:array[nextId++],done:false};}else{return{done:true};}}}}varit=iter(['Hello','Iterators']);console.log(it.next().value);//'Hello'console.log(it.next().value);//'Iterators'console.log(it.next().done);//true

In the preceding example, we are returning value and done till we have elements in the array.When we exhaust elements in the array to return, we will return done as true, indicating that theiteration has no more values. Elements from an iterator are accessed using the next() methodrepeatedly.

Page 239: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iterables

Aniterableisanobjectthatdefinesitsiterationbehaviororinternaliteration.Suchobjectscanbeusedinthefor...of loopsintroducedinES6.Built-intypessuchasarraysandstringsdefinedefaultiterationbehavior.Foranobjecttobeiterable,itmustimplementthe@@iteratormethod,meaningtheobjectmusthaveapropertywith'Symbol.iterator'askey.

Anobjectbecomesiterableifitimplementsamethodwhosekeyis'Symbol.iterator'.Thismethodmustreturnaniteratorviathenext()method.Let'stakealookatthefollowingexampletoclarifythis:

//Aniterableobject//1.Hasamethodwithkeyhas'Symbol.iterator'//2.Thismethodreturnsaniteratorviamethod'next'letiter={0:'Hello',1:'Worldof',2:'Iterators',length:3,[Symbol.iterator](){letindex=0;return{next:()=>{letvalue=this[index];letdone=index>=this.length;index++;return{value,done};}};}};for(letiofiter){console.log(i);}"Hello"

"World of ""Iterators"

Let'sbreakthisexampledownintosmallerpieces.Wearecreatinganiterableobject.Wewillcreateaniterobjectusingobjectliteralsyntaxthatwearealreadyfamiliarwith.Onespecialaspectofthisobjectisa[Symbol.iterator]method.ThismethoddefinitionusesacombinationofcomputedpropertiesandES6shorthandmethoddefinitionsyntax,whichwealreadydiscussedinthelastchapter.Asthisobjectcontainsa[Symbol.iterator]method,thisobjectisiterable,oritfollowsaniterableprotocol.Thismethodalsoreturnstheiteratorobjectthatdefinestheiterationbehaviorviaexposingthenext()method.Nowthisobjectcanbeusedwiththefor...ofloop.

Page 240: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

GeneratorsClosely linked with iterators and iterables, generators are one of the most talked about features ofES6.Generatorfunctionsreturnageneratorobject;thistermsoundsconfusingatfirst.Whenyouwriteafunction,youalsoinstinctivelyunderstanditsbehavior-thefunctionstartsexecution,line-by-line,andfinishesexecutionwhenthelastlineisexecuted.Oncethefunctionislinearlyexecutedthisway,therestofthecodethatfollowsthefunctionisexecuted.

Inlanguageswheremultithreadingissupported,suchflowofexecutioncanbeinterruptedandpartiallyfinishedtaskscanbesharedbetweendifferentthreads,processes,andchannels.JavaScriptissingle-threaded,andyoudon'tneed todealwithchallengesaroundmultithreadingatthemoment.

However,generatorfunctionscanbepausedandresumedlater.Theimportantideahereisthatthegeneratorfunctionchoosestopauseitself,itcannotbepausedbyanyexternalcode.Duringexecution,thefunctionusestheyieldkeywordtopause.Onceageneratorfunctionispaused,itcanonlyberesumedbycodeoutsidethefunction.

Youcanpauseandresumeageneratorfunctionasmanytimesyouwantto.Withgeneratorfunctions,apopularpatternistowriteinfiniteloopsandpauseandresumethemwhenneeded.Thereareprosandconsofdoingthis,butthepatternhascaughtupalready.

Anotherimportantpointtounderstandisthatgeneratorfunctionsalsoallowtwo-waymessagepassing,inandoutofit.Wheneveryoupausethefunctionusingyieldkeyword,themessageissentoutofthegeneratorfunction,andwhenthefunctionisresumed,themessageispassedbacktothegeneratorfunction.

Let'slookatthefollowingexampletoclarifyhowthegeneratorfunctionswork:

function*generatorFunc(){console.log('1');//----------->Ayield;//----------->Bconsole.log('2');//----------->C}constgeneratorObj=generatorFunc();console.log(generatorObj.next());//"1"//Object{//"done":false,//"value":undefined

//}

Thisisaverysimplegeneratorfunction.However,thereareseveralinterestingaspectsthatneedcarefulunderstanding.

Page 241: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

First,noticeanasterix*immediatelyafterthekeywordfunction,thisisthesyntaxtoindicatethatthefunctionisageneratorfunction.Itisalsookaytokeeptheasteriximmediatelyprecedingthefunctionname.Bothofthefollowingarevaliddeclarations:

function*f(){}function*f(){}

Insidethefunction,therealmagicisaroundtheyieldkeyword.Whentheyieldkeywordisencountered,thefunctionpausesitself.Beforewemovefurther,let'sseehowthefunctionisinvoked:

constgeneratorObj=generatorFunc();generatorObj.next();//"1"

Whenweinvokethegeneratorfunction,itisnotexecutedlikeanormalfunction,butitreturnsagenerator object. You can use this generator object to control the execution of the generatorfunction.Thenext()methodonthegeneratorobjectresumestheexecutionofthefunction.

Whenwecallnext()thefirsttime,theexecutionproceedsupuntilthefirstlineofthefunction(markedby'A'),andpauseswhentheyieldkeywordisencountered.Ifwecallthenext()functionagain,itwillresumetheexecutiontothe nextlinefromthepointtheexecutionwaspausedlasttime:

console.log(generatorObj.next());//"2"//Object{//"done":true,//"value":undefined//}

Oncetheentirefunctionbodyisexecuted,anycallstonext()onthegeneratorobjecthavenoeffect.Wetalkedaboutgeneratorfunctionsallowingatwo-waymessagepassing.Howdoesthatwork?Inthepreviousexample,youcanseethatwheneverweresumethegeneratorfunction,wereceiveanobjectwithtwovalues,doneandvalue;inourcase,wereceivedundefinedasthevalue.Thisisbecausewedidnotreturnanyvaluewiththeyieldkeyword.Whenyoureturnavaluewiththeyieldkeyword,thecallingfunctionreceivesit.Considerthefollowingexample:

function* logger() {console.log('start')console.log(yield)console.log(yield)console.log(yield)return('end')}

vargenObj=logger();

//thefirstcallofnextexecutesfromthe

Page 242: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

startofthefunctionuntilthefirstyieldstatementconsole.log(genObj.next())//"start",Object{"done":false,"value":undefined}console.log(genObj.next('Save'))//"Save",Object{"done":false,"value":undefined}console.log(genObj.next('Our'))//"Our",Object{"done":false,"value":undefined}console.log(genObj.next('Souls'))//"Souls",Object{"done":true,"value":"end"}

Let'stracetheflowofexecutionofthisexamplestepbystep.Thegeneratorfunctionhasthreepausesoryields.Wecancreatethegeneratorobjectbywritingthefollowinglineofcode:

vargenObj=logger();

Wewillstarttheexecutionofthegeneratorfunctionbycallingthenextmethod;thismethodstartstheexecutiontillthefirstyield.Ifyounotice,wearenotpassinganyvaluetothenext()methodinthefirstcall.Thepurposeofthisnext()methodisjusttostartthegeneratorfunction.Wewillcallthenext()methodagain,butthistimewitha"Save"valuepassedasaparameter.Thisvalueisreceivedbyyieldwhenthefunctionexecutionisresumed,andwecanseethevalueprintedonconsole:

"Save",Object{"done":false,"value":undefined}

Wewillcallthenext()methodagainwithtwodifferentvalues,andtheoutputissimilartotheoneintheprecedingcode.Whenwecallthenext()methodthelasttime,theexecutionendsandthegeneratorfunctionreturnsanendvaluetothecallingpieceofcode.Attheendoftheexecution,youwillseedonesetastrueandvalueassignedthevaluereturnedbythefunction,thatis,end:

"Souls",Object{"done":true,"value":"end"}

Itisimportanttonotethatthepurposeofthefirstnext()methodistostarttheexecutionofthegeneratorfunction-ittakesustothefirstyieldkeywordandhence,anyvaluepassedtothefirstnext()methodisignored.

Fromthediscussionsofar,itisapparentthatgeneratorobjectsconformtotheiteratorcontract:

function*logger(){yield'a'yield'b'}vargenObj=logger();//thegeneratorobjectisbuiltusinggeneratorfunctionconsole.log(typeofgenObj[Symbol.iterator]==='function')//true//itisaniterableconsole.log(typeofgenObj.next==='function')//true//andaniterator(hasanext()method)console.log(genObj[Symbol.iterator]()===genObj)//true

Page 243: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thisexampleconfirmsthatgeneratorfunctionsalsoconformtotheiterablescontract.

Page 244: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iteratingovergenerators

Generatorsareiterators, andlikeallES6constructsthatsupportiterables,theycanbeusedtoiterateovergenerators.

Thefirstmethodistousethefor...ofloop,asshowninthefollowingcode:

function*logger(){yield'a'yield'b'}for(constioflogger()){console.log(i)}//"a""b"

Wearenotcreatingageneratorobjecthere.TheFor...ofloophassupportforiterablesandgeneratorsnaturallyfallintothisloop.

Thespreadoperatorcanbeusedtoturniterables intoarrays.Considerthefollowingexample:

function* logger() {yield'a'yield'b'}constarr=[...logger()]console.log(arr)//["a","b"]

Finally,youcanusethedestructuringsyntaxwithgenerators,asfollows:

function*logger(){yield'a'yield'b'}

const [x,y] = logger()console.log(x,y)//"a""b"

Generatorsplayanimportantroleinasynchronousprogramming.Shortly,wewilllookatasynchronousprogrammingandpromisesinES6.JavaScriptandNode.jsofferagreatenvironmenttowriteasynchronousprograms.Generatorscanhelpyouwritecooperativemultitaskingfunctions.

Page 245: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CollectionsES6 introduces four data structures-Map, WeakMap, Set, and WeakSet. JavaScript, whencompared to other languages such as Python and Ruby, had a very weak standard library tosupporthashorMapdatastructuresordictionaries.SeveralhackswereinventedtosomehowachievethebehaviorofaMapbymappingastringkeywithanobject.Thereweresideeffectsofsuchhacks.Languagesupportforsuchdatastructureswassorelyneeded.

ES6supportsstandarddictionarydatastructures; wewilllookatmoredetailsaroundtheseinthenextsection.

Page 246: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Map

Mapallowsarbitraryvaluesaskeys.Thekeysaremappedtovalues.Mapsallowfastaccesstovalues.Let'slookatsomeexamplesofmaps:

const m = new Map(); //Creates an empty Mapm.set('first',1);//Setavalueassociatedwithakeyconsole.log(m.get('first'));//Getavalueusingthekey

WewillcreateanemptyMapusingtheconstructor.Youcanusetheset() methodtoaddanentrytotheMapassociatingkeywithvalue,andoverwritinganyexistingentrywiththesamekey.Itscounterpartmethod,get(),getsthevalueassociatedwithakey,orundefinedifthereisnosuchentryinthemap.

Thereareotherhelpermethodsavailablewithmaps,whichareasfollows:

console.log(m.has('first'));//Checksforexistenceofakey//truem.delete('first');console.log(m.has('first'));//false

m.set('foo',1);m.set('bar', 0);

console.log(m.size);//2m.clear();//clearstheentiremapconsole.log(m.size);//0

YoucancreateaMapusingthefollowingiterable[key,value]pairsaswell:

constm2=newMap([[ 1, 'one' ],

[2,'two'],[3,'three'],]);

Youcanchaintheset() methodforacompactsyntaxasfollows:

constm3=newMap().set(1,'one').set(2,'two').set(3,'three');

Wecanuseanyvalueasakey.Forobjects,thekeycanonlybestrings,butwithcollections,thislimitationisremoved.Wecanuseanobjectasakeyaswell,thoughsuchuseisnotverypopular:

constobj={}constm2=newMap([[1,'one'],["two",'two'],[obj,'three'],]);console.log(m2.has(obj));//true

Page 247: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Iteratingovermaps

Oneimportantthingtorememberisthatorderisimportantwithmaps.Mapsretaintheorderinwhichelementswereadded.

TherearethreeiterablesyoucanusetoiterateoveraMap,thatis,keys,values,andentries.

Thekeys()methodreturnsiterableoverthekeysofaMapasfollows:

constm=newMap([[1,'one'],[2,'two'],[3,'three'],]);for(constkofm.keys()){console.log(k);}//123

Similarly,thevalues()methodreturnsiterableoverthevaluesofaMap,asshowninthefollowingexample:

for(constvofm.values()){console.log(v);}//"one"//"two"//"three"

Theentries()methodreturnsentriesoftheMapinformofa[key,value]pair,asyoucanseeinthefollowingcode:

for(constentryofm.entries()){console.log(entry[0],entry[1]);}//1"one"//2"two"//3"three"

Youcanusedestructuringtomakethisconciseasfollows:

for(const[key,value]ofm.entries()){console.log(key, value);

}//1"one"//2"two"//3"three"

Anevenmoresuccinct:

for(const[key,value]ofm){

Page 248: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

console.log(key,value);}//1"one"//2"two"//3"three"

Convertingmapstoarrays

Thespreadoperator(...)comesinhandyifyouwanttoconvertaMaptoanarray:

constm=newMap([[1,'one'],[2,'two'],[3,'three'],]);constkeys=[...m.keys()]console.log(keys)//Array[//1,//2,//3//]

Asmapsareiterable,youcanconverttheentireMapintoanarrayusingspreadoperators:

constm=newMap([[1,'one'],[2,'two'],[3,'three'],]);constarr=[...m]console.log(arr)//Array[//[1,"one"],//[2,"two"],//[3,"three"]//]

Page 249: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Set

ASetisacollectionofvalues.Youcanaddandremovevaluesfromit.Althoughthissoundssimilartoarrays,setsdon'tallowthesamevaluetwice.ValueinaSetcanbeofanytype.Sofar,youmustbewonderinghowdifferentisthisfromanArray?ASetisdesignedtodoonethingquickly-membershiptesting.Arraysarerelativelysloweratthis.SetoperationsaresimilartoMapoperations:

consts=newSet();s.add('first');s.has('first');//trues.delete('first');//trues.has('first');//false

Similartomaps,youcancreateaSetviaaniterator:

constcolors=newSet(['red',white,'blue']);

WhenyouaddavaluetotheSet,andthevaluealreadyexisted,nothinghappens.Similarly,ifyoudeleteavaluefromtheSet,andthevaluedidn'texistinthefirstplace,nothinghappens.Thereisnowaytocatchthisscenario.

Page 250: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

WeakMapandWeakSet

WeakMapandWeakSethavethesimilar,butrestricted,APIsastheMapandSetrespectively,andtheyworkmostlyliketheirstrongcounterparts.Thereareafewdifferencesthough,whichareasfollows:

WeakMaponlysupportsthenew,has(),get(),set(),anddelete()methodsWeakSetonlysupportsnew,has(),add(),anddelete()KeysofaWeakMapmustbeobjectsValuesofaWeakSetmustbeobjectsYoucan'titerateoverWeakMap;theonlywayyoucanaccessavalueisviaitskeyYoucan'titerateoveraWeakSetYoucan'tclearaWeakMaporaWeakSet

Let'sunderstandWeakMapfirst.ThedifferencebetweenaMapandaWeakMapisthataWeakMapallowsitselftobegarbagecollected.ThekeysinaWeakMapareweaklyheld.WeakMapkeysarenotcountedwhenthegarbagecollectordoesareferencecount(atechniquetoseeallalivereferences),andtheyaregarbagecollectedwhen possible.

WeakMapsareusefulwhenyoudon'thaveanycontroloverthelifecycleoftheobjectyouarekeepingintheMap.Youdon'tneedtoworryaboutmemoryleakwhenusingWeakMapsbecausetheobjectswillnotkeepthememoryoccupiedeveniftheirlifecycleislong.

SameimplementationdetailsapplytoWeakSetaswell.However,asyoucannotiterateoveraWeakSet,therearenotmanyusecasesforaWeakSet.

Page 251: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, we took a detailed look at ES6 Generators. Generators are one of the mostanticipatedfeaturesofES6.Theabilitytopauseandresumeexecutionofafunctionopensupalotofpossibilitiesaroundco-operativeprogramming.Theprimarystrengthofgeneratorsisthattheyprovideasingle-threaded,synchronous-lookingcodestyle,whilehidingtheasynchronousnatureaway.Thismakesiteasierforustoexpressinaverynaturalwaywhattheflowofourprogram'ssteps/statementsiswithoutsimultaneouslyhavingtonavigateasynchronoussyntaxandgotchas.Weachieveseparationofconcernusinggeneratorsduetothis.

Generatorsworkhand-in-handwiththeiteratorsanditerablescontract.ThesearewelcomeadditiontoES6andsignificantlybooststhedatastructuresthelanguageoffers.Iteratorsprovideasimplewaytoreturna(potentiallyunbounded)sequenceofvalues.The@@iteratorsymbolisusedtodefinedefaultiteratorsforobjects,makingthemaniterable.

Themostimportantusecaseforiteratorsbecomesevidentwhenwewanttouseitinaconstructthatconsumesiterables,suchasthefor...ofloop.Inthischapterwealsolookedatanewloopconstructfor...ofintroducedinES6.for...ofworkswithalotofnativeobjectsbecausetheyhavedefault@@iteratormethodsdefined.WelookedatnewadditionstotheES6collectionslike-Maps,Sets,WeakMaps,andWeakSets.Thesecollectionshaveadditionaliteratormethods-.entries(),.values()and.keys().

ThenextchapterwilltakeadetailedlookatJavaScriptPrototypes.

Page 252: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 6. PrototypeIn this chapter, you'll learn about the prototype property of the function objects. UnderstandinghowtheprototypeworksisanimportantpartoflearningtheJavaScriptlanguage.Afterall,JavaScriptisoftenclassifiedashavingaprototype-basedobjectmodel.There'snothingparticularlydifficultabouttheprototype,butit'sanewconcept,andassuch,maysometimestakeabitoftimetosinkin.Likeclosures(seeChapter3,Functions),theprototypeisoneofthosethingsinJavaScriptwhich,onceyouget,seemsoobviousandmakeperfectsense.Aswiththerestofthisbook,you'restronglyencouragedtotypeinandplayaroundwiththeexamples-thismakesitmucheasiertolearnandremembertheconcepts.

Inthischapter,wewillcoverthefollowingtopics:

EveryfunctionhasaprototypepropertyanditcontainsanobjectAddingpropertiestotheprototypeobjectUsingthepropertiesaddedtotheprototypeThedifferencebetweenownpropertiesandpropertiesoftheprototypeThe__proto__property,thesecretlinkeveryobjectkeepstoitsprototypeMethodssuchasisPrototypeOf(),hasOwnProperty(),andpropertyIsEnumerable()Enhancingbuilt-inobjects,suchasarraysorstrings,andwhythatcanbeabadidea

Page 253: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

The prototype propertyThe functions in JavaScript are objects, and they contain methods and properties. Some of themethodsthatyou'realreadyfamiliarwithareapply()andcall(),andsomeoftheotherpropertiesarelengthandconstructor.Anotherpropertyofthefunctionobjectsisprototype.

Ifyoudefineasimplefunction,foo(),youcanaccessitspropertiesasyouwoulddowithanyotherobject.Considerthefollowingcode:

>functionfoo(a,b){returna*b;}>foo.length;2>foo.constructor;functionFunction(){[nativecode]}

Theprototypepropertyisapropertythatisavailabletoyouassoonasyoudefinethefunction.Itsinitialvalueisanemptyobject:

>typeoffoo.prototype;"object"

It'sasifyouhaveaddedthispropertyyourself,asfollows:

>foo.prototype={};

Youcanaugmentthisemptyobjectwithpropertiesandmethods.Theywon'thaveanyeffectonthefoo()functionitself;they'llonlybeusedifyoucallfoo()asaconstructor.

Page 254: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Addingmethodsandpropertiesusingtheprototype

Inthepreviouschapter,youlearnedhowtodefineconstructorfunctionsthatyoucanusetocreate(construct)newobjects.Themainideaisthat,insideafunctioninvokedwithnew,youwillhaveaccesstothethisvalue,whichreferstotheobjecttobereturnedbytheconstructor.Augmenting,whichisaddingmethodsandpropertiestothis,ishowyoucanaddfunctionalitytotheobjectbeingconstructed.

Let'stakealookattheconstructorfunction,Gadget(),whichusesthistoaddtwopropertiesandonemethodtotheobjectsitcreates,asfollows:

functionGadget(name,color){this.name=name;this.color=color;

this.whatAreYou = function () {return'Iama'+this.color+''+this.name;};}

Addingmethodsandpropertiestotheprototypepropertyoftheconstructorfunctionisanotherwaytoaddfunctionalitytotheobjectsthisconstructorproduces.Let'saddtwomoreproperties,priceandrating,aswellasagetInfo()method.Asprototypealreadypointstoanobject,youcanjustkeepadding propertiesandmethodstoit,asfollows:

Gadget.prototype.price=100;Gadget.prototype.rating=3;Gadget.prototype.getInfo=function(){return'Rating:'+this.rating+',price:'+this.price;};

Alternatively, instead of adding properties to the prototype object one by one, you canoverwrite the prototype completely, replacing it with an object of your choice, as shown in thefollowing example:

Gadget.prototype={price:100,rating:.../*andsoon...*/};

Page 255: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Using the prototype's methods and propertiesAll the methods and properties you have added to the prototype are available as soon as youcreate a new object using the constructor. If you create a newtoy object using the Gadget()constructor, you can access all the methods and properties that are already defined, as you can seeinthefollowingcode:

>varnewtoy=newGadget('webcam','black');>newtoy.name;"webcam">newtoy.color;"black">newtoy.whatAreYou();"Iamablackwebcam">newtoy.price;100>newtoy.rating;3>newtoy.getInfo();"Rating:3,price:100"

It'simportanttonotethattheprototypeislive.ObjectsarepassedbyreferenceinJavaScript,andtherefore,theprototypeisnotcopiedwitheverynewobjectinstance.Whatdoesthismeaninpractice?Itmeansthatyoucanmodifytheprototypeatanytime,andalltheobjects,eventhosecreatedbeforethemodification,willseethechanges.

Let's continue the example by adding a new method to the prototype:

Gadget.prototype.get=function(what){returnthis[what];};

Eventhoughthenewtoyobjectwascreatedbeforetheget()methodwasdefined,thenewtoyobjectstillhasaccessto thenewmethod,whichisasfollows:

>newtoy.get('price');100>newtoy.get('color');"black"

Page 256: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Ownpropertiesversusprototypeproperties

Intheprecedingexample,getInfo()wasusedinternallytoaccessthepropertiesoftheobject.Itcould'vealsousedGadget.prototypetoachievethesameoutput,asfollows:

Gadget.prototype.getInfo=function(){return'Rating:'+Gadget.prototype.rating+',price:'+Gadget.prototype.price;};

What'sthedifference?Toanswerthisquestion,let'sexamineindetailhowtheprototypeworks.

Let'stakethenewtoyobjectagain:

varnewtoy=newGadget('webcam','black');

Whenyoutrytoaccessapropertyofnewtoy,say,newtoy.name,theJavaScriptenginelooksthroughallofthepropertiesoftheobjectsearchingforonecalledname,andifitfindsit,itreturnsitsvalue,asfollows:

>newtoy.name;"webcam"

Whatifyoutrytoaccesstheratingproperty?TheJavaScriptengineexaminesallofthepropertiesofthenewtoyobjectanddoesn'tfindtheonecalledrating.Then,thescriptengineidentifiestheprototypeoftheconstructorfunctionusedtocreatethisobject(thesameasifyoudonewtoy.constructor.prototype).Ifthepropertyisfoundintheprototypeobject,thefollowingpropertyisused:

>newtoy.rating;3

Youcandothesameandaccesstheprototypedirectly.Everyobjecthasaconstructorproperty,whichisareferencetothefunctionthatcreatedtheobject,sointhiscaselookatthefollowingcode:

>newtoy.constructor===Gadget;true>newtoy.constructor.prototype.rating;3

Now,let'stakethislookuponestepfurther.Everyobjecthasaconstructor.Theprototypeisanobject,soitmusthaveaconstructortoo,which,inturn,hasaprototype.Youcangouptheprototypechain,andyou willeventuallyendupwiththebuilt-inObject()object,whichisthehighest-levelparent.Inpractice,thismeansthatifyoutrynewtoy.toString()andnewtoydoesn'thaveitsowntoString()method,anditsprototypedoesn'teither,intheend,you'llget

Page 257: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

theobject'stoString()method:

>newtoy.toString();"[objectObject]"

Page 258: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Overwritingaprototype'spropertywithanownproperty

Astheprecedingdiscussiondemonstrates,ifoneofyourobjectsdoesn'thaveacertainpropertyofitsown,itcanuseone,ifitexists,somewhereuptheprototypechain.Whatiftheobjectdoeshaveitsownpropertyandtheprototypealsohasonewiththesamename?Then,theownpropertytakesprecedenceovertheprototype's.

Considerascenariowhereapropertynameexistsasbothanownpropertyandapropertyoftheprototypeobject:

>functionGadget(name){this.name=name;}>Gadget.prototype.name='mirror';

Creatinganewobjectandaccessingitsnamepropertygivesyoutheobject'sownnameproperty,asfollows:

>vartoy=newGadget('camera');>toy.name;"camera"

YoucantellwherethepropertywasdefinedusinghasOwnProperty(),whichisasfollows:

>toy.hasOwnProperty('name');true

Ifyoudeletethetoyobject'sownnameproperty,theprototype'sproperty withthesamenameshinesthrough:

>deletetoy.name;true>toy.name;"mirror">toy.hasOwnProperty('name');false

Ofcourse,youcanalwaysrecreatetheobject'sownpropertyasfollows:

>toy.name='camera';> toy.name;

"camera"

YoucanplayaroundwiththehasOwnProperty()methodtofindouttheoriginsofaparticularpropertyyou'recuriousabout.ThetoString()methodwasmentionedearlier.Whereisitcomingfrom?

Page 259: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>toy.toString();"[objectObject]">toy.hasOwnProperty('toString');false>toy.constructor.hasOwnProperty('toString');false>toy.constructor.prototype.hasOwnProperty('toString');false>Object.hasOwnProperty('toString');false>Object.prototype.hasOwnProperty('toString');true

Enumeratingproperties

Ifyouwanttolistallthepropertiesofanobject,youcanuseafor...inloop.InChapter2,PrimitiveDataTypes,Arrays,Loops,andConditions,yousawthatyoucanalsoloopthroughalltheelementsofanarraywithfor...in,butasmentionedthere,forisbettersuitedforarraysandfor...inforobjects.Let'stakeanexampleofconstructingaquerystringforaURLfromanobject:

var params = {productid:666,section:'products'};

varurl='http://example.org/page.php?',i,query=[];

for(iinparams){query.push(i+'='+params[i]);}

url+=query.join('&');

Thisproducestheurlstringasfollows:

http://example.org/page.php?productid=666&section=products.

Thefollowingareafewdetailstobeawareof:

Notallpropertiesshowupinafor...inloop.Forexample,thelength(forarrays)andconstructorpropertiesdon'tshowup.Thepropertiesthatdoshowuparecalledenumerable.YoucancheckwhichonesareenumerablewiththehelpofthepropertyIsEnumerable()methodthateveryobjectprovides.InES5,youcanspecifywhichpropertiesareenumerable,whileinES3youdon'thavethatcontrol.Prototypesthatcomethroughtheprototypechainalsoshowup,providedtheyareenumerable.Youcancheckwhetherapropertyisanobject'sownpropertyoraprototype's

Page 260: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

propertyusingthehasOwnProperty()method.ThepropertyIsEnumerable()methodreturnsfalseforalloftheprototype'sproperties,eventhosethatareenumerableandshowup inthefor...inloop.

Let'sseethesemethodsinaction.TakethissimplifiedversionofGadget():

functionGadget(name,color){this.name=name;

this.color = color;this.getName=function(){returnthis.name;};}Gadget.prototype.price=100;Gadget.prototype.rating=3;

Createanewobjectasfollows:

varnewtoy=newGadget('webcam','black');

Now,ifyouloopusingafor...inloop,youcanseealloftheobject'sproperties,includingthosethatcomefromtheprototype:

for(varpropinnewtoy){console.log(prop+'='+newtoy[prop]);}

Theresultalsocontainstheobject'smethods,asmethodsarejustpropertiesthathappentobefunctions:

name=webcamcolor=blackgetName=function(){returnthis.name;}price=100rating=3

Ifyouwanttodistinguishbetweentheobject'sownpropertiesandtheprototype'sproperties,usehasOwnProperty().Trythefollowingfirst:

>newtoy.hasOwnProperty('name');true

>newtoy.hasOwnProperty('price');false

Let'sloopagain,butthistime,showingonlytheobject'sownproperties:

for(varpropinnewtoy){if(newtoy.hasOwnProperty(prop)){console.log(prop+'='+newtoy[prop]);

Page 261: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}}

Theresultisasfollows:

name=webcamcolor=blackgetName=function(){returnthis.name;

}

Now,let'strypropertyIsEnumerable().Thismethodreturnstruefortheobject'sownpropertiesthatarenotbuiltin,forexample:

>newtoy.propertyIsEnumerable('name');true

Mostbuilt-inpropertiesandmethodsarenotenumerable:

>newtoy.propertyIsEnumerable('constructor');false

Anypropertiescomingdowntheprototypechainarenotenumerable:

> newtoy.propertyIsEnumerable('price');false

However,notthatsuchpropertiesareenumerableifyoureachtheobjectcontainedintheprototypeandinvokeitspropertyIsEnumerable()method.Considerthefollowingcode:

>newtoy.constructor.prototype.propertyIsEnumerable('price');true

Page 262: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

UsingisPrototypeOf()method

ObjectsalsohavetheisPrototypeOf()method.Thismethodtellsyouwhetherthatspecificobjectisusedasaprototypeofanotherobject.

Let'stakeasimpleobjectnamedmonkey:

varmonkey={hair:true,feeds:'bananas',breathes:'air'};

Now,let'screateaHuman()constructorfunctionandsetitsprototypepropertytopointtomonkey:

functionHuman(name){this.name=name;}Human.prototype=monkey;

Now,ifyoucreateanewHumanobjectcalledgeorgeandaskIfmonkeytheprototypeofgeorge?,you'llgettrue:

>vargeorge=newHuman('George');>monkey.isPrototypeOf(george);true

Notethatyouhavetoknow,orsuspect,whotheprototypeisandthenaskisittruethatyourprototypeismonkey?inordertoconfirmyoursuspicion.But,whatifyoudon'tsuspectanything,andyouhavenoidea?Canyoujustasktheobjecttotellyouitsprototype?Theansweris,youcan'tinallbrowsers,butyoucaninmostofthem.MostrecentbrowsershaveimplementedtheadditiontoES5calledObject.getPrototypeOf().

>Object.getPrototypeOf(george).feeds;"bananas">Object.getPrototypeOf(george)===monkey;true

Forsomeofthepre-ES5environmentsthatdon'thavegetPrototypeOf(),youcanusethespecialproperty,__proto__.

Page 263: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thesecret__proto__link

Asyoualreadyknow,theprototypepropertyisconsultedwhenyoutrytoaccessapropertythatdoesnotexistinthecurrentobject.

Consideranotherobjectcalledmonkey,anduseitasaprototypewhencreatingobjectswiththeHuman()constructor:

>varmonkey={feeds:'bananas',breathes:'air'};>functionHuman(){}>Human.prototype=monkey;

Now,let'screateadeveloperobject,andgiveitthefollowingproperties:

>vardeveloper=newHuman();>developer.feeds='pizza';>developer.hacks='JavaScript';

Now,let'saccesstheseproperties(forexample,hacksisapropertyofthedeveloperobject):

>developer.hacks;"JavaScript"

Thefeedspropertycanalsobefoundintheobject,asfollows:

>developer.feeds;"pizza"

Thebreathespropertydoesn'texistasapropertyofthedeveloperobject,sotheprototypeislookedup,asifthereisasecretlinkorpassagewaythatleadstotheprototypeobject:

>developer.breathes;"air"

The secret link is exposed in most modern JavaScript environments as the __proto__ property,the word proto with two underscores before and after:

>developer.__proto__===monkey;true

Youcanusethissecretpropertyforlearningpurposes,butit'snotagoodideatouseitinyourrealscriptsbecauseitdoesnotexistinallbrowsers(notablyIE),soyour scriptswon'tbeportable.

Beawarethat__proto__isnotthesameasprototype,as__proto__isapropertyofthe

Page 264: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

instances(objects),whereasprototypeisapropertyoftheconstructorfunctionsusedtocreatethoseobjects:

>typeofdeveloper.__proto__;"object">typeofdeveloper.prototype;"undefined">typeofdeveloper.constructor.prototype;"object"

Onceagain,youshoulduse__proto__onlyforlearningordebuggingpurposes.Or,ifyou'reluckyenoughandyourcodeonlyneedstoworkinES5-compliantenvironments,youcanuseObject.getPrototypeOf().

Page 265: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Augmenting built-in objectsThe objects created by the built-in constructor functions, such as Array, String, and evenObject and Function, can be augmented (or enhanced) through the use of prototypes. This meansthat you can, for example, add new methods to the Array prototype, and in this way you can makethem available to all arrays. Let's see how to do this.

InPHP,thereisafunctioncalledin_array(),whichtellsyouwhetheravalueexistsinanarray.InJavaScript,thereisnoinArray()method,although,inES5,there'sindexOf(),whichyoucanuseforthesamepurpose.So,let'simplementitandaddittoArray.prototype,asfollows:

Array.prototype.inArray=function(needle){for(vari=0,len=this.length;i<len;i++){if(this[i]===needle){returntrue;}}returnfalse;};

Now,allarrayshaveaccesstothenewmethod.Let'stestthefollowingcode:

>varcolors=['red','green','blue'];>colors.inArray('red');true>colors.inArray('yellow');false

Thatwasniceandeasy!Let'sdoitagain.Imagineyourapplicationoftenneedstospellwordsbackward,andyoufeelthereshouldbeabuilt-in reverse()methodforstringobjects.Afterall,arrayshavereverse().Youcaneasilyaddareverse()methodtotheStringprototypebyborrowingArray.prototype.reverse()(therewasasimilarexerciseattheendofChapter4,Objects):

String.prototype.reverse=function(){returnArray.prototype.reverse.apply(this.split('')).join('');};

Thiscodeusesthesplit()methodtocreateanarrayfromastring,thencallsthereverse()methodonthisarray,whichproducesareversedarray.Theresultingarrayisthenturnedbackintoastringusingthejoin()method.Let'stestthenewmethod:

>"bumblebee".reverse();"eebelbmub"

Page 266: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Augmentingbuilt-inobjects-discussion

Augmentingbuilt-inobjectsthroughtheprototypeisapowerfultechnique,andyoucanuseittoshapeJavaScriptinanywayyoulike.Becauseofitspower,though,youshouldalwaysthoroughlyconsideryouroptionsbeforeusingthisapproach.

ThereasonisthatonceyouknowJavaScript,you'reexpectingittoworkthesameway,nomatterwhichthird-partylibraryorwidgetyou'reusing.Modifyingcoreobjectscanconfusetheusersandmaintainersofyourcodeandcreateunexpectederrors.

JavaScript evolves and browser's vendors continuously support more features. What you consideramissingmethodtodayanddecidetoaddtoacoreprototypecouldbeabuilt-inmethodtomorrow.Inthiscase,yourmethodisnolongerneeded.Additionally,whatifyouhavealreadywrittenalotofcodethat usesthemethodandyourmethodisslightlydifferentfromthenewbuilt-inimplementation?

Themostcommonandacceptableusecasetoaugmentbuilt-inprototypesistoaddsupportfornewfeatures(onesthatarealreadystandardizedbytheECMAScriptcommitteeandimplementedinnewbrowsers)tooldbrowsers.OneexamplewillbeaddinganES5methodtooldversionsofIE.Theseextensionsareknownasshimsorpolyfills.

Whenaugmentingprototypes,youwillfirstcheckifthemethodexistsbeforeimplementingityourself.Thisway,youcanusethenativeimplementationinthebrowserifoneexists.Forexample,let'saddthetrim()methodforstrings,whichisamethodthatexistsinES5butismissinginolderbrowsers:

if(typeofString.prototype.trim!=='function'){String.prototype.trim=function(){returnthis.replace(/^\s+|\s+$/g,'');};}>"hello".trim();"hello"

Tip

Bestpractice

Ifyoudecidetoaugmentabuilt-inobject,oritsprototypewithanewproperty,docheckfortheexistenceofthenewpropertyfirst.

Page 267: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Prototypegotchas

Thefollowingarethetwoimportantbehaviorstoconsiderwhendealingwithprototypes:

The prototype chain is live, except for when you completely replace the prototype objectThe prototype.constructor method is not reliable

Let'screateasimpleconstructorfunctionandtwoobjects:

>functionDog(){this.tail=true;}>varbenji=newDog();>varrusty=newDog();

Even after you've created the benji and rusty objects, you can still add properties to theprototype of Dog() and the existing objects will have access to the new properties. Let's throw inthe say() method:

>Dog.prototype.say=function(){return'Woof!';};

Bothobjectshaveaccesstothenewmethod:

>benji.say();"Woof!"rusty.say();"Woof!"

Uptothispoint,ifyouconsultyourobjects,askingwhichconstructorfunctionwasusedtocreatethem,they'llreportitcorrectly:

>benji.constructor===Dog;true

> rusty.constructor === Dog;true

Now,let'scompletelyoverwritetheprototypeobjectwithabrandnewobject:

>Dog.prototype={paws:4,hair:true};

Itturnsoutthattheoldobjectsdonotgetaccesstothenewprototype'sproperties;theystillkeepthe secret link pointing to the old prototype object, as follows:

>typeofbenji.paws;"undefined"

Page 268: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>benji.say();"Woof!">typeofbenji.__proto__.say;"function">typeofbenji.__proto__.paws;"undefined"

Anynewobjectsthatyouwillcreatefromnowonwillusetheupdatedprototype,whichisasfollows:

>varlucy=newDog();>lucy.say();TypeError:lucy.sayisnotafunction>lucy.paws;

4

Thesecret__proto__linkpointstothenewprototypeobject,asshowninthefollowinglinesofcode:

>typeoflucy.__proto__.say;"undefined">typeoflucy.__proto__.paws;"number"

Nowtheconstructorpropertyofthenewobjectnolongerreportscorrectly.YouwillexpectittopointtoDog(),butinsteaditpointstoObject(),asyoucanseeinthefollowingexample:

>lucy.constructor;functionObject(){[nativecode]}>benji.constructor;functionDog(){this.tail=true;}

Youcaneasilypreventthisconfusionbyresettingtheconstructorpropertyafteryouoverwritetheprototypecompletely,asfollows:

>functionDog(){}>Dog.prototype={};>newDog().constructor===Dog;false>Dog.prototype.constructor=Dog;>newDog().constructor===Dog;true

Tip

Bestpractice

Whenyouoverwritetheprototype,remembertoresettheconstructorproperty.

Page 269: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ExercisesLets practice the following exercise:

1. CreateanobjectcalledshapethathasthetypepropertyandagetType()method.2. DefineaTriangle()constructorfunctionwhoseprototypeisshape.Objectscreatedwith

Triangle()shouldhavethreeownproperties-a,b,andc,representingthelengthsofthesidesofatriangle.

3. AddanewmethodtotheprototypecalledgetPerimeter().4. Testyourimplementationwiththefollowingcode:

>vart=newTriangle(1,2,3);>t.constructor===Triangle;true>shape.isPrototypeOf(t);true>t.getPerimeter();6

> t.getType();"triangle"

5. Loopovert,showingonlyyourownpropertiesandmethods,noneoftheprototype's.6. Makethefollowingcodework:

>[1,2,3,4,5,6,7,8,9].shuffle();[2,4,1,8,9,6,5,3,7]

Page 270: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryLet's summarize the most important topics you have learned in this chapter:

Allfunctionshaveapropertycalledprototype.Initially,itcontainsanemptyobject-anobjectwithoutanyownproperties.Youcanaddpropertiesandmethodstotheprototypeobject.Youcanevenreplaceitcompletelywithanobjectofyourchoice.Whenyoucreateanobjectusingafunctionasaconstructor(withnew),theobjectgetsasecretlinkpointingtotheprototypeoftheconstructorandcanaccesstheprototype'sproperties.Anobject'sownpropertiestakeprecedence overaprototype'spropertieswiththesamename.UsethehasOwnProperty()methodtodifferentiatebetweenanobject'sownpropertiesandprototypeproperties.Thereisaprototypechain.Whenyouexecutefoo.bar,andifyourfooobjectdoesn'thaveapropertycalledbar,theJavaScriptinterpreterlooksforabarpropertyintheprototype.Ifnoneisfound,itkeepssearchingintheprototype'sprototype,thentheprototypeoftheprototype'sprototype,anditwillkeepgoingallthewayuptoObject.prototype.Youcanaugmenttheprototypesofbuilt-inconstructorfunctions,and allobjectswillseeyouradditions.AssignafunctiontoArray.prototype.flipandallarrayswillimmediatelygetaflip()method,asin[1,2,3].flip().But,docheckwhetherthemethod/propertyyouwanttoaddalreadyexists,soyoucanfuture-proofyourscripts.

Page 271: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 7. InheritanceIf you go back to Chapter 1, Object-Oriented JavaScript, and review the Object-orientedprogrammingsection,you'llseethatyoualreadyknowhowtoapplymostofthemtoJavaScript.Youknowwhatobjects,methods,andpropertiesare.Youknowthatthere arenoclassesinES5,althoughyoucanachievethemusingconstructorfunctions.ES6introducesthenotionofclasses;wewilltakeadetailedlookathowES6classesworkinthenextchapter.Encapsulation?Yes,theobjectsencapsulateboth thedataandthemeans(methods)todosomethingwiththedata.Aggregation?Sure,anobjectcancontainotherobjects.Infact,thisisalmostalwaysthecasesincemethodsarefunctionsandfunctionsarealsoobjects.

Now,let'sfocusontheinheritancepart.Thisisoneofthemostinterestingfeatures,asitallowsyoutoreuseexistingcode,thuspromotinglaziness,whichislikelytobewhatbroughthumanspeciestocomputerprogramminginthefirstplace.

JavaScriptisadynamiclanguage,andthereisusuallymorethanonewaytoachieveanygiventask.Inheritanceisnotanexception.Inthischapter,you'llseesomecommonpatternsforimplementinginheritance.Havingagoodunderstandingofthesepatternswillhelpyoupicktherightone,ortherightmix,dependingonyourtask,project,orstyle.

Page 272: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Prototype chainingLet's start with the default way of implementing inheritance - inheritance chaining through theprototype.

Asyoualreadyknow,everyfunctionhasaprototypeproperty,whichpointstoanobject.Whenafunctionisinvokedusingthenewoperator,anobjectiscreatedandreturned.Thisnewobjecthasasecretlinktotheprototypeobject.Thesecretlink(called__proto__insomeenvironments)allowsmethodsandpropertiesoftheprototypeobjecttobeusedasiftheybelongedtothenewlycreatedobject.

Theprototypeobjectisjustaregularobjectand,therefore,italsohasthesecretlinktoitsprototype.Andso,achaincalledaprototypechainiscreated:

In this illustration, an object A contains a number of properties. One of the properties is thehidden__proto__property,whichpointstoanotherobject,B.B's__proto__propertypointstoC.ThischainendswiththeObject.prototypeobject,thegrandparent,andeveryobjectinheritsfromit.

Thisisallgoodtoknow,buthowdoesithelpyou?ThepracticalsideisthatwhenobjectAlacksapropertybutBhasit,Acanstillaccessthispropertyasitsown.ThesameappliesifBalsodoesn'thavetherequiredproperty,butCdoes.Thisishowinheritancetakesplace-anobjectcan

Page 273: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

accessanypropertyfoundsomewheredowntheinheritancechain.

Throughoutthischapter,you'llseedifferentexamplesthatusethefollowinghierarchy-agenericShape parent is inherited by a 2D shape, which in turn is inherited by any number of specifictwo-dimensional shapes such as a triangle, rectangle, and so on.

Page 274: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Prototypechainingexample

Prototypechainingisthedefaultwaytoimplementinheritance.Inordertoimplementthehierarchy,let'sdefinethreeconstructorfunctions:

functionShape(){this.name='Shape';this.toString=function(){returnthis.name;

};}

functionTwoDShape(){this.name='2Dshape';}

functionTriangle(side,height){this.name='Triangle';this.side=side;this.height=height;this.getArea=function(){returnthis.side*this.height/2;};}

Thecodethatperformstheinheritancemagicisasfollows:

TwoDShape.prototype=newShape();Triangle.prototype=newTwoDShape();

What'shappeninghere?YoutaketheobjectcontainedintheprototypepropertyofTwoDShape,andinsteadofaugmentingitwithindividualproperties,youcompletelyoverwriteitwithanotherobject,createdbyinvokingtheShape()constructorwithnew.ThesameprocesscanbefollowedforTriangle-itsprototypeisreplacedbyanobjectcreatedbynewTwoDShape().It'simportanttorememberthatJavaScriptworkswithobjects,notclasses.YouneedtocreateaninstanceusingthenewShape()constructor,andafterthat,youcaninherititsproperties;youdon'tinheritfromShape()directly.Additionally,afterinheriting,youcanmodifytheShape()constructor,overwriteit,orevendeleteit,andthiswillhavenoeffectonTwoDShape,becauseallyouneededisoneinstancetoinheritfrom.

Asyouknowfromthepreviouschapter,overwritingtheprototype(asopposedtojustaddingproperties to it), has side effects on the constructor property. Therefore, it's a good idea toreset the constructor property after inheriting. Consider the following example:

TwoDShape.prototype.constructor=TwoDShape;Triangle.prototype.constructor=Triangle;

Now,let'stestwhathashappenedsofar.CreatingaTriangleobjectandcallingitsown

Page 275: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

getArea()methodworksasexpected:

>varmy=newTriangle(5,10);>my.getArea();25

Although the my object doesn't have its own toString() method, it inherited one and you can callit. Note how the inherited method toString() binds the this object to my:

>my.toString();"Triangle"

It'sfascinatingtoconsiderwhattheJavaScriptenginedoeswhenyoucall my.toString():

Itloopsthroughallofthepropertiesofmyanddoesn'tfindamethodcalledtoString().Itlooksattheobjectthatmy.__proto__pointstothisobjectistheinstancenewTwoDShape()createdduringtheinheritanceprocess.Now,theJavaScriptengineloopsthroughtheinstanceofTwoDShapeanddoesn'tfindatoString()method.Itthenchecks__proto__ofthatobject.Thistime,__proto__pointstotheinstancecreatedbynewShape().TheinstanceofnewShape()isexamined,andtoString()isfinallyfound.Thismethodisinvokedinthecontextofmy,meaningthatthispointstomy.

Ifyouaskmy,Who'syourconstructor?,itreportsitcorrectlybecauseoftheresetoftheconstructorpropertyaftertheinheritance:

>my.constructor===Triangle;true

Usingtheinstanceofoperator,youcanvalidatethatmyisaninstanceofallthreeconstructors:

>myinstanceofShape;true>myinstanceofTwoDShape;true>myinstanceofTriangle;true>myinstanceofArray;false

ThesamehappenswhenyoucallisPrototypeOf()ontheconstructorsbypassingmy:

>Shape.prototype.isPrototypeOf(my);true>TwoDShape.prototype.isPrototypeOf(my);true>Triangle.prototype.isPrototypeOf(my);true>String.prototype.isPrototypeOf(my);

Page 276: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

false

Youcanalsocreateobjectsusingtheothertwoconstructors.ObjectscreatedwithnewTwoDShape()alsogetthetoString()methodinheritedfromShape():

>vartd=newTwoDShape();>td.constructor === TwoDShape;

true>td.toString();"2Dshape">vars=newShape();>s.constructor===Shape;true

Page 277: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Movingsharedpropertiestotheprototype

Whenyoucreateobjects usingaconstructorfunction,ownpropertiesareaddedusingthis.Thiscouldbeinefficientincaseswherepropertiesdon'tchangeacrossinstances.Inthepreviousexample,Shape()wasdefinedasfollows:

function Shape(){this.name='Shape';}

ThismeansthateverytimeyoucreateanewobjectusingnewShape(),anewnamepropertyiscreatedandstoredsomewhereinthememory.Theotheroptionistohavethenamepropertyaddedtotheprototypeandsharedamongalltheinstances:

functionShape(){}Shape.prototype.name='Shape';

Now,everytimeyoucreateanobjectusingnewShape(),thisobjectdoesn'tgetitsownpropertyname,butusestheoneaddedtotheprototype.Thisismoreefficient,butyoushouldonlyuseitforpropertiesthatdon'tchangefromoneinstancetoanother.Methodsareidealforthistypeofsharing.

Let'simprovetheprecedingexamplebyaddingallmethodsandsuitablepropertiestoprototype.InthecaseofShape()andTwoDShape(),everythingismeanttobeshared:

//constructorfunctionShape(){}

//augmentprototypeShape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.name;};

//anotherconstructorfunctionTwoDShape(){}

//takecareofinheritanceTwoDShape.prototype=newShape();TwoDShape.prototype.constructor=TwoDShape;

//augmentprototypeTwoDShape.prototype.name='2Dshape';

Asyoucansee,youhavetotakecareofinheritancefirstbeforeaugmentingtheprototype.Otherwise, anything you add to TwoDShape.prototype gets wiped out when you inherit.

TheTriangleconstructorisalittledifferent,becauseeveryobjectitcreatesisanewtriangle,

Page 278: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

whichislikelytohavedifferentdimensions.So,it'sgoodtokeepsideandheightasownpropertiesandsharetherest.ThegetArea()method,forexample,isthesame,regardlessoftheactualdimensionsofeachtriangle.Again,youdotheinheritancebitfirstandthenaugmenttheprototype:

functionTriangle(side,height){this.side=side;this.height=height;}//takecareofinheritanceTriangle.prototype=newTwoDShape();Triangle.prototype.constructor=Triangle;

//augmentprototypeTriangle.prototype.name='Triangle';Triangle.prototype.getArea=function(){returnthis.side*this.height/2;};

Alltheprecedingtestcodeworksexactlythesame.Hereisanexample:

>varmy=newTriangle(5,10);>my.getArea();25>my.toString();"Triangle"

Thereisonlyaslightbehind-the-scenesdifferencewhencallingmy.toString().ThedifferenceisthatthereisonemorelookuptobedonebeforethemethodisfoundinShape.prototype,asopposedtointhenewShape()instance,likeitwasinthepreviousexample.

YoucanalsoplaywithhasOwnProperty()toseethedifferencebetweentheownpropertyversusapropertycomingdowntheprototypechain:

>my.hasOwnProperty('side');true>my.hasOwnProperty('name');false

ThecallstoisPrototypeOf()andtheinstanceofoperatorfromthepreviousexampleworkinexactlythesameway:

>TwoDShape.prototype.isPrototypeOf(my);true>myinstanceofShape;true

Page 279: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inheriting the prototype onlyAs explained earlier, for reasons of efficiency, you should add the reusable properties andmethodstotheprototype.Ifyoudoso,thenit'sagoodideatoinheritonlytheprototype,becauseallthereusablecodeisthere.ThismeansthatinheritingtheShape.prototypeobjectisbetterthaninheritingtheobjectcreatedwithnewShape().Afterall,newShape()onlygivesyouownshapepropertiesthatarenotmeanttobereused(otherwise,theywouldbeintheprototype).Yougainalittlemoreefficiencyby:

NotcreatinganewobjectforthesakeofinheritancealoneHavingfewerlookupsduringruntime(whenitcomestosearchingfortoString())

For example, here's the updated code; the changes are highlighted:

functionShape(){}//augmentprototypeShape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.name;};

functionTwoDShape(){}//takecareofinheritanceTwoDShape.prototype=Shape.prototype;TwoDShape.prototype.constructor=TwoDShape;//augmentprototypeTwoDShape.prototype.name='2Dshape';

function Triangle(side, height) {this.side=side;this.height=height;}

//takecareofinheritanceTriangle.prototype=TwoDShape.prototype;Triangle.prototype.constructor=Triangle;//augmentprototypeTriangle.prototype.name='Triangle';Triangle.prototype.getArea=function(){returnthis.side*this.height/2;};

Thetestcodegivesyouthesameresult:

>varmy=newTriangle(5,10);>my.getArea();25>my.toString();"Triangle"

Page 280: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

What'sthedifferenceinthelookupswhencallingmy.toString()?First,asusual,theJavaScriptenginelooksforatoString()methodofthemyobjectitself.Theenginedoesn'tfindsuchamethod,soitinspectstheprototype.TheprototypeturnsouttobepointingtothesameobjectthattheprototypeofTwoDShapepointstoandalsothesameobjectthatShape.prototypepointsto.Rememberthatobjectsarenotcopiedbyvalue,butonlybyreference.So,thelookupisonlyatwo-stepprocessasopposedtofour(inthepreviousexample)orthree(inthefirstexample).

Simplycopyingtheprototypeismoreefficient,butithasasideeffectbecause,alltheprototypesofthechildrenandparentspointtothesameobject,whenachildmodifiestheprototype,theparentsgetthechangesandsodothesiblings.

Lookatthefollowingline:

Triangle.prototype.name = 'Triangle';

Itchangesthenameproperty,soiteffectivelychangesShape.prototype.nametoo.IfyoucreateaninstanceusingnewShape(),itsnamepropertysays"Triangle":

>vars=newShape();>s.name;"Triangle"

Thismethodismoreefficient,butmaynotsuitallyourusecases.

Page 281: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Atemporaryconstructor-newF()

Asolutiontothepreviouslyoutlinedproblem,whereallprototypespointtothesameobjectandtheparentsgetchildren'sproperties,istouseanintermediarytobreakthechain.Theintermediaryisintheformofatemporaryconstructorfunction.CreatinganemptyfunctionF()andsettingitsprototypetotheprototypeoftheparentconstructorallowsyoutocallnewF()andcreateobjectsthathavenopropertiesoftheirown,butinheriteverythingfromtheparent'sprototype.

Let'stakealookatthemodifiedcode:

functionShape(){}//augmentprototypeShape.prototype.name='Shape';

Shape.prototype.toString = function () {returnthis.name;};

functionTwoDShape(){}//takecareofinheritancevarF=function(){};F.prototype=Shape.prototype;TwoDShape.prototype=newF();TwoDShape.prototype.constructor=TwoDShape;//augmentprototypeTwoDShape.prototype.name='2Dshape';

functionTriangle(side,height){this.side=side;this.height=height;}

//takecareofinheritancevarF=function(){};F.prototype=TwoDShape.prototype;Triangle.prototype=newF();Triangle.prototype.constructor=Triangle;//augmentprototypeTriangle.prototype.name='Triangle';

Triangle.prototype.getArea = function () {returnthis.side*this.height/2;};

Creatingmytriangleandtestingthemethods:

>varmy=newTriangle(5,10);>my.getArea();25

>my.toString();"Triangle"

Page 282: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingthisapproach,theprototypechainstaysinplace:

>my.__proto__===Triangle.prototype;true>my.__proto__.constructor===Triangle;true>my.__proto__.__proto__===TwoDShape.prototype;true>my.__proto__.__proto__.__proto__.constructor===Shape;true

Also,theparents'propertiesarenotoverwrittenbythechildren:

>vars=newShape();>s.name;"Shape">"Iama"+newTwoDShape();//callingtoString()"Iama2Dshape"

Atthesametime,thisapproachsupportstheidea thatonlypropertiesandmethodsaddedtotheprototypeshouldbeinheritedandownpropertiesshouldnot.Therationalebehindthisisthatownpropertiesarelikelytobetoospecifictobereusable.

Page 283: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Uber - access to the parent from a childobjectClassicalOOlanguagesusuallyhaveaspecialsyntaxthatgivesyouaccesstotheparentclass,alsoreferredtothesuperclass.Thiscouldbeconvenientwhenachildwantstohaveamethodthatdoeseverythingtheparent'smethoddoes,plussomethinginadditiontoit.Insuchcases,thechildcallstheparent'smethodwiththesamenameandworkswiththeresult.

InJavaScript,thereisnosuchspecialsyntax,but it'strivialtoachievethesamefunctionality.Let'srewritethelastexample,andwhiletakingcareofinheritance,alsocreateanuberpropertythatpointstotheparent'sprototypeobject:

functionShape(){}//augmentprototypeShape.prototype.name='Shape';Shape.prototype.toString=function(){varconst=this.constructor;returnconst.uber?this.const.uber.toString()+','+this.name:this.name;

};

functionTwoDShape(){}//takecareofinheritancevarF=function(){};F.prototype=Shape.prototype;TwoDShape.prototype=newF();TwoDShape.prototype.constructor=TwoDShape;TwoDShape.uber=Shape.prototype;//augmentprototypeTwoDShape.prototype.name='2Dshape';

functionTriangle(side,height){this.side=side;this.height=height;}

//takecareofinheritancevarF=function(){};F.prototype=TwoDShape.prototype;Triangle.prototype=newF();Triangle.prototype.constructor=Triangle;Triangle.uber=TwoDShape.prototype;//augmentprototypeTriangle.prototype.name='Triangle';

Triangle.prototype.getArea = function () {returnthis.side*this.height/2;};

Page 284: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thenewthingshereare:

Anewuberpropertypointstotheparent'sprototypeTheupdatedtoString()method

Previously,toString()onlyreturnedthis.name.Now,inadditiontothis,thereisachecktoseewhetherthis.constructor.uberexistsand,ifitdoes,callitstoString()first.Thethis.constructoristhefunctionitself,andthis.constructor.uberpointstotheparent'sprototype.TheresultisthatwhenyoucalltoString()foraTriangleinstance,alltoString()methodsuptheprototypechainarecalled:

>varmy=newTriangle(5,10);>my.toString();"Shape,2Dshape,Triangle"

Thenameoftheuberpropertycould'vebeensuperclass,butthiswouldsuggestthatJavaScripthasclasses.Ideally,itcould'vebeensuper(asinJava),butsuperisareservedwordinJavaScript.TheGermanwordubersuggestedbyDouglasCrockfordmeansmoreorlessthesameassuper,andyouhavetoadmit,itsoundsubercool.

Page 285: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Isolating the inheritance part into a functionLet's move the code that takes care of all the inheritance details from the last example into areusableextend()function:

functionextend(Child,Parent){varF=function(){};F.prototype=Parent.prototype;Child.prototype=newF();Child.prototype.constructor=Child;Child.uber=Parent.prototype;}

Usingthisfunction(oryourowncustomversionofit)helpsyoukeepyourcodecleanwithregardtotherepetitiveinheritance-relatedtasks.Thisway,youcaninheritbysimplyusingthefollowingtwolinesofcode:

extend(TwoDShape, Shape);extend(Triangle,TwoDShape);

Let'sseeacompleteexample:

//inheritancehelperfunctionextend(Child,Parent){varF=function(){};F.prototype=Parent.prototype;Child.prototype=newF();Child.prototype.constructor=Child;Child.uber=Parent.prototype;}

//define->augmentfunctionShape(){}Shape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.constructor.uber?this.constructor.uber.toString()+','+this.name:this.name;};

//define->inherit->augmentfunctionTwoDShape(){}extend(TwoDShape,Shape);TwoDShape.prototype.name='2Dshape';

//definefunctionTriangle(side,height){this.side=side;this.height=height;}

Page 286: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

//inheritextend(Triangle,TwoDShape);//augmentTriangle.prototype.name='Triangle';Triangle.prototype.getArea=function(){returnthis.side*this.height/2;};

Letstestthefollowingcode:

>newTriangle().toString();"Shape,2Dshape,Triangle"

Page 287: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Copying propertiesNow, let's try a slightly different approach. Since inheritance is all about reusing code, can yousimplycopythepropertiesyoulikefromoneobjecttoanother?Orfromaparenttoachild?Keepingthesameinterfaceastheprecedingextend()function,youcancreateaextend2()function,whichtakestwoconstructorfunctionsandcopiesallthepropertiesfromtheparent'sprototypetothechild'sprototype.Thiswill,ofcourse,carryovermethodstoo,asmethodsarejustpropertiesthathappentobefunctions:

functionextend2(Child,Parent){varp=Parent.prototype;varc=Child.prototype;for(variinp){c[i]=p[i];}c.uber=p;}

Asyoucansee,asimpleloopthroughthepropertiesisallittakes.Aswiththepreviousexample,youcansetanuberpropertyifyouwanttohavehandyaccesstoparent'smethodsfromthechild.Unlikethepreviousexamplethough,it'snotnecessarytoresetChild.prototype.constructorbecausehere,thechildprototypeisaugmented,notoverwrittencompletely.So,theconstructorpropertypointstotheinitialvalue.

Thismethodisalittleinefficientcomparedtothepreviousmethodbecausepropertiesofthechildprototypearebeingduplicatedinsteadofsimplybeinglookedupviatheprototypechainduringexecution.Bearinmindthatthisisonlytrueforpropertiescontainingprimitivetypes.Allobjects(includingfunctionsandarrays)arenotduplicated,becausethesearepassedbyreferenceonly.

Let'sseeanexampleofusingtwoconstructorfunctions,Shape()andTwoDShape().TheShape()function'sprototypeobjectcontainsaprimitiveproperty,name,andanon-primitiveone,thetoString()method:

varShape=function(){};var TwoDShape = function () {};

Shape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.uber?this.uber.toString()+','+this.name:this.name;};

Ifyouinheritwithextend(),neithertheobjectscreatedwithTwoDShape()noritsprototypegetanownnameproperty,buttheyhaveaccesstotheonetheyinherit:

>extend(TwoDShape,Shape);

Page 288: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>vartd=newTwoDShape();>td.name;"Shape">TwoDShape.prototype.name;"Shape">td.__proto__.name;"Shape">td.hasOwnProperty('name');false>td.__proto__.hasOwnProperty('name');false

However,ifyouinheritwithextend2(),theprototypeofTwoDShape()getsitsowncopyofthenameproperty.ItalsogetsitsowncopyoftoString(),butit'sareferenceonly,sothefunctionwillnotberecreatedasecondtime:

>extend2(TwoDShape,Shape);>vartd=newTwoDShape();>td.__proto__.hasOwnProperty('name');true>td.__proto__.hasOwnProperty('toString');true>td.__proto__.toString===Shape.prototype.toString;true

Asyoucansee,thetwotoString()methodsarethesamefunctionobject.Thisisgoodbecauseitmeansthatnounnecessaryduplicatesofthemethodsarecreated.

So,youcansaythatextend2()islessefficientthanextend()becauseitrecreatesthepropertiesoftheprototype.However,thisisnotsobadbecauseonlytheprimitivedatatypesareduplicated.Additionally,thisisbeneficialduringtheprototypechainlookupsastherearefewerchainlinkstofollowbeforefindingtheproperty.

Takealookattheuberpropertyagain.Thistime,forachange,it'ssetontheParentobject'sprototypep,notontheParentconstructor.ThisiswhytoString()uses itasthis.uberasopposedtothis.constructor.uber.Thisisjustanillustrationthatyou canshapeyourfavoriteinheritancepatterninanywayyouseefit.Let'stestitout:

>td.toString();"Shape,Shape"

TwoDShapedidn'tredefinethenameproperty,hencetherepetition.Itcandothatatanytime,and(theprototypechainbeinglive)alltheinstancesseetheupdate:

>TwoDShape.prototype.name="2Dshape";>td.toString();"Shape,2Dshape"

Page 289: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Heads-up when copying by referenceThe fact that objects (including functions and arrays) are copied by reference could sometimesleadtoresultsyoudon'texpect.

Let'screatetwoconstructorfunctionsandaddpropertiestotheprototypeofthefirstone:

>functionPapa(){}>functionWee(){}>Papa.prototype.name='Bear';>Papa.prototype.owns=["porridge","chair","bed"];

Now,let'shaveWeeinheritfromPapa(eitherextend()orextend2()willdo):

>extend2(Wee,Papa);

Usingextend2(),theWeefunction'sprototypeinheritedthepropertiesofPapa.prototypeasitsown:

>Wee.prototype.hasOwnProperty('name');true>Wee.prototype.hasOwnProperty('owns');

true

Thenamepropertyisprimitive,soanewcopyofitiscreated.Theownspropertyisanarrayobject,soit'scopiedbyreference:

>Wee.prototype.owns;["porridge","chair","bed"]>Wee.prototype.owns===Papa.prototype.owns;true

ChangingtheWeefunction'scopyofnamedoesn'taffectPapa:

>Wee.prototype.name+=',LittleBear';"Bear,LittleBear">Papa.prototype.name;"Bear"

ChangingtheWeefunction'sownsproperty,however,affectsPapa,becausebothpropertiespointtothesamearrayinmemory:

>Wee.prototype.owns.pop();"bed">Papa.prototype.owns;["porridge","chair"]

It'sadifferentstorywhenyoucompletelyoverwritetheWeefunction'scopyofownswithanotherobject(asopposedtomodifyingtheexistingone).Inthiscase,Papa.ownskeepspointingtothe

Page 290: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

oldobject,whileWee.ownspointstoanewone:

>Wee.prototype.owns=["emptybowl","brokenchair"];>Papa.prototype.owns.push('bed');>Papa.prototype.owns;["porridge","chair","bed"]

Thinkofanobjectassomethingthatiscreatedandstoredinaphysicallocationinmemory.Variablesandpropertiesmerelypointtothislocation,sowhenyouassignabrandnewobjecttoWee.prototype.owns,youessentiallysay-Hey,forgetaboutthisotheroldobject,moveyourpointertothisnewoneinstead.

Thefollowingdiagramillustrateswhathappensifyouimaginethememorybeingaheapofobjects(likeawallofbricks)andyoupointto(referto)someoftheseobjects:

Anewobjectiscreated,andApointstoit.AnewvariableBiscreatedandmadeequaltoA,meaningitnowpointstothesameplaceAispointingto.ApropertycolorischangedusingtheBhandle(pointer).Thebrickisnowwhite.AcheckforA.color==="white"wouldbetrue.Anewobjectiscreated,andtheBvariable/pointerisrecycledtopointtothatnewobject.AandBarenowpointingtodifferentpartsofthememorypile.Theyhavenothingincommonandchangestooneofthemdon'taffecttheother:

Page 291: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare
Page 292: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Ifyouwanttoaddresstheproblemthatobjectsarecopiedbyreference,consideradeepcopy,describedlaterinthechapter.

Page 293: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Objects inherit from objectsAll the examples so far in this chapter assume that you create your objects with constructorfunctions,andyouwantobjectscreatedwithoneconstructortoinheritpropertiesthatcomefromanotherconstructor.However,youcanalsocreateobjectswithoutthehelpofaconstructorfunction,justusingtheobjectliteral,andthisis,infact,lesstyping.So,howaboutinheritingthose?

InJavaorPHP,youdefineclassesandhavetheminheritfromotherclasses.That'swhyyou'llseethetermclassical,becausetheOOfunctionalitycomesfromtheuseofclasses.InJavaScript,therearenoclasses,soprogrammersthatcomefromaclassicalbackgroundresorttoconstructorfunctions,becauseconstructorsaretheclosesttowhattheyareusedto.In addition,JavaScriptprovidesthenewoperator,whichcanfurthersuggestthatJavaScriptislikeJava.Thetruthisthat,intheend,itallcomesdowntoobjects.Thefirst exampleinthischapterusedthissyntax:

Child.prototype=newParent();

Here,theChildconstructor(orclass,ifyouwill)inheritsfromParent.However,thisisdonebycreatinganobjectusingnewParent()andinheritingfromit.That'swhythisisalsoreferredtoasapseudo-classicalinheritancepattern,becauseitresemblesclassicalinheritance,althoughitisn't(noclassesareinvolved).

So,whynotgetridofthemiddleman(theconstructor/class)andjusthave objectsinheritfromobjects?Inextend2(),thepropertiesoftheparentprototypeobjectwerecopiedaspropertiesofthechildprototypeobject.Thetwoprototypesare,inessence,justobjects.Forgettingaboutprototypesandconstructorfunctions,youcansimplytakeanobjectandcopyallofitspropertiesintoanotherobject.

You already know that objects can start as a blank canvas without any own properties, using varo = {};, and then get properties later. However, instead of starting fresh, you can start bycopying all of the properties of an existing object. Here's a function that does exactly this: it takesanobjectandreturnsanewcopyofit:

functionextendCopy(p){varc={};for(variinp){c[i]=p[i];}c.uber=p;returnc;}

Simplycopyingallthepropertiesisastraightforwardpattern,andit'swidelyused.Let'sseethisfunctioninaction.Youstartbyhavingabaseobject:

Page 294: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varshape={name:'Shape',toString:function(){returnthis.name;}};

Inordertocreateanewobjectthatbuildsupontheoldone,youcancalltheextendCopy()function,whichreturnsanewobject.Then,youcanaugmentthenewobjectwithadditionalfunctionality:

vartwoDee=extendCopy(shape);twoDee.name='2Dshape';twoDee.toString=function(){returnthis.uber.toString()+','+this.name;

};

Hereisatriangleobjectthatinheritsthe2Dshapeobject:

vartriangle=extendCopy(twoDee);triangle.name='Triangle';triangle.getArea=function(){returnthis.side*this.height/2;};

Usingthetriangle,forexample:

>triangle.side=5;>triangle.height=10;>triangle.getArea();25>triangle.toString();"Shape,2Dshape,Triangle"

Apossible drawback of this method is the somewhat verbose way of initializing the newtriangleobject,where youmanuallysetvaluesforsideandheight,asopposedtopassingthemasvaluestoaconstructor.However,thisiseasilyresolvedbyhavingafunction,forexample,calledinit()(or__construct()ifyoucomefromPHP)thatactsasaconstructorandacceptsinitializationparameters.Alternatively,haveextendCopy()accepttwoparameters,anobjecttoinheritfromandanotherobjectliteralofpropertiestoaddtothe copybeforeit'sreturned.Inotherwords,justmergetwoobjects.

Page 295: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Deep copyThe extendCopy() function discussed previously creates what is called a shallow copy of anobject, just like extend2() before that. The opposite of a shallow copy would be, naturally, adeep copy. As discussed previously (in the Heads-up when copying by reference section of thischapter),whenyoucopy objects,youonlycopypointerstothelocationinmemorywheretheobjectisstored.Thisiswhathappensinashallowcopy.Ifyoumodifyanobjectinthecopy,youalsomodifytheoriginal. Thedeepcopyavoidsthisproblem.

Thedeepcopyisimplementedinthesamewayastheshallowcopy-youloopthroughthepropertiesandcopythemonebyone.However,whenyouencounterapropertythatpointstoanobject,youcallthedeepcopyfunctionagain:

functiondeepCopy(p,c){c=c||{};for(variinp){if(p.hasOwnProperty(i)){

if (typeof p[i] === 'object') {c[i]=Array.isArray(p[i])?[]:{};deepCopy(p[i],c[i]);}else{c[i]=p[i];}}}returnc;}

Let'screateanobjectthathasarraysandasubobjectasproperties:

var parent = {numbers:[1,2,3],letters:['a','b','c'],obj:{prop:1},bool:true};

Let'stestthisbycreatingadeepcopyandashallowcopy.Unliketheshallowcopy,whenyouupdatethenumberspropertyofadeepcopy,theoriginalisnotaffected:

>varmydeep=deepCopy(parent);>varmyshallow=extendCopy(parent);

>mydeep.numbers.push(4,5,6);6>mydeep.numbers;[1,2,3,4,5,6]>parent.numbers;

Page 296: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

[1,2,3]>myshallow.numbers.push(10);4>myshallow.numbers;[1,2,3,10]>parent.numbers;[1,2,3,10]>mydeep.numbers;[1,2,3,4,5,6]

TwosidenotesaboutthedeepCopy()function:

Filteringoutnon-ownpropertieswithhasOwnProperty()isalwaysagoodideatomakesureyoudon'tcarryoversomeone'sadditionstothecoreprototypes.Array.isArray()existssinceES5becauseit'ssurprisinglyhardotherwisetotellrealarraysfromobjects.Thebestcross-browsersolution(ifyouneedtodefineisArray()inES3browsers)looksalittlehacky,butitworks:

if(Array.isArray!=="function"){Array.isArray=function(candidate){returnObject.prototype.toString.call(candidate)==='[objectArray]';};}

Page 297: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Using object() methodBased on the idea that objects inherit from objects, Douglas Crockford advocates the use of anobject()functionthatacceptsanobjectandreturnsanewonethathastheparentasaprototype:

functionobject(o){functionF(){}F.prototype=o;returnnewF();}

Ifyouneedaccesstoanuberproperty,youcanmodifytheobject()functionasfollows:

functionobject(o){varn;functionF(){}F.prototype=o;n=newF();n.uber=o;returnn;}

UsingthisfunctionisthesameasusingextendCopy(),youtakeanobjectsuchastwoDee,createanewobjectfromit,andthenproceedtoaugmentingthenewobject:

vartriangle=object(twoDee);triangle.name='Triangle';triangle.getArea=function(){returnthis.side*this.height/2;};

Thenewtrianglestillbehavesthesameway:

>triangle.toString();"Shape,2Dshape,Triangle"

Thispatternisalsoreferredtoasprototypalinheritance,becauseyouuseaparentobjectastheprototypeofachildobject.It'salsoadoptedandbuiltuponinES5andcalledObject.create().Hereisanexample:

>varsquare=Object.create(triangle);

Page 298: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Using a mix of prototypal inheritance andcopyingpropertiesWhenyouuseinheritance,youwillmostlikelywanttotakeanalreadyexistingfunctionalityandthenbuilduponit.Thismeanscreatinganewobjectbyinheritingfroman existingobjectandthenaddingadditionalmethodsandproperties.Youcandothiswithonefunctioncallusingacombinationofthelasttwoapproachesjustdiscussed.

Youcan:

Useprototypalinheritancetouseanexistingobjectasaprototypeof anewoneCopyallthepropertiesofanotherobjectintothenewlycreatedone:

functionobjectPlus(o,stuff){var n;

functionF(){}F.prototype=o;n=newF();n.uber=o;for(variinstuff){n[i]=stuff[i];}returnn;}

Thisfunctiontakesanobjectotoinheritfromandanotherobjectstuffthathastheadditionalmethodsandpropertiesthataretobecopied.Let'sseethisinaction.

Startwiththebaseshapeobject:

varshape={name:'Shape',toString:function(){returnthis.name;}};

Createa2Dobjectbyinheritingshapeandaddingmoreproperties.Theadditionalpropertiesaresimplycreatedwithanobjectliteral:

vartwoDee=objectPlus(shape,{name:'2Dshape',

toString: function () {returnthis.uber.toString()+','+this.name;}});

Page 299: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Now,let'screateatriangleobjectthatinheritsfrom2Dandaddsmoreproperties:

vartriangle=objectPlus(twoDee,{name:'Triangle',getArea:function(){returnthis.side*this.height/2;},side:0,height:0});

Youcantesthowitallworksbycreatingaconcretetrianglemywithdefinedsideandheight:

varmy=objectPlus(triangle,{side:4,height:4});>my.getArea();8>my.toString();

"Shape, 2D shape, Triangle, Triangle"

Thedifferencehere,whenexecutingtoString(),isthattheTrianglenameisrepeatedtwice.That'sbecausetheconcreteinstancewascreatedbyinheritingtriangle,sotherewasonemorelevelofinheritance.Youcouldgivethenewinstanceaname:

>objectPlus(triangle,{side:4,height:4,name:'My4x4'}).toString();"Shape,2Dshape,Triangle,My4x4"

ThisobjectPlus()isevenclosertoES5'sObject.create();onlytheES5onetakestheadditionalproperties(thesecondargument)usingsomethingcalledpropertydescriptors(discussedinAppendixC,Built-InObjects).

Page 300: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Multiple inheritanceMultiple inheritance is where a child inherits frommore than one parent. Some OO languagessupportmultipleinheritanceoutoftheboxandsomedon't.Youcanarguebothways,thatmultipleinheritanceisconvenientorthatit'sunnecessary,complicatesapplicationdesign,andit'sbettertouseaninheritancechaininstead.Leavingthediscussionofmultipleinheritance'sprosandconsforthelong,coldwinternights,let'sseehowyoucandoitinpracticeinJavaScript.

Theimplementationcanbeassimpleastakingtheideaofinheritancebycopyingpropertiesandexpandingitsothatittakesanunlimitednumberofinputobjectstoinheritfrom.

Let'screateamulti()functionthatacceptsanynumberofinputobjects.Youcanwraptheloopthatcopiespropertiesinanotherloopthatgoesthroughalltheobjectspassedasargumentstothefunction:

functionmulti(){varn={},stuff,j=0,len=arguments.length;for(j=0;j<len;j++){stuff=arguments[j];for(variinstuff){if(stuff.hasOwnProperty(i)){n[i]=stuff[i];

}}}returnn;}

Let'stestthisbycreatingthreeobjects-shape,twoDee,andathird,unnamedobject.Then,creatingatriangleobjectmeanscallingmulti()andpassingallthreeobjects:

varshape={name: 'Shape',

toString:function(){returnthis.name;}};

vartwoDee={name:'2Dshape',dimensions:2};

vartriangle=multi(shape,twoDee,{name:'Triangle',getArea:function(){returnthis.side*this.height/2;},side:5,

Page 301: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

height:10});

Doesthiswork?Let'ssee.ThegetArea()methodshouldbeanownproperty,dimensionsshouldcomefromtwoDee,andtoString()shouldcomefromshape:

>triangle.getArea();25>triangle.dimensions;2>triangle.toString();"Triangle"

Bearinmindthatmulti()loopsthroughtheinputobjectsintheordertheyappearandifithappensthattwoofthemhavethesameproperty, thelastonewins.

Page 302: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Mixins

Youmightcomeacrossthetermmixin.Thinkofamixinasanobjectthatprovidessomeusefulfunctionalitybutisnotmeanttobeinheritedandextendedbysubobjects.Theapproachtomultipleinheritanceoutlinedpreviouslycanbeconsideredanimplementationofthemixinsidea.Whenyoucreateanewobject,youcanpickandchooseanyotherobjectstomixintoyournewobject.Bypassingthemalltomulti(),yougetalltheirfunctionalitywithoutmakingthempartoftheinheritancetree.

Page 303: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Parasitic inheritanceIf you like the fact that you can have all kinds of different ways to implement inheritance inJavaScriptandyou'rehungryformore,here'sanotherone.Thispattern,courtesyofDouglasCrockford,iscalledparasiticinheritance.It'saboutafunctionthatcreatesobjectsbytakingallthefunctionalityfromanotherobjectintoanewone,augmentingthenewobject,andreturningit,pretendingthatithasdoneallthework.

Here'sanordinaryobject,definedwithanobject literal,andunawareofthefactthatit'ssoongoingtofallvictimtoparasitism:

vartwoD={name:'2Dshape',dimensions:2};

A function that creates triangle objects could:

UsethetwoDobjectasaprototypeofanobjectcalledthat(similartothisforconvenience).Thiscanbedoneinanywayyousawpreviously,forexample,usingtheobject()functionorcopyingalltheproperties.Augmentthatwithmoreproperties.Returnthat:

functiontriangle(s,h){varthat=object(twoD);that.name='Triangle';

that.getArea = function () {returnthis.side*this.height/2;};that.side=s;that.height=h;returnthat;}

Becausetriangle()isanormalfunction,notaconstructor,itdoesn'trequirethenewoperator.However,becauseitreturnsanobject,callingitwithnewbymistakeworkstoo:

>vart=triangle(5,10);>t.dimensions;2>vart2=newtriangle(5,5);>t2.getArea();12.5

Notethatthatisjustaname,itdoesn'thaveaspecialmeaning,thewaythisdoes.

Page 304: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Borrowing a constructorOne more way of implementing inheritance (the last one in the chapter, I promise) has to do againwithconstructorfunctionsandnottheobjectsdirectly.Inthispattern,theconstructorofthechildcallstheconstructoroftheparentusingeitherthe call()orapply()method.Thiscanbecalledstealingaconstructororinheritancebyborrowingaconstructorifyouwanttobemoresubtleaboutit.

Thecall()andapply()methodswerediscussedinChapter4,Objects, buthere'sarefresher;theyallowyoutocallafunctionandpassanobjectthatthefunctionshouldbindtoitsthisvalue.Soforinheritancepurposes,thechildconstructorcallstheparent'sconstructorandbindsthechild'snewlycreatedthisobjectastheparent'sthis.

Let'shavethisparentconstructorShape():

functionShape(id){this.id=id;}Shape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.name;};

Now,let'sdefineTriangle(),whichusesapply()tocalltheShape()constructor,passingthis(aninstancecreatedwithnewTriangle())andanyadditionalarguments:

functionTriangle(){Shape.apply(this,arguments);}Triangle.prototype.name='Triangle';

NotethatbothTriangle()andShape()haveaddedsomeextrapropertiestotheirprototypes.

Now,let'stestthisbycreatinganewtriangleobject:

>vart=newTriangle(101);>t.name;"Triangle"

Thenewtriangleobjectinheritstheidpropertyfromtheparent,butitdoesn'tinheritanythingaddedtotheparent'sprototype:

>t.id;101>t.toString();"[objectObject]"

Page 305: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ThetrianglefailedtogettheShapefunction'sprototypepropertiesbecausetherewasneveranewShape()instancecreated,sotheprototypewasneverused.However,yousawhowtodothisatthebeginningofthischapter.YoucanredefineTriangleasfollows:

functionTriangle(){Shape.apply(this,arguments);}Triangle.prototype=newShape();Triangle.prototype.name='Triangle';

Inthisinheritancepattern,theparent'sownpropertiesarerecreatedasthechild'sownproperties.Ifachildinheritsanarrayorotherobject,it'sacompletelynewvalue(notareference),andmodifyingitwon'taffecttheparent.

Thedrawbackisthatthe parent'sconstructorgetscalledtwice-oncewithapply()toinheritownpropertiesandoncewithnewtoinherittheprototype.Infact,theownpropertiesoftheparentareinheritedtwice.Let'stakethissimplifiedscenario:

functionShape(id){this.id=id;}functionTriangle(){Shape.apply(this,arguments);}Triangle.prototype=newShape(101);

Here,wewillcreateanewinstance:

>vart=newTriangle(202);>t.id;202

There'sanownpropertyid,butthere'salsoonethatcomesdowntheprototypechain,readytoshinethrough:

>t.__proto__.id;101>deletet.id;true

>t.id;101

Page 306: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Borrowingaconstructorandcopyingitsprototype

Theproblemofthedoubleworkperformedbycallingtheconstructortwicecaneasilybecorrected.Youcancallapply()ontheparentconstructortogetallownpropertiesandthencopytheprototype'spropertiesusingasimpleiteration(orextend2()asdiscussedpreviously):

function Shape(id) {this.id=id;}Shape.prototype.name='Shape';Shape.prototype.toString=function(){returnthis.name;};

functionTriangle(){Shape.apply(this,arguments);}extend2(Triangle,Shape);Triangle.prototype.name='Triangle';

Letstestthefollowingcode:

>vart=newTriangle(101);>t.toString();"Triangle">t.id;101

Nodoubleinheritance:

>typeoft.__proto__.id;"undefined"

Theextend2()methodalsogivesaccesstouberifneeded:

>t.uber.name;"Shape"

Page 307: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Case study - drawing shapesLet's finish off this chapter with a more practical example of using inheritance. The task is to beabletocalculatetheareaandtheperimeterofdifferentshapes,aswellastodrawthem,whilereusingasmuchcodeaspossible.

Page 308: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Analysis

Let'shaveoneShapeconstructorthatcontainsallthecommonparts.Fromthere,let'shaveTriangle,Rectangle,andSquareconstructors,allinheritingfromShape.Asquareisreallyarectanglewiththesamelengthsides,solet'sreuseRectanglewhenbuildingSquare.

Inordertodefineashape,you'llneedpointswithxandycoordinates.Agenericshapecanhaveanynumberofpoints.Atriangleisdefinedwiththreepoints,arectangle(tokeepitsimpler)withonepointandthelengthsofthesides.Theperimeterofanyshapeisthesumofitsside'slengths.Calculatingtheareaisshapespecificandwillbeimplementedbyeachshape.

ThecommonfunctionalityinShapewouldbe:

Adraw()methodthatcandrawanyshapegiventhepointsAgetParameter()methodApropertythatcontainsanarrayofpointsOthermethodsandpropertiesasneeded

Forthedrawingpart,let'susea<canvas>tag.It'snotsupportedinearlyIEs,buthey,thisisjustanexercise.

Let'shavetwootherhelperconstructors-PointandLine.Pointwillhelpwhendefiningshapes.Linewillmakecalculationseasier,asitcangivethelengthofthelineconnectinganytwogivenpoints.

Youcanplaywithaworkingexampleathttp://www.phpied.com/files/canvas/.Justopenyourconsoleandstartcreatingnewshapesasyou'llseeinamoment.

Page 309: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Implementation

Let'sstartbyaddingacanvastagtoablankHTMLpage:

<canvasheight="600"width="800"id="canvas"/>

Then,puttheJavaScriptcodeinside<script>tags:

<script>// ... code goes here

</script>

Now,let'stakealookatwhat'sintheJavaScriptpart.FirstisthehelperPointconstructor.Itjustcan'tgetanysimplerthanthefollowing:

functionPoint(x,y){this.x=x;this.y=y;}

Bear in mind that the coordinates of the points on the canvas start from x=0, y=0, which is the topleft. The bottom right will be x = 800, y = 600:

NextcomestheLineconstructor.Ittakestwopointsandcalculatesthelengthofthelinebetween

them,usingthePythagoreantheorema2+b2=c2(imaginearight-angledtrianglewherethehypotenuseconnectsthetwogivenpoints):

function Line(p1, p2) {

Page 310: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

this.p1=p1;this.p2=p2;this.length=Math.sqrt(Math.pow(p1.x-p2.x,2)+Math.pow(p1.y-p2.y,2));}

NextcomestheShapeconstructor.Theshapeswillhavetheirpoints(and thelinesthatconnectthem)asownproperties.Theconstructoralsoinvokesaninitializationmethod,init(),thatwillbedefinedintheprototype:

functionShape(){this.points=[];this.lines=[];this.init();}

Now,thebigpart-themethodsofShape.prototype.Let'sdefineallthesemethodsusingtheobjectliteralnotation.Refertothecommentsforguidelinesastowhateachmethoddoes:

Shape.prototype={//resetpointertoconstructorconstructor:Shape,

// initialization, sets this.context to point//tothecontextifthecanvasobjectinit:function(){if(this.context===undefined){varcanvas=document.getElementById('canvas');Shape.prototype.context=canvas.getContext('2d');}},

//methodthatdrawsashapebyloopingthroughthis.pointsdraw:function(){vari,ctx=this.context;ctx.strokeStyle=this.getColor();ctx.beginPath();ctx.moveTo(this.points[0].x,this.points[0].y);for(i=1;i<this.points.length;i++){ctx.lineTo(this.points[i].x,this.points[i].y);}ctx.closePath();ctx.stroke();},

//methodthatgeneratesarandomcolorgetColor:function(){vari,rgb=[];

for (i = 0; i< 3; i++) {rgb[i]=Math.round(255*Math.random());

Page 311: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}return'rgb('+rgb.join(',')+')';},

//methodthatloopsthroughthepointsarray,//createsLineinstancesandaddsthemtothis.linesgetLines:function(){if(this.lines.length>0){returnthis.lines;}vari,lines=[];for(i=0;i<this.points.length;i++){lines[i]=newLine(this.points[i],this.points[i+1]||this.points[0]);}this.lines=lines;returnlines;},

//shellmethod,tobeimplementedbychildrengetArea:function(){},

//sumsthelengthsofalllinesgetPerimeter:function(){vari,perim=0,lines=this.getLines();for(i=0;i<lines.length;i++){perim+=lines[i].length;}returnperim;}};

Now,thechildrenconstructorfunctions.Trianglecomesfirst:

functionTriangle(a,b,c){this.points=[a,b,c];this.getArea=function(){varp=this.getPerimeter(),s=p/2;returnMath.sqrt(s*(s-this.lines[0].length)*(s-this.lines[1].length)*(s-this.lines[2].length));};}

TheTriangleconstructortakesthreepointobjectsandassignsthemtothis.points(itsowncollectionofpoints).Then,itimplementsthegetArea()method,usingHeron'sformula:

Area=s(s-a)(s-b)(s-c)

sisthesemi-perimeter(perimeterdividedbytwo).

Page 312: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

NextcomestheRectangleconstructor.Itreceivesonepoint(theupper-leftpoint)andthelengthsofthetwosides.Then,itpopulatesitspointsarraystartingfromthatonepoint:

functionRectangle(p,side_a,side_b){this.points=[p,newPoint(p.x+side_a,p.y),//toprightnewPoint(p.x+side_a,p.y+side_b),//bottomrightnewPoint(p.x,p.y+side_b)//bottomleft];

this.getArea = function () {returnside_a*side_b;};}

ThelastchildconstructorisSquare.Asquareisaspecialcaseofarectangle,soitmakessensetoreuseRectangle.Theeasiestthingtodohereistoborrowtheconstructor:

functionSquare(p,side){Rectangle.call(this,p,side,side);

}

Nowthatallconstructorsaredone,let'stakecareofinheritance.Anypseudo-classicalpattern(onethatworkswithconstructorsasopposedtoobjects)willdo.Let'stryusingamodifiedandsimplifiedversionoftheprototype-chainingpattern(thefirstmethoddescribedinthischapter).Thispatterncallsforcreatinganewinstanceoftheparentandsettingitasthechild'sprototype.Inthiscase,it'snotnecessarytohaveanewinstanceforeachchild-theycanallshareit:

(function () {vars=newShape();Triangle.prototype=s;Rectangle.prototype=s;Square.prototype=s;})();

Page 313: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Testing

Let'stestthisbydrawingshapes.First,definethreepointsforatriangle:

>var p1 = new Point(100, 100);>varp2=newPoint(300,100);>varp3=newPoint(200,0);

NowyoucancreateatrianglebypassingthethreepointstotheTriangleconstructor:

>vart=newTriangle(p1,p2,p3);

Youcancallthemethodstodrawthetriangleonthecanvasandgetitsareaandperimeter:

>t.draw();>t.getPerimeter();482.842712474619>t.getArea();10000.000000000002

Nowlet'splaywitharectangleinstance:

>varr=newRectangle(newPoint(200,200),50,100);>r.draw();>r.getArea();5000>r.getPerimeter();300

Andfinally,let'splaywithasquare:

>vars=newSquare(newPoint(130,130),50);>s.draw();>s.getArea();2500>s.getPerimeter();200

It'sfuntodrawtheseshapes.Youcanalsobeaslazyasthefollowingexample,whichdrawsanothersquare,reusingatriangle'spoint:

> new Square(p1, 200).draw();

Theresultofthetestswillbesomethinglikethefollowing:

Page 314: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare
Page 315: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ExercisesLets do the following exercise:

1. Implementmultipleinheritancebutwithaprototypalinheritancepattern,notpropertycopying.Hereisan example:

varmy=objectMulti(obj,another_obj,a_third,{additional:"properties"});

The additional property should be an own property; all the rest should be mixed into theprototype.

2. Usethecanvasexampletopractice.Tryoutdifferentthings.Herearesomeexamples:Drawafewtriangles,squares,andrectangles.Addconstructorsformoreshapes,suchasTrapezoid,Rhombus,Kite,andPentagon.Ifyouwanttolearnmoreaboutthecanvastag,createaCircleconstructortoo.Itwillneedtooverwritethedraw()methodoftheparent.Canyouthinkofanotherwaytoapproachtheproblemanduseanothertypeofinheritance?Pickoneofthemethodsthatusesuberasawayforachildtoaccessitsparent.Addfunctionalitywheretheparentscankeeptrackofwhotheirchildrenare,perhapsusingapropertythatcontainsachildrenarray?

Page 316: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, you learned quite a few ways (patterns) of implementing inheritance, and thefollowingtablesummarizesthem.Thedifferenttypescanroughlybedividedintothefollowing:

PatternsthatworkwithconstructorsPatternsthatworkwithobjects

Youcanalsoclassifythepatternsbasedonwhetherthey:

UsetheprototypeCopypropertiesDoboth(copypropertiesoftheprototype):

# Name Example Classification Notes

1

Prototypechaining

(pseudo-classical)

Child.prototype=newParent();

WorkswithconstructorsUsestheprototypechain

ThedefaultmechanismTip-moveallproperties/methodsthataremeanttobereusedtotheprototype,andaddthenon-reusableas own properties

2Inheritonlytheprototype

Child.prototype=Parent.prototype;

WorkswithconstructorsCopiestheprototype(noprototypechain,asallsharethesameprototypeobject)

Moreefficient;nonewinstancesarecreatedjustforthesakeofinheritancePrototypechainlookupduringruntime;itisfast,sincethere'snochainDrawback:childrencanmodifyparents'functionality

3Temporaryconstructor

functionextend(Child,Parent){varF=function(){};F.prototype=Parent.prototype;Child.prototype = new F();Child.prototype.constructor=Child;Child.uber=Parent.prototype;}

Works withconstructorsUsestheprototypechain

Unlike#1,itonlyinheritspropertiesofthe prototype; own properties(createdwiththisinsidetheconstructor)arenotinherited.Providesconvenientaccesstotheparent(throughuber)

4Copyingtheprototype

properties

functionextend2(Child,Parent){varp=Parent.prototype;varc=Child.prototype;for(variinp){c[i]=p[i];}c.uber=p;}

WorkswithconstructorsCopiespropertiesUsestheprototypechain

AllpropertiesoftheparentprototypebecomepropertiesofthechildprototypeNoneedtocreateanewobjectonlyforinheritancepurposesShorterprototypechains

Page 317: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

5

Copyallproperties

(shallowcopy)

functionextendCopy(p){varc={};for(variinp){c[i]=p[i];}c.uber=p;returnc;}

Works with objectsCopiesproperties

SimpleDoesn'tuseprototypes

6 DeepcopySameasthepreviousone,butrecurseintoobjects

WorkswithobjectsCopiesproperties

Sameas#5,butclonesobjectsandarrays

7Prototypalinheritance

functionobject(o){functionF(){}F.prototype=o;returnnewF();}

WorkswithobjectsUsestheprototypechain

Nopseudo-classes,objectsinheritfrom objectsLeveragesthebenefitsoftheprototype

8Extendandaugment

functionobjectPlus(o,stuff) {varn;functionF(){}F.prototype=o;n=newF();n.uber=o;for(variinstuff){n[i]=stuff[i];}returnn;}

WorkswithobjectsUsestheprototypechainCopiesproperties

Mixofprototypalinheritance(#7)andcopyingproperties(#5)Onefunctioncalltoinheritandextendatthesametime

9Multipleinheritance

functionmulti(){varn={},stuff,j=0,len=arguments.length;for(j=0;j<len;j++){stuff=arguments[j];for(variinstuff){n[i]=stuff[i];}}returnn;}

WorkswithobjectsCopiesproperties

Amixin-styleimplementationCopiesallthepropertiesofalltheparentobjectsintheorderofappearance

10Parasiticinheritance

functionparasite(victim){varthat=object(victim);that.more=1;returnthat;}

WorkswithobjectsUsestheprototypechain

Constructor-likefunctioncreatesobjectsCopiesanobject,andaugmentsandreturnsthecopy

11Borrowingconstructors

functionChild(){Parent.apply(this,arguments);}

Workswithconstructors

InheritsonlyownpropertiesCanbecombinedwith#1toinherittheprototypetooConvenientwaytodealwiththeissues whenachildinheritsapropertythatis anobject(andtherefore,passed by reference)

functionChild(){ Workswith Combinationof#11and#4

Page 318: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

12Borrowaconstructorandcopytheprototype

Parent.apply(this,arguments);}extend2(Child,Parent);

constructorsUsestheprototypechainCopiesproperties

Allowsyoutoinheritbothownpropertiesandprototypepropertieswithoutcallingtheparentconstructortwice

Givensomanyoptions,youmustbewonderingwhichistherightone.Thatdependsonyourstyleand preferences, your project, task, and team. Are you more comfortable thinking in terms ofclasses?Thenpickoneofthemethodsthatworkwithconstructors.Areyougoingtoneedjustoneorafewinstancesofyourclass?Thenchooseanobject-basedpattern.

Arethesetheonlywaysofimplementinginheritance?No.Youcanchooseapatternfromtheprecedingtable,youcanmixthem,oryoucanthinkofyourown.Theimportantthingistounderstandandbecomfortablewithobjects,prototypes,andconstructors;therestisjustpurejoy.

Page 319: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 8. Classes and ModulesIn this chapter, we will explore some of the most interesting features introduced in ES6.JavaScriptisaprototype-basedlanguageandsupportsprototypicalinheritance.Inthepreviouschapter,wediscussedtheprototypepropertyofanobjectandhowprototypicalinheritanceworksinJavaScript.ES6bringsinclasses.Ifyouarecomingfromtraditionalobject-orientedlanguagessuchasJava,youwillimmediatelyrelatetothewell-knownconceptsofclasses.However,theyarenotthesameinJavaScript.ClassesinJavaScriptareasyntacticsugarovertheprototypicalinheritancewediscussedinthelastchapter.

Inthischapter,wewilltakeadetailedlookatES6classesandmodules-thesearewelcomechangestothiseditionofJavaScriptandmakeObjectOrientedProgramming(OOP)andinheritancesignificantlyeasier.

Ifyouarecomingfroma traditionalobject-orientedlanguage,prototypicalinheritancemayfeelabitoutofplaceforyou.ES6classesofferamoretraditionalsyntaxforyoutogetfamiliarizedwithprototypicalinheritanceinJavaScript.

Beforewetryanddelvedeeperintoclasses,letmeshowyouwhyyoushouldusetheES6classessyntaxovertheprototypicalinheritancesyntaxof ES5.

Inthissnippet,IamcreatingaclasshierarchyofPerson,Employee,andEngineer,prettystraightforward.First,wewillseetheES5prototypicalinheritance,whichiswrittenasfollows:

varPerson=function(firstname){if(!(thisinstanceofPerson)){thrownewError("Personisaconstructor");}

this.firstname = firstname;};

Person.prototype.giveBirth=function(){//...wegivebirthtotheperson};

varEmployee=function(firstname,lastname,job){if(!(thisinstanceofEmployee)){thrownewError("Employeeisaconstructor");}Person.call(this,firstname);this.job=job;};Employee.prototype=Object.create(Person.prototype);Employee.prototype.constructor=Employee;Employee.prototype.startJob=function(){//...Employeestartsjob};

Page 320: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varEngineer=function(firstname,lastname,job,department){if(!(thisinstanceofEngineer)){thrownewError("Engineerisaconstructor");}Employee.call(this,firstname,lastname,job);this.department=department;};Engineer.prototype=Object.create(Employee.prototype);Engineer.prototype.constructor=Engineer;Engineer.prototype.startWorking=function(){//...Engineerstartsworking};

Nowlet'slookattheequivalentcodeusingtheES6classessyntax:

classPerson{constructor(firstname){this.firsnamet=firstname;}giveBirth(){//...apersonisborn}}

classEmployeeextendsPerson{constructor(firstname,lastname,job){super(firstname);this.lastname=lastname;this.position=position;}

startJob(){//...Employeestartsjob

}}

classEngineerextendsEmployee{constructor(firstname,lastname,job,department){super(firstname,lastname,job);this.department=department;}

startWorking(){//...Engineerstartsworking}}

Ifyouobservethetwoprecedingcodesnippets,itwillbeobvioustoyouthatthesecondexampleisprettyneat.IfyoualreadyknowJavaorC#,youwillfeelrightathome.However,oneimportantthingtorememberisthatclassesdonotintroduceanynewobject-orientedinheritancemodeltothelanguage,butbringinamuchnicerwaytocreateobjectsandhandleinheritance.

Page 321: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Defining classesUnder the hood, classes are special functions. Just like you can define functions using functionexpressionsanddeclarations,youcandefineclassesaswell.Onewaytodefineclassesisusingclassdeclaration.

Youcanusetheclasskeywordandthenameoftheclass.ThissyntaxisverysimilartothatofJavaorC#:

classCar{constructor(model,year){this.model=model;this.year=year;}}console.log(typeofCar);//"function"

Toestablishthefactthatclassesareaspecialfunction,ifwegetthetypeoftheCarclass,wewillgetafunction.

Thereisanimportantdistinctionbetweenclassesandnormalfunctions.Whilenormalfunctionsarehoisted,classesarenot.Anormalfunctionisavailableimmediatelywhenyouenterascopeinwhichitisdeclared;thisiscalledhoisting,whichmeansthatanormalfunctioncanbedeclaredanywhereinthescope,anditwillbeavailable.However,classesarenothoisted;theyare available only after they are declared. For a normal function, you can say:

normalFunction();//usefirstfunctionnormalFunction(){}//declarelater

However,youcannotusetheclassbeforedeclaringit,forexample:

varford=newCar();//ReferenceErrorclassCar{}

Theotherwaytodefineaclassistouseaclassexpression.Aclassexpression,likeafunctionexpression,mayormaynothaveaname.

Thefollowingexampleshowsananonymousclassexpression:

constCar=class{constructor(model,year){this.model=model;this.year=year;}}

Ifyounametheclassexpression,thenameislocaltotheclass'sbodyand notavailableoutside:

Page 322: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

constNamedCar=classCar{constructor(model,year){this.model=model;this.year=year;}getName(){returnCar.name;}}constford=newNamedCar();console.log(ford.getName());//Carconsole.log(ford.name);//ReferenceError:nameisnotdefined

Asyoucansee,here,wewillgiveanametotheCarclass.Thisnameisavailablewithinthebodyoftheclass,butwhenwetrytoaccessitoutsidetheclass,wegetareferenceerror.

Youcannotusecommaswhileseparatingmembersofaclass.Semicolonsarevalidthough.ThisisfunnyasES6ignoressemicolonsandthereisaragingdebateaboutusingsemicolonsinES6.Considerthefollowingcodesnippetasanexample:

classNoCommas{method1(){}

member1;//Thisisignoredandcanbeusedtoseparateclassmembersmember2,//Thisisanerrormethod2(){}}

Oncedefined,wecanuseclassesviaanewkeywordandnotafunctioncall;here'stheexample:

class Car {constructor(model,year){this.model=model;this.year=year;}}constfiesta=newCar('Fiesta','2010');

Page 323: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Constructor

Wehaveusedtheconstructorfunctionintheexamplessofar.Aconstructorisaspecialmethodusedtocreateandinitializeanobjectcreatedwiththeclass.Youcanhaveonlyoneconstructorinaclass.Constructorsareabitdifferentfromthenormalconstructorfunctions.Unlikenormalconstructors,aclassconstructorcancallitsparentclassconstructorviasuper().Wewilldiscussthisindetailwhenwelookatinheritance.

Page 324: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Prototypemethods

Prototypemethodsareprototypepropertiesoftheclass,andtheyareinheritedbyinstancesoftheclass.

Prototypemethodscanalsohavegetterandsettermethods.ThesyntaxofgettersandsettersisthesameasES5:

classCar{constructor(model,year){this.model=model;

this.year = year;}getmodel(){returnthis.model}calculateCurrentValue(){return"7000"}}constfiesta=newCar('Fiesta','2010')console.log(fiesta.model)

Similarly,computedpropertiesarealsosupported.Youcandefinethenameofthemethodusingtheexpression.Theexpressionneedstobeputinsidesquarebrackets.Wediscussedthisshorthandsyntaxinearlierchapters.Thefollowingareallequivalent:

classCarOne{driveCar(){}}classCarTwo{['drive'+'Car'](){}}

const methodName = 'driveCar';classCarThree{[methodName](){}}

Page 325: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Staticmethods

Staticmethodsareassociatedwiththeclassandnotwithaninstanceofthatclass(object).Inotherwords,youcanonlyreachastaticmethodusingthenameoftheclass.Staticmethodsareinvokedwithoutinstantiatingtheclassandtheycannotbecalledonaninstanceofaclass.Staticmethodsarepopularincreatingutilityorhelpermethods.Considerthefollowingpieceofcode:

classLogger{staticlog(level,message){console.log(`${level}:${message}`)}}//InvokestaticmethodsontheClassLogger.log("ERROR","Theendisnear")//"ERROR:Theendisnear"

//Notoninstanceconstlogger=newLogger("ERROR")logger.log("Theendisnear")//logger.logisnotafunction

Page 326: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Staticproperties

Youmayask-well,wehavestaticmethods,whataboutstaticproperties?InthehurryofgettingES6ready,theydidnotaddstaticproperties.Theywillbeaddedinfutureiterationsofthelanguage.

Page 327: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Generatormethods

Wediscussedhugelyusefulgeneratorfunctionsafewchaptersback.Youcanaddgeneratorfunctionsaspartofclass,andtheyarecalledgeneratormethods.AgeneratormethodisusefulbecauseyoucandefinetheirkeyasSymbol.iterator.Thefollowingexampleshowshowgeneratormethodscanbedefinedinsideaclass:

classiterableArg{constructor(...args){this.args=args;}*[Symbol.iterator](){for(constargofthis.args){yieldarg;}

}}

for(constxofnewiterableArg('ES6','wins')){console.log(x);}

//ES6//wins

Page 328: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SubclassingSo far, we discussed how to declare classes and the types of members classes can support. Amajoruseofaclassistoserveasatemplatetocreateothersubclasses.Whenyoucreateachildclassfromaclass,youderivepropertiesoftheparentclassandextendtheparentclassbyaddingmorefeaturesofitsown.

Let'slookatthefollowingdefactoexampleofinheritance:

class Animal {constructor(name){this.name=name;}speak(){console.log(this.name+'genericnoise');}}classCatextendsAnimal{speak(){console.log(this.name+'saysMeow.');}}varc=newCat('Grace');c.speak();//"GracesaysMeow."

Here,AnimalisthebaseclassandtheCatclassisderivedfromtheclassAnimal.Theextendclauseallowsyoutocreateasubclassofanexistingclass.Thisexampledemonstratesthesyntaxofsubclassing.Let'senhancethisexampleabitmorebywritingthefollowingcode:

classAnimal{constructor(name){this.name=name;}speak(){console.log(this.name+'genericnoise');}}classCatextendsAnimal{speak(){console.log(this.name+'saysMeow.');}}classLionextendsCat{speak(){super.speak();console.log(this.name+'Roars....');}}varl=newLion('Lenny');l.speak();

Page 329: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

//"LennysaysMeow."//"LennyRoar...."

Here,weareusingthesuperkeywordtocallfunctionsfromtheparentclass.Thefollowingarethethreewaysinwhichthesuperkeywordcanbeused:

You can use super (<params>) as a function call to invoke the constructor of the parentclassYoucanusesuper.<parentClassMethod>toaccesstheparentclassmethodsYoucanusesuper.<parentClassProp>toaccesstheparentclassproperties

Inthederiveclassconstructor,youmustcallthesuper()methodbeforeyoucanuse,thiskeyword;forexample,thefollowingpieceofcodewillfail:

classBase{}classDeriveextendsBase{constructor(name){this.name=name;//'this'isnotallowedbeforesuper()}}

Youcan'timplicitlyleaveaderivedconstructorwithasuper()methodasanerror:

classBase{}classDeriveextendsBase{constructor(){//missingsuper()callinconstructor}}

Ifyoudon'tprovideaconstructorforthebaseclass,thefollowingconstructorisused:

constructor(){}

Forthederivedclasses,thedefaultconstructorisasfollows:

constructor(...args){super(...args);

}

Page 330: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Mixins

JavaScriptsupportsonlysingleinheritance.Atmost,aclasscanhaveonesuperclass.Thisislimitingwhenyouwanttocreateclasshierarchiesbutalsowanttoinherittoolmethodsfromdifferentsources.

Let'ssaywehaveascenariowherewehaveaPersonclass,andwecreateasubclass,Employee:

classPerson{}classEmployeeextendsPerson{}

Wealsowanttoinheritfunctionsfromtwoutility classes,BackgroundCheck-thisclassdoesemployeebackgroundchecks-andOnboard-thisclasshandlesemployeeonboardingprocesses,suchasprintingbadgesandsoon:

classBackgroundCheck{check(){}}classOnboard{printBadge(){}}

BothBackgroundCheckandOnboardclassesaretemplates,andtheirfunctionalitywillbeusedmultipletimes.Suchtemplates(abstractsubclasses)arecalledmixins.

As multiple inheritance is not possible in JavaScript, we will employ a different technique toachievethis.ApopularwayofimplementingmixinsinES6istowriteafunctionwithasuperclassasaninputandasubclassextendingthatsuperclassastheoutput,forexample:

classPerson{}constBackgroundCheck=Tools=>classextendsTools{check(){}};constOnboard=Tools=>classextendsTools{printBadge(){}};classEmployeeextendsBackgroundCheck(Onboard(Person)){}

ThisessentiallymeansthatEmployeeisasubclassofBackgroundCheck,whichinturnisasubclassofOnboard,whichinturnisasubclassofPerson.

Page 331: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ModulesJavaScript modules are not new. In fact, there were have been libraries that support modules forsometimenow.ES6,however,offersbuilt-inmodules.Traditionally,JavaScript'smajorusewasonbrowsers,wheremostoftheJavaScriptcodewaseitherembeddedorsmallenoughtomanagewithoutmuchtrouble.Thingshavechanged.JavaScriptprojectsarenowonamassivescale.Withoutanefficientsystemofspreadingthecode intofilesanddirectories,managingcodebecomesanightmare.

ES6modulesarefiles.Onemoduleperfileandonefilepermodule.Thereisnomodulekeyword.Whatevercodeyouwriteinthemodulefileislocaltothemoduleunlessyouexportit.Youmayhaveabunchoffunctionsinamodule,andyouwanttoexportonlyafewofthem.Youcanexportmodulefunctionalityinacoupleofways.

Thefirstwayistousetheexportkeyword.Youcanexportanytop-level function,class,var,let,orconst.

The following example shows a module inside server.js where we export a function, aclass, and a const. We don't export the processConfig() function, and any file importing thismodule won't be able to access the unexported function:

//----------------server.js---------------------exportconstport=8080;exportfunctionstartServer(){//...startserver}exportclassConfig{//...}functionprocessConfig(){//...}

Anycodethathasaccesstoserver.jscanimporttheexportedfunctionality:

//--------------app.js----------------------------import{Config,startServer}from'server'startServer(port);

Inthiscase,anotherJavaScriptfileisimportingConfigandstartServerfromtheservermodule(withthecorrespondingJavaScriptfileserver.js,wedropthefileextension).

Youcanalsoimporteverythingthatwasexportedfromthemodule:

import*from'server'

Page 332: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Ifyouhaveonlyonethingtoexport,youcanusethedefaultexportsyntax. Considerthefollowingpieceofcodeasanexample:

//----------------server.js---------------------exportdefaultclass{//...}//--------------app.js----------------------------importServerfrom'server';consts=newServer();

Inthisexample,wewillkeeptheclassanonymousaswecanusethemodulenameitselfasthereferenceoutside.

BeforeES6modules,externallibrariessupportedseveralapproachestomodules.Theyestablishedfairlygoodguidelines/stylesforES6tofollow.ThefollowingstyleisfollowedbyES6:

Modulesaresingletons.Amoduleisimportedonlyonce,evenifyoutrytoimportitseveraltimesinyourcode.Variable,functions, andothertypeofdeclarationsarelocaltothemodule.Onlydeclarationsmarkedwithexportareavailableoutsidethemoduleforimport.Modulescanimportfromothermodules.Thefollowingarethethreeoptionsforreferringtoothermodules:

Youcanuserelativepaths("../lib/server");thesepathsareresolvedrelativelytothefileimportingthemodule.Forexample,ifyouareimportingthemodulefrom<project_path>/src/app.js,andthemodulefileislocatedat<project_path>/lib/server.js,youwillneedtoprovidea pathrelativetotheapp.js-../lib/serverinthiscase.Absolutepathscanalsopointtothemodulefiledirectly.Youcandropthefile.jsextensionwhileimportingthemodule.

BeforewegointomoredetailsoftheES6modulesystem,weneedtounderstandhowES5supportedthemviaexternallibraries.ES5hastwonon-compatiblemodulesystems,whichareasfollows:

CommonJS:ThisisthedominantstandardasNode.jsadopteditAMD(AsynchronousModuleDefinition):ThisisslightlymorecomplicatedthanCommonJSanddesignedforasynchronousmoduleloading,andtargetedtowardbrowsers

ES6moduleswereaimedtobeeasytouseforengineerscomingfromanyofthesesystems.

Page 333: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exportlists

Insteadoftaggingeachexportedfunctionorclassfromyourmodulewiththeexportkeyword,youcanwriteasinglelistofallthethingsyouwanttoexportfromthemodule,whichareasfollows:

export{port,startServer,Config};constport=8080;functionstartServer(){//...startserver

}classConfig{//...}functionprocessConfig(){//...}

Thefirstlineofthemoduleisthelistofexports.Youcanhavemultipleexportlistsinthemodulefileandthelistcanappearanywhereinthefile.Youcanalsohaveamixofexportlistandexportdeclarationsinthesamemodulefile,butyoucanexportonenameonlyonce.

Inalargeproject,therearecaseswhenyouencounternameconflicts.Supposeyouimporttwomodules,andbothofthemexportafunctionwiththesamename.Insuchcases,youcanrenametheimportsasfollows:

import{truncasStringLib}from"../lib/string.js"import{truncasMathLib}from"../lib/math.js"

Here, both the imported modules exported a name, trunc, and hence created a conflict of names.We can alias them to resolve this conflict.

Youcandotherenaming whileexportingaswell,whichisasfollows:

functionv(){}functionv2(){}export{vasfunctionV(),v2asfunctionV2(),v2asfunctionLatest()}

IfyouarealreadyusingES5modulesystems,ES6modulesmaylookredundant.However,itwasveryimportantforthelanguagetohavesupportforsuchanimportantfeature.ES6modulesyntaxisalsostandardizedandmorecompactthantheotheralternatives.

Page 334: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, we focused on understanding ES6 classes. ES6 classes give formal support to thecommonJavaScriptpatternofsimulatingclass-likeinheritancehierarchiesusingfunctionsandprototypes.Theyaresyntacticsugaringoverprototype-basedOO,offeringaconvenientdeclarativeformforclasspatternswhichencourageinteroperability.ES6 classesofferamuchnicer,cleaner,andclearersyntaxforcreatingtheseobjectsanddealingwithinheritance.ES6classesprovidesupportforconstructors,instanceandstaticmethods,(prototype-based)inheritance,andsupercalls.

Sofar,JavaScriptlackedoneofthemostbasicfeatures-modules.BeforeES6,wewrotemodulesusingeitherCommonJSorAMD.ES6bringsmodulesintoJavaScriptofficially.Inthischapter,wetookadetailedlookathowmodulesareusedinES6.

ThenextchapterfocusesonanotherinterestingadditiontoES6-proxiesandpromises.

Page 335: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 9. Promises and ProxiesThis chapter introduces the important concept of asynchronous programming and howJavaScriptisanideallanguagetoutilizeit.Theothertopicthatwewillcoverinthischapterismetaprogrammingwithproxies.ThesetwoconceptsareintroducedinES6.

Inthischapter,ourprimaryfocusistounderstandasynchronousprogramming,beforewejumpintothelanguage-specificconstructs,let'sspendtimeinunderstandingtheconceptfirst.

Thefirstmodel-thesynchronousmodel-iswhereitallbegan.Thisisthesimplestmodelofprogramming.Eachtaskisexecutedoneatatime,andonlyafterthefirsttaskcompletesexecutioncan,thenexttaskstart.Whenyouprograminthismodel,weexpectthatalltasksbeforethecurrenttaskarecompleteandthereisnoerror.Takealookatthefollowingfigure:

Page 336: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thesinglethreadedasynchronousmodelisafamiliarmodelweallknow.However,thismodelcanbewastefulandoptimized.Foranynontrivialprogramscomposedofseveraldifferenttasks,thismodelcanbeslow.Considerthefollowinghypotheticalscenarioasanexample:

varresult=database.query("SELECT*FROMtable");console.log("Afterreadingfromthedatabase");

Withthesynchronousmodelinmind,twotasksareexecutedoneaftertheother.Thismeansthatthesecondstatementwillonlybeexecutedoncethefirsthascompletedexecution.Assumingthe

Page 337: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

firststatementisacostlyoneandtakes10seconds(itisnormaltotakeevenmoretimetoreadfromaremotedatabase),thesecondstatementwillbeblocked.

This is a serious problemwhen you need to write high - performance and scalable systems. Thereisanotherproblemthatmanifestswhenyouarewritingprogramswhereyouneedtowriteinterfacesforhumaninteractionslikewedoonwebsitesthatrunonabrowser.Whileyouareperformingataskthatmaytakesometime,youcannotblocktheuser.Theymaybeenteringsomethinginaninputfieldwhilethecostlytaskisrunning;itwouldbeaterribleexperienceifweblockuserinputwhilewearebusydoingacostlyoperation.Insuchscenarios,thecostlytasksneedtoberuninthebackgroundwhilewecanhappilytakeinputfromtheuser.

Tosolvethis,onesolutionistospliteachtaskintoitsownthreadofcontrol.Thisiscalledthemulti-threadedorthreadedmodel.Considerthefollowingfigure:

Thedifferenceishowthetasksaresplit.Inthethreadedmodel,eachtaskisperformedinitsownthreadofcontrol.Usually,threadsaremanagedbytheoperatingsystemandcanberuninparallelon different CPU cores or on a single core with appropriate thread scheduling done by the CPU.WithmodernCPUs,thethreadedmodelcanbeextremelyoptimalinperformance.Severallanguagessupportthispopularmodel.Althoughapopularmodel,thethreadedmodelcanbecomplextoimplementinpractice.Thethreadsneedtocommunicateandcoordinatewitheachother.Inter-threadcommunicationcangettrickyveryquickly.Therearevariationsofthethreadedmodelwherethestateisimmutable.Insuchcases,themodelbecomessimpleraseachthreadisresponsibleforimmutablestateandthereisnoneedtomanagestatebetweenthreads.

Page 338: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Asynchronous programming modelThe third model is what interests us the most. In this model, tasks are interleaved in a singlethreadofcontrol.Considerthefollowingfigure:

Theasynchronousmodelissimplerbecauseyouhaveonlyonethread.Whenyouareexecutingonetask,youaresurethatonlythattaskisbeingexecuted.Thismodeldoesn'trequirecomplexmechanismforinter-threadcoordinationand,hence,ismorepredictable.Thereisonemoredifferencebetweenthethreadedandtheasynchronousmodels;inthethreadedmodel,youdon'thaveawaytocontrolthethreadexecutionasthethreadschedulingismostlydonebytheoperatingsystem.However,intheasynchronousmodel,thereisnosuchchallenge.

In which scenarios can the asynchronous model outperform the synchronous model? If we aresimplysplittingtasksintosmallerchunks,intuitively,eventhesmallerchunkswilltakequiteanamountoftimewhenyouaddthemupintheend.

Page 339: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thereisasignificantfactorwehavenotyetconsidered.Whenyouexecuteatask,youwillendupwaitingonsomething-adiskread,adatabasequery,oranetworkcall;theseareblockingoperations.Whenyouenterablockedmode,yourtasksimplywaitsinthesynchronousmodel.Takealookatthefollowingfigure:

Intheprecedingdiagram,theblackblocksarewhereataskiswaitingonsomething.Whatarethetypicaloperationsthatcancausesuchablock?A taskisperformedinaCPUandRAM.AtypicalCPUandRAMcanhandledatatransferordersofmagnitudefasterthanatypicaldiscreadoranetworkcall.

Page 340: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Tip

Pleaserefertoacomparison(https://gist.github.com/jboner/2841832)oflatenciesbetweenCPU,internalmemory,anddiscs.

Whenyourtaskswaiton anI/O(Input/Output)fromsuchsources,thelatencyisunpredictable.ForasynchronousprogramthatdoesalotofI/O,thisisarecipeforbadperformance.

The most important difference between the synchronous and asynchronous models is the way theyhandleblockingoperations.Intheasynchronousmodel,aprogram,whenfacedwithataskthatencountersablock,executesanothertaskwithoutwaitingfortheblockingoperationtofinish.Inaprogramwheretherearepotentialblocks,anasynchronousprogramoutperformsanequivalentsynchronousprogrambecauselesstimeisspentonwaiting.Aslightlyinaccuratevisualizationofsuchamodelwouldbeasseeninthefollowingfigure:

Withthisconceptualbackgroundoftheasynchronousmodelwithus,wecanlookatlanguage-specificconstructstosupportthismodel.

Page 341: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

JavaScript call stackIn JavaScript, function calls form a stack of frames. Consider the following example:

functionc(z2){console.log(newError().stack);}functionb(z1){c(z1+1);}functiona(z){b(z+1);}a(1);

//atc(evalat<anonymous>)//atb(evalat<anonymous>)//ata(evalat<anonymous>)

Whenwecallfunctiona(),thefirstframeinthestackiscreatedwithargumentstothefunctionandalllocalvariablesinthea()function.Whenfunctiona()callsfunctionb(),asecondframeiscreatedandpushedtothetopofthestack.Thisgoesonforallfunctioncalls.Whenthec()function returns, the top frame from the stack is popped out, leaving functions b() and a();this goes on until the entire stack is empty. This is necessary to maintain because once the functionfinishesexecution,JavaScriptwillneedtoknowwheretoreturn.

Page 342: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Messagequeue

TheJavaScriptruntimecontainsamessagequeue.Thisqueuecontainsthelistofmessagestobeprocessed.ThesemessagesarequeuedinresponsetoeventssuchasclickoranHTTPresponsereceived.Eachmessageisassociatedwithacallbackfunction.

Page 343: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Eventloop

Abrowsertabrunsinasinglethread-aneventloop.Thisloopcontinuouslypicksmessagesfromthemessagequeueandexecutesthecallbacksassociatedwiththem.Theeventloopsimplykeepspickingtasksfromthemessagequeueswhileotherprocessesaddtaskstothemessagequeue.Otherprocessessuchastimersandeventhandlersruninparallelandkeepaddingtaskstothequeue.

Page 344: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Timers

ThesetTimeout()methodcreatesatimerandwaitsuntilitfires.Whenthetimerisexecuted,ataskisaddedtothemessagequeue.ThesetTimeOut()methodtakestwoarguments:acallback,andthedurationinmilliseconds.Aftertheduration,thecallbackisaddedtothemessagequeue.Oncethecallbackisaddedtothemessagequeue,theeventloopwilleventuallypickitupandexecuteit.Thereis,however,noguaranteewhenthecallbackwillbepickedupbytheeventloop.

Runtocompletion

Whentheeventlooppicksupamessagefromthequeue,theassociatedcallbackisruntocompletion.Thismeansthatamessageisprocessedcompletelybeforethenextmessagefromthequeueisprocessed.Thispropertygivestheasynchronousmodelasenseofpredictability.Asthereisnointerventiontopreemptanyofthemessagesinbetweenexecution,thismodelismuchsimplerthanothermodels,whereanyunitofexecutioncanbehaltedinbetween.However,oncethemessageispickedup,eveniftheexecutiontakestoolong,anyotherinteractiononthebrowserisblocked.

Events

Youcanregistereventhandlersforanobjectandreceiveresultsofamethodasynchronously.ThefollowingexampleshowshowwecansetupeventhandlersfortheXMLHttpRequestAPI:

varxhr=newXMLHttpRequest();xhr.open('GET','http://babeljs.io',true);xhr.onload=function(e){if(this.status==200){console.log("Works");}};xhr.send();

Intheprecedingsnippet, wearecreatingtheobjectoftheXMLHttpRequestclass.Oncetherequestobjectiscreated,wewillregistereventhandlersforit.Eventhandlers,suchasonload(),aretriggeredasynchronouslywhentheresponseisreceivedfromtheopen()method.

The send() method doesn't actually initiate the request, it adds the request to the message queuefor the event loop to pick it up and execute necessary callbacks associated with it.

Callbacks

TheNode.jsapplicationpopularizedthisstyleof receivingasynchronousdata.Acallbackisafunctionpassedasthelastargumenttotheasynchronousfunctioncall.

Toillustratetheusage,let'susethefollowingexampleofreadingafileinNode.js:

Page 345: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

fs.readFile('/etc/passwd',(err,data)=>{if(err)throwerr;console.log(data);});

Don'tworryaboutafewdetailshere.Weareusingthefilesystemmoduleasanfsalias.ThismodulehasareadFilemethodtoreadafileasynchronously.Wewillpassthefilepathandfilenameasthefirstargumentandacallbackfunctionasthelastargumentofthefunction.Weareusingananonymousfunctionasthecallbackintheexample.

Thecallbackfunctionhastwoarguments-erroranddata.WhenthereadFile()methodissuccessful,thecallbackfunctionreceivesdata,andifitfails,theerrorargumentwillhavetheerrordetails.

Wecanalsouseaslightlyfunctionalstyletowritethesamecallback.Considerthefollowingexample:

fs.readFile('/etc/passwd',//successfunction(data){console.log(data)},//errorfunction(error){console.log(error)

});

Thisstyleofpassingcallbacksisalsocalledcontinuous-passingstyle(CPS);thenextstepofexecutionorcontinuationispassedasaparameter.ThefollowingexamplefurtherillustratestheCPSstyleofcallbacks:

console.log("1");cps("2",functioncps_step2(val2){console.log(val2);cps("3",functioncos_step3(val3){console.log(val3);})console.log("4");});console.log("5");//15243

functioncps(val,callback){setTimeout(function(){callback(val);},0);}

Wewillprovidethecontinuation(thenextcallback)toeachstep.Thisnestedcallbackstylealso

Page 346: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

causesaproblemsometimesreferredtoascallbackhell.

CallbacksandtheCPSintroducearadicallydifferentstyleofprogramming.Althoughitiseasierto understand callbacks compared to other constructs, callbacks can create slightly difficult tounderstandcode.

Page 347: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

PromisesES6 introduces promises as an alternate to callbacks. Like callbacks, promises are used toretrievetheresultsofanasynchronousfunctioncall.Usingpromisesiseasierthancallbacksandproducesmorereadablecode.However,toimplementpromisesforyourasynchronousfunctionsrequiresmorework.

Apromiseobjectrepresentsavaluethatmaybeavailablenoworinthefuture,orpossiblynever.Asthenamesuggests,apromisemaybefulfilledorrejected.Apromiseactsasaplaceholderfortheeventualresult.

Apromisehasthreemutuallyexclusivestates,whichareasfollows:

1. Apromiseispendingbeforetheresultisready;thisistheinitialstate.2. Apromiseisfulfilledwhentheresultisready.3. Onanerror,apromiseisrejected.

Whenapendingpromiseiseitherfulfilledorrejected,associatedcallbacks/handlersthatarequeuedupbythethen()methodofthepromiseareexecuted.

ThepurposeofpromisesistoprovideabettersyntaxfortheCPScallbacks.ThetypicalCPSstyleasynchronousfunctionslikethefollowingone:

asyncFunction(arg,result=>{//...})

Theprecedingcodecanbewrittenabitdifferentlywithpromises,asshowninthefollowinglinesofcode:

asyncFunction(arg).then(result=>{//...});

Theasynchronousfunctionnowreturnsapromise,whichistheplaceholderforaneventualresult.Callbacksregisteredwiththethen()methodarenotifiedwhentheresultisready.

Youcanchainthethen()method.Whenthethen()methodseesthatthecallbacktriggeredanotherasynchronousactionthatreturnsapromise,itreturnsthatpromise.Takealookatthefollowingexample:

asyncFunction(arg).then(resultA=>{//...returnasyncFunctionB(argB);

Page 348: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}).then(resultB=>{//...})

Let'sseearealexampleofhowwecanusepromises.WesawatypicalexampleofasynchronousfilereadsinNode.js;nowlet'sseewhatthatexamplewilllooklikewhenusedwithpromises.Tojogourmemories,wewrotesomethinglikethefollowing:

fs.readFile('text.json',function(error,text){if(error){console.error('Errorwhilereadingtextfile');}else{try{//...}catch(e){console.error('Invalidcontent');}

}});

Weseecallbacksascontinuationhere;nowlet'sseehowthesamefunctioncanbewrittenusingpromises:

readFileWithPromises('text.json').then(text=>{//...processtext}).catch(error=>{console.error('Errorwhilereadingtextfile');})

Nowthecallbacksareinvokedviatheresultandmethodsthen()andcatch().Theerrorhandlingismuchcleanerbecausewearenotwritingtheif...elseandtry...catchconstructsanymore.

Page 349: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Creatingpromises

Wesawhowwecanconsumepromises.Now,let'slookathowwecanproducethem.

Asaproducer,youcancreateaPromiseobjectandsendaresultviathePromise.Theconstructlookslikethefollowingcodesnippet:

constp=newPromise(function(resolve,reject){//(1)if(){resolve(value);//success}else{reject(reason);//failure}});

TheparametertoPromiseisanexecutorfunction.Theexecutorhandlestwostatesofthepromise,whichareasfollows:

Resolving: If the result was generated successfully, the executor sends the results back viatheresolve()method.ThismethodusuallyfulfillsthePromiseobject.Rejecting:Ifanerrorhappened,theexecutornotifiestheconsumerviathereject()method.Ifanexceptionoccurs,itisnotified viathereject()methodaswell.

Asaconsumer,youarenotifiedofeitherfulfillmentofpromiseorrejectionofpromiseviathethen()andcatch()methods.Considerthefollowingpieceofcodeasanexample:

promise.then(result=>{/*promisefulfilled*/}).catch(error=>{/*promiserejected*/});

Nowthatwehavesomebackgroundonhowtoproducepromises,let'srewriteourearlierexampleoftheasynchronousfile'sreadmethodtoproducepromises.WewilluseNode.js'sfilesystemmoduleandthereadFile()methodaswedidlasttime.Ifyoudon'tunderstandanyNode.jsspecificconstructinthefollowingsnippet,pleasedon'tworry.Considerthefollowingcode:

import{readFile}from'fs';functionreadFileWithPromises(filename){returnnewPromise(

function (resolve, reject) {readFile(filename,(error,data)=>{if(error){reject(error);}else{resolve(data);

Page 350: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}});});}

Intheprecedingsnippet, wearecreatinganewPromiseobjectandreturningittotheconsumer.Aswesawearlier,theparametertothePromiseobjectistheexecutorfunctionandtheexecutorfunctiontakescareoftwostatesofPromise-fulfilledandrejected.Theexecutorfunctiontakesintwoarguments,resolveandreject.ThesearethefunctionsthatnotifythestateofthePromiseobjecttotheconsumer.

Insidetheexecutorfunction,wewillcalltheactualfunction-thereadFile()method;ifthisfunctionissuccessful,wewillreturntheresultusingtheresolve()methodandifthereisanerror,wewillnotifytheconsumerusingthereject()method.

Ifanerrorhappensinoneofthethen()reactions,theyarecaughtinthesubsequentcatch()block.Takealookatthe followingcode:

readFileWithPromises('file.txt').then(result=>{'somethingcausesanexception'}).catch(error=>{'Somethingwentwrong'});

Inthiscase,thethen()reactioncausesanexceptionorerror,andthesubsequentcatch()blockcanhandlethis.

Similarly,anexceptionthrowninsideathen()orcatch()handlerispassedtothenexterrorhandler.Considerthefollowingcodesnippet:

readFileWithPromises('file.txt').then(thrownewError())

.catch(error=> {'Something went wrong'});

Promise.all()

Oneinterestingusecaseistocreateaniterableoverpromises.Let'sassumethatyouhavealistofURLsyouwanttovisitandparsetheresults.YoucancreatepromisesforeachofthefetchURLcallsandusethemindividually,oryoucancreateaniteratorwithalltheURLsandusethepromiseinonego.ThePromise.all()methodtakestheiterableofpromisesasanargument.Whenallofthepromisesarefulfilled,anarrayisfilledwiththeirresults.Considerthefollowingcodeasanexample:

Promise.all([f1(),

f2()]).then(([r1,r2])=>{//})

Page 351: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

.catch(err=>{//..});

Page 352: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Metaprogrammingandproxies

Metaprogrammingreferstoamethodofprogrammingwheretheprogramisawareofitsstructureandcanmanipulateitself.Manylanguageshavesupportformetaprogrammingintheformofmacros.MacrosareimportantconstructsinfunctionallanguagessuchasLISP(Locator/IDSeparationProtocol).InlanguagessuchasJavaandC#,reflectionisaformofmetaprogrammingbecauseaprogramcanexamineinformationaboutitselfusingreflection.

InJavaScript,youcansaythatmethodsofobjectallowyoutoexaminethestructureandhence,theyoffermetaprogramming.Therearethreetypesofmetaprogrammingparadigms(TheArtoftheMetaobjectProtocol,Kiczalesetal,https://mitpress.mit.edu/books/art-metaobject-protocol):

Introspection:Thisgivesaread-onlyaccesstotheinternalsofaprogramSelf-modification:ThismakesstructuralchangespossibletotheprogramIntercession:Thischangeslanguagesemantics

TheObject.keys()methodisanexampleofintrospection.Inthefollowingexample,theprogramisexaminingitsownstructure:

constintrospection={intro(){console.log("IthinkthereforeIam");}}for(constkeyofObject.keys(introspection)){console.log(key);//intro}

Self-modificationisalsopossibleinJavaScriptbymutatingthepropertiesofanobject.

However,intercession,ortheabilitytochangelanguagesemantics,issomethingnotavailableinJavaScripttillES6.Proxiesareintroducedtoopenupthispossibility.

Page 353: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Proxy

Youcanuseaproxytodeterminethebehaviorofanobject,whichiscalledthetarget,wheneveritspropertiesareaccessed.Aproxyisusedtodefinecustombehaviorforbasicoperationsonanobject,suchaslookingupaproperty,functioninvocation,andassignment.

Aproxyneedstwoparameters,whichareasfollows:

Handler:Foreachoperationyouwanttocustomize,youneedahandlermethod.Thismethodinterceptstheoperationsandissometimescalledatrap.Target:Whenthehandlerdoesnotintercepttheoperation,thetargetisusedasafallback.

Let'stakealookatthefollowingexampletounderstandthisconceptbetter:

varhandler={get:function(target,name){returnnameintarget?target[name]:42;}}varp=newProxy({},handler);p.a=100;p.b=undefined;console.log(p.a,p.b);//100,undefinedconsole.log('c'inp,p.c);//false,42

Inthisexample,wearetrappingtheoperationofgettingapropertyfromtheobject.Wereturn42asadefaultpropertyvalueifthepropertydoesnotexist.Weareusingthe gethandlertotrapthisoperation.

Youcanuseproxiestovalidatevaluesbeforesettingthemonanobject.Forthis,wecantrapthesethandlerasfollows:

letageValidator={set:function(obj,prop,value){if(prop==='age'){if(!Number.isInteger(value)){thrownewTypeError('Theageisnotannumber');}if(value>100){thrownewRangeError('Youcantbeolderthan100');}}//Ifnoerror-juststorethevalueinthepropertyobj[prop]=value;}};letp=newProxy({},ageValidator);p.age=100;

Page 354: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

console.log(p.age);//100p.age='Two';//Exceptionp.age=300;//Exception

Intheprecedingexample,wearetrappingthesethandler.Whenwesetapropertyoftheobject,wearetrappingthatoperationandintroducingvalidationofvalues.Ifthevalueisvalid,wewillsettheproperty.

Page 355: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Functiontraps

Therearetwooperationsthatcanbetrappedifthetargetisafunction:applyandconstruct.

Tointerceptfunctioncalls,youwillneedtotrapthegetandapplyoperations.Firstgetthefunctionandthenapplytocallthefunction.So,yougetthefunctionandreturnthefunction.

Let'sconsiderthefollowingexampletounderstandhowmethodinterceptionworks:

varcar={name:"Ford",method_1:function(text){console.log("Method_1calledwith"+text);}}varmethodInterceptorProxy=newProxy(car,{//targetistheobjectbeingproxied,receiveristheproxyget:function(target,propKey,receiver){//Ionlywanttointerceptmethodcalls,notpropertyaccessvarpropValue=target[propKey];if(typeofpropValue!="function"){returnpropValue;}else{

return function(){console.log("interceptingcallto"+propKey+"incar"+target.name);//targetistheobjectbeingproxiedreturnpropValue.apply(target,arguments);}}}});methodInterceptorProxy.method_1("Mercedes");//"interceptingcalltomethod_1incarFord"//"Method_1calledwithMercedes"

Intheprecedingexample,wearetrappingthegetoperation.Ifthetypeofthepropertybeinggetisafunction,wewilluseapplytoinvokethatfunction.Ifyouseetheoutput,wearegettingtwoconsole.logs;thefirstisfromtheproxywherewetrappedthegetoperationandthesecondisfromtheactualmethodcall.

Metaprogrammingisaninterestingconstructtouse.However,anykindofintrospectionorreflectioncomesatthecostofperformance.Careshouldbetakenwhileusingproxiesastheycanbeslow.

Page 356: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, we looked at two important concepts. ES6 proxies are useful meta programmingconstructsusedtodefinecustombehaviorforfundamentaloperations(forexample,propertylookup,assignment,enumeration,functioninvocation,andsoon).Welookedathowtousehandlers,traps,andproxytargetstointerceptandmodifythedefaultbehaviorofoperations.ThisgivesusverypowerfulmetaprogrammingcapabilitiesearlierlackinginJavaScript.

TheotherimportantconstructwediscussedinthischapterwasES6promises.Promisesareimportantbecausetheymakeasynchronousprogrammingconstructseasiertoworkwith.Apromiseactsasaproxyforavaluenotnecessarilyknownwhenthepromiseiscreated.Thisletsasynchronousmethodsreturnvalueslikesynchronousmethods-insteadofthefinalvalue,theasynchronousmethodreturnsapromiseforthevalueatsomepointinthefuture.

ThesearetwoverypowerfulconstructsinES6thatgreatlyenhancethelanguage'scorecapabilities.

Inthenextchapter,wewilllookatthefascinatingpossibilitiesaroundbrowsersandDOMmanipulationusingJavaScript.

Page 357: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 10. The Browser EnvironmentYou know that JavaScript programs need a host environment. Most of what you learned so far inthisbookwasrelatedtocoreECMAScript/JavaScriptandcanbeusedinmanydifferenthostenvironments.Now,let'sshiftthefocustothebrowserasthisisthemostpopularandnaturalhostenvironmentforJavaScriptprograms.Inthischapter,youwilllearnthefollowingtopics:

TheBrowserObjectModel(BOM)TheDocumentObjectModel(DOM)BrowsereventsTheXMLHttpRequestobject

Page 358: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Including JavaScript in an HTML pageTo include JavaScript in an HTMLpage, you will need to use the <script> tag as follows:

<!DOCTYPE><html><head><title>JStest</title><scriptsrc="somefile.js"></script></head><body><script>vara=1;a++;

</script></body></html>

Inthisexample,thefirst<script>tagincludesanexternalfile,somefile.js,whichcontainsJavaScriptcode.Thesecond<script>tagincludestheJavaScriptcodedirectlyintheHTMLcodeofthepage.ThebrowserexecutestheJavaScriptcodeinthesequenceitfindsitonthepageandallthecodeinalltagssharethesameglobalnamespace.Thismeansthatwhenyoudefineavariableinsomefile.js,italsoexistsinthesecond<script>block.

Page 359: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BOM and DOM - an overviewThe JavaScript code in a page has access to a number of objects. These objects can be dividedintothefollowingtypes:

CoreECMAScriptobjects:ThisconsistsofalltheobjectsmentionedinthepreviouschaptersDOM:Thisconsistsofobjectsthathavetodowiththecurrentlyloadedpage,whichisalsocalledthedocumentBOM:Thisconsistsofobjectsthatdealwitheverythingoutsidethepage-thebrowserwindowandthedesktopscreen

DOMstandsforDocumentObjectModelandBOMforBrowserObjectModel.

TheDOMisastandardgovernedbytheWorldWideWebConsortium(W3C)andhasdifferentversions,calledlevels,suchasDOMLevel1,DOMLevel2,andsoon.Browsersinusetodayhavedifferentdegreesofcompliancewiththestandard,butingeneral,theyalmostallcompletelyimplementDOMLevel1.TheDOMwasstandardizedpostfactumafterthebrowservendorshadeachimplementedtheirownwaystoaccessthedocument.ThelegacypartfrombeforetheW3CtookoverisstillaroundandisreferredtoasDOM0,although,norealDOMLevel0standardexists.SomepartsofDOM0havebecomedefactostandardsasallmajorbrowserssupportthem;someofthesewereaddedtotheDOMLevel1standard.TherestofDOM0thatdidn'tfinditswaytoDOM1istoobrowserspecificandwon'tbediscussedhere.

Historically,BOMwasnotapartofanystandard.SimilartoDOM0,ithasasubsetofobjectsthatissupportedbyallmajorbrowsers,andanothersubsetthatisbrowser-specific.TheHTML5standard codifies common behavior among browsers, and it includes common BOM objects.Additionally,mobiledevicescomewiththeirspecificobjects(andHTML5aimstostandardizethoseaswell),whichtraditionallywerenotnecessaryfordesktopcomputers,butmakesenseinamobileworld,forexample,geolocation,cameraaccess,vibration,touchevents,telephony,andSMS.

Thischapterdiscussesonlycross-browsersubsetsofBOMandDOMLevel1,unlessnotedotherwiseinthetext.Eventhesesafesubsetsconstitutealargetopic,andafullreferenceisbeyondthescopeofthisbook.Youcanalsoconsultthefollowingreferences:

MozillaDOMreference(http://developer.mozilla.org/en/docs/Gecko_DOM_Reference)Mozilla'sHTML5wiki(https://developer.mozilla.org/en-US/docs/HTML/HTML5)Microsoft'sdocumentationforInternetExplorer(http://msdn2.microsoft.com/en-us/library/ms533050(vs.85).aspx)W3C'sDOMspecifications(http://www.w3.org/DOM/DOMTR)

Page 360: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BOMThe BOM is a collection of objects that give you access to the browser and the computer screen.Theseobjectsareaccessiblethroughtheglobalobjectwindow.

Page 361: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thewindowobjectrevisited

Asyoualreadyknow,inJavaScript,there'saglobalobjectprovidedbythehostenvironment.Inthebrowserenvironment,thisglobalobjectisaccessibleusingwindow.Allglobalvariablesarealsoaccessibleaspropertiesofthewindowobject.Forexample,takealookatthefollowingcode:

>window.somevar=1;1>somevar;1

Additionally,allthecoreJavaScriptfunctions,discussedinChapter2,PrimitiveDataTypes,Arrays, Loops, and Conditions, are methods of the global object. Consider the following piece ofcode:

>parseInt('123a456');123>window.parseInt('123a456');123

Inadditiontobeingareferencetotheglobalobject,thewindowobjectalsoservesasecondpurpose-providinginformationaboutthebrowserenvironment.There'sawindowobjectforeveryframe,iframe,popup,orbrowsertab.

Let'sseesomeofthebrowser-relatedpropertiesofthewindowobject.Again,thesecanvaryfromonebrowsertoanother,solet'sonlyconsiderthe propertiesthatareimplementedconsistentlyandreliablyacrossallmajorbrowsers.

Page 362: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingwindow.navigatorproperty

Thenavigatorisanobjectthathassomeinformationaboutthebrowseranditscapabilities.Onepropertyisnavigator.userAgent,whichisalongstringofbrowseridentification.InFirefox,you'llgetthefollowingoutput:

> window.navigator.userAgent;"Mozilla/5.0(Macintosh;IntelMacOSX10_8_3)AppleWebKit/536.28.10(KHTML,likeGecko)Version/6.0.3Safari/536.28.10"

TheuserAgentstringinMicrosoftInternetExplorerissomethingasfollows:

"Mozilla/5.0(compatible;MSIE10.0;WindowsNT6.1;Trident/6.0)"

Asthebrowsershavedifferentcapabilities,developersareusingtheuserAgentstringtoidentifythebrowserandprovidedifferentversionsofthecode.Forexample,thefollowingcodesnippetsearchesforthepresenceoftheMSIEstringtoidentifyInternetExplorer:

if(navigator.userAgent.indexOf('MSIE')!==-1){//thisisIE}else{//notIE}

It'sbetternottorelyontheuserAgentstring,buttousefeaturesniffing(alsocalledcapabilitydetection)instead.Thereasonforthisisthatit'shardtokeeptrackofallbrowsersandtheirdifferentversions.It'smucheasiertosimplycheckifthefeatureyouintendtouseisindeedavailableintheuser'sbrowser.Forexample,takealookatthefollowingcodesnippet:

if(typeofwindow.addEventListener==='function'){//featureissupported,let'suseit}else{//hmm,thisfeatureisnotsupported,willhaveto//thinkofanotherway}

AnotherreasontoavoiduserAgentsniffingisthatsomebrowsersallowuserstomodifythestringandpretendtheyareusingadifferentbrowser.

Page 363: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Yourconsoleisacheatsheet

Theconsoleletsyouinspectwhat'sinanobjectandthisincludesalltheBOMandDOMproperties.Justtypethefollowingcode:

>navigator;

Thenclickontheresult.Theresultisalistofpropertiesandtheirvalues,asshowninthefollowingscreenshot:

Page 364: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingwindow.locationproperty

ThelocationpropertypointstoanobjectthatcontainsinformationabouttheURLofthecurrentlyloadedpage.Forexample,location.hrefisthefullURLandlocation.hostnameisonlythedomain.Withasimpleloop,youcansee thefulllistofpropertiesofthelocationobject.

Imagineyou'reonapagewiththefollowingURL:

http://search.phpied.com:8080/search?q=java&what=script#results.

Considerthefollowingcode:

for(variinlocation){if(typeoflocation[i]==="string"){console.log(i+'="'+location[i]+'"');}}href="http://search.phpied.com:8080/search?q=java&what=script#results"hash="#results"host="search.phpied.com:8080"hostname="search.phpied.com"pathname="/search"port=<<8080>>protocol=<<http:>>search="?q=java&what=script"

Therearealsothreemethodsthatlocationpropertyprovides,namelyreload(),assign(),andreplace().

It'sinterestinghowmanydifferentwaysexistforyoutonavigatetoanotherpage.Thefollowingareafewways:

>window.location.href='http://www.packtpub.com';>location.href='http://www.packtpub.com';>location='http://www.packtpub.com';>location.assign('http://www.packtpub.com');

Thereplace()methodisalmostthesameasassign().Thedifferenceisthatitdoesn'tcreateanentryinthebrowser'shistorylistasfollows:

>location.replace('http://www.yahoo.com');

Toreloadapage,youcanusethefollowingcode:

>location.reload();

Page 365: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Alternatively,youcanuselocation.hreftopointittoitself,asfollows:

>window.location.href=window.location.href;

Or,simplyusethefollowingcode:

>location=location;

Page 366: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingwindow.historyproperty

Thewindow.historypropertyallowslimitedaccesstothepreviouslyvisitedpagesinthesamebrowsersession.Forexample,youcanseehowmanypagestheuserhasvisitedbeforecomingtoyourpage,asfollows:

>window.history.length;5

YoucannotseetheactualURLsthough.Forprivacyreasons,thisdoesn'twork.Seethefollowingcode:

>window.history[0];

Youcan,however,navigatebackandforththroughtheuser'ssessionasiftheuserhadclickedontheback/forwardbrowserbuttons,asfollows:

>history.forward();>history.back();

Youcanalsoskippagesbackandforthwithhistory.go().Thisisthesameascallinghistory.back().Thecodeforhistory.go()isasfollows:

>history.go(-1);

Togotwopagesback,usethefollowingcode:

>history.go(-2);

Reloadthecurrentpageusingthefollowingcode:

>history.go(0);

MorerecentbrowsersalsosupportHTML5historyAPI,whichletsyouchangetheURLwithoutreloading the page. This is perfect for dynamic pages because they can allow users to bookmark aspecificURL,whichrepresentsthestateoftheapplication,andwhentheycomeback,orsharewiththeirfriends,thepagecanrestoretheapplicationstatebasedontheURL.TogetasenseofthehistoryAPI,gotoanypageandwritethefollowinglinesofcodeintheconsole:

>history.pushState({a:1},"","hello");> history.pushState({b: 2}, "", "hello-you-too");

>history.state;

NoticehowtheURLchanges,butthepageisthesame.Now,experimentwithbackandforwardbuttonsinthebrowserandinspectthehistory.stateobjectagain.

Page 367: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

usingwindow.framesproperty

Thewindow.framespropertyisacollectionofalloftheframesinthecurrentpage.Itdoesn'tdistinguishbetweenframesandiframes(inlineframes).Regardlessofwhetherthereareframesonthepageornot,window.framesalwaysexistsandpointstowindow,asfollows:

> window.frames === window;true

Let'sconsideranexamplewhereyouhaveapagewithoneiframe,asfollows:

<iframename="myframe"src="hello.html"/>

Inordertotellifthereareanyframesonthepage,youcancheckthelengthproperty.Incaseofoneiframe,you'llseethefollowingoutput:

>frames.length1

Eachframecontainsanotherpage,whichhasitsownglobalwindowobject.

Togetaccesstotheiframe'swindow,youcanexecuteanyofthefollowing:

>window.frames[0];>window.frames[0].window;>window.frames[0].window.frames;>frames[0].window;>frames[0];

Fromtheparentpage,youcanaccesspropertiesofthechildframeaswell.Forexample,youcanreloadtheframeasfollows:

> frames[0].window.location.reload();

Frominsidethechild,youcanaccesstheparentasfollows:

>frames[0].parent===window;true

Usingapropertycalledtop,youcanaccessthetop-mostpage-theonethatcontainsalltheotherframes-fromwithinanyframe,asfollows:

>window.frames[0].window.top===window;true>window.frames[0].window.top===window.top;true>window.frames[0].window.top===top;true

Page 368: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inaddition,selfisthesameaswindow,asyoucanseeinthefollowingcodesnippet:

>self===window;true>frames[0].self==frames[0].window;true

Ifaframehasanameattribute,youcannotonlyaccesstheframebyname, butalsobyindex,asshowninthefollowingpieceofcode:

>window.frames['myframe']===window.frames[0];true

Or,alternatively,youcanusethefollowingcode:

>frames.myframe===window.frames[0];true

Page 369: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingwindow.screenproperty

Thescreenpropertyprovidesinformationabout theenvironmentoutsidethebrowser.Forexample,thescreen.colorDepthpropertycontainsthecolorbitdepth(thecolorquality)ofthemonitor.Thisismostlyusedforstatisticalpurposes.Takealookatthefollowinglineofcode:

> window.screen.colorDepth;32

Youcanalsochecktheavailablescreenrealestate(theresolution),asfollows:

>screen.width;1440>screen.availWidth;1440>screen.height;900>screen.availHeight;847

ThedifferencebetweenheightandavailHeightisthatheightisthewholescreen,whileavailHeightsubtractsanyoperatingsystemmenus,suchastheWindowstaskbar.ThesameisthecaseforwidthandavailWidth.

Somewhatrelatedisthepropertymentionedinthefollowingcode:

>window.devicePixelRatio;1

Ittellsyouthedifference(ratio)betweenphysicalpixelsanddevicepixelsintheretinadisplaysinmobiledevices,forexample,value2iniPhone.

Page 370: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

window.open()/close()method

Havingexploredsomeofthemostcommoncross-browserpropertiesofthewindowobject,let'smovetosomeofthemethods.Onesuchmethodisopen(),whichallowsyoutoopennewbrowserwindows(popups).Variousbrowserpoliciesandusersettingsmaypreventyoufromopeningapopup(duetoabuseofthetechniqueformarketingpurposes),butgenerally,youshouldbeabletoopenanewwindowifitwasinitiatedbytheuser.Otherwise,ifyoutrytoopenapopupasthepageloads,itwillmostlikelybeblocked,becausetheuserdidn'tinitiateitexplicitly.

Thewindow.open()methodacceptsthefollowingparameters:

URLtoloadinthenewwindowNameofthenewwindowthatcanbeusedasthevalueofaform'stargetattributeComma-separatedlistoffeatures,whichisasfollows:

resizable:Shouldtheuserbeabletoresizethenewwindowwidth,height:Widthandheightofthepopupstatus:Shouldthestatusbarbevisible

Thewindow.open()methodreturnsareferencetothewindowobjectofthenewlycreatedbrowserinstance.Thefollowingisanexample:

varwin=window.open('http://www.packtpub.com','packt','width=300,height=300,resizable=yes');

Thewinvariablepointstothewindowobjectofthepopup.Youcancheckifwinhasafalsyvalue,whichmeansthatthepopupwasblocked.

Thewin.close()methodclosesthenewwindow.

It'sbesttostayawayfromopeningnewwindowsforaccessibilityandusabilityreasons.Ifyoudon'tlikesitespoppingupwindowstoyou,whydoittoyourusers?Therearelegitimatepurposes,suchasprovidinghelpinformationwhilefillingoutaform,butoften,thesamecanbeachievedwithalternativesolutions,suchasusingafloating<div>insidethepage.

Page 371: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

window.moveTo()andwindow.resizeTo()methods

Continuingwiththeshadypracticesfromthepast,thefollowingaremoremethodstoirritateyourusers,providedtheirbrowserandpersonalsettingsallowyoutodoso:

window.moveTo(100,100):Thismovesthebrowserwindowtoscreenlocationx=100andy=100,whichiscountedfromthetop-leftcornerwindow.moveBy(10,-10):Thismovesthewindow10pixelstotherightand10pixelsupfromitscurrentlocationwindow.resizeTo(x,y)andwindow.resizeBy(x,y):Theseacceptthesameparametersasthemovemethods,buttheyresizethewindowasopposedtomovingit

Again,trytosolvetheproblemyou'refacingwithoutresortingtothesemethods.

Page 372: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

window.alert(),window.prompt(),andwindow.confirm()methods

InChapter2,PrimitiveDataTypes,Arrays,Loops,andConditions,wetalkedaboutthealert()function.Nowyouknowthatglobalfunctionsareaccessibleasmethodsoftheglobalobject,soalert('Watchout!')andwindow.alert('Watchout!')areexactlythesame.

Thealert()functionisnotanECMAScriptfunctionbutaBOMmethod.Inadditiontoit,twootherBOMmethodsallowyoutointeractwiththeuserthroughsystemmessages.Thefollowingarethemethods:

confirm():Thisgivestheusertwooptions,OKandCancelprompt():Thiscollectstextualinput

Thisishowitworks:

>varanswer=confirm('Areyoucool?');>answer;

It presents you with a window similar to the following screenshot (the exact look depends on thebrowserandtheoperatingsystem):

You'llnoticethefollowingthings:

Nothinggetswrittentotheconsoleuntilyou closethismessage,whichmeansthatanyJavaScriptcodeexecutionfreezes,waitingfortheuser'sanswerClickingonOKreturnstrue,clickingonCancelorclosingthemessageusingtheXicon,ortheESCkey,returnsfalse

Thisishandytoconfirmuseractions,asshowninthefollowingpieceofcode:

if(confirm('Sureyouwanttodeletethis?')){//delete}else{//abort

Page 373: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}

MakesureyouprovideanalternativewaytoconfirmuseractionsforpeoplewhohavedisabledJavaScript,orforsearchenginespiders.

Thewindow.prompt()methodpresentstheuserwithadialogtoentertext,asfollows:

>varanswer=prompt('Andyournamewas?');>answer;

Thisresultsinthefollowingdialogbox(Chrome,MacOS):

Thevalueofanswerisoneofthefollowing:

null:ThishappensifyouclickonCancel,theXicon,orpressESCkey""(emptystring):ThishappensifyouclickonOKorpressEnterwithouttypinganythingAtextstring:ThisisifyoutypesomethingandthenclickonOKorpressEnter

Thefunctionalsotakesastringasasecondparameteranddisplaysitasadefaultvalueprefilledintotheinputfield.

Page 374: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Usingwindow.setTimeout()andwindow.setInterval()methods

ThesetTimeout()andsetInterval()methodsallowschedulingtheexecutionofapieceofcode.ThesetTimeout()methodattemptstoexecutethegivencodeonce,afteraspecifiednumberofmilliseconds.ThesetInterval()methodattemptstoexecuteitrepeatedlyafteraspecifiednumberofmillisecondshaspassed.

Thisshowsanalertafterapproximately2seconds(2000milliseconds).Considerthefollowingcode:

>functionboo(){alert('Boo!');}>setTimeout(boo,2000);4

Asyoucansee,thefunctionreturnedaninteger(inthiscase,4)representingtheIDofthetimeout.YoucanusethisIDtocancelthetimeoutusingclearTimeout().Inthefollowingexample,ifyou'requickenough,andclearthetimeoutbefore 2secondshavepassed,thealertwillneverbeshown,asyoucanseeinthefollowingcode:

>varid=setTimeout(boo,2000);>clearTimeout(id);

Let'schangeboo()tosomethinglessintrusive,asfollows:

>functionboo(){console.log('boo');}

Now,usingsetInterval(),youcanscheduleboo()toexecuteevery2seconds,untilyoucancelthescheduledexecutionwithclearInterval().Considerthefollowingcode:

>varid=setInterval(boo,2000);booboobooboobooboo>clearInterval(id);

Notethatbothfunctionsacceptapointertoacallbackfunctionasafirstparameter.Theycanalsoacceptastring,whichisevaluatedwitheval();however,asyouknow,eval()isevil,soitshouldbeavoided.Moreover,whatifyouwanttopassargumentstothefunction?Insuchcases,youcanjustwrapthefunctioncallinsideanother function.

Thefollowingcodeisvalid,butnotrecommended:

//badidea

Page 375: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varid=setInterval("alert('boo,boo')",2000);

Thisalternativeispreferred:

varid=setInterval(function(){alert('boo,boo');},2000

);

Beawarethatschedulingafunctioninsomeamountofmillisecondsisnotaguaranteethatitwillexecuteexactlyatthattime.Onereasonisthatmostbrowsersdon'thavemillisecondresolutiontime.Ifyouschedulesomethingin3milliseconds,itwillexecuteafteraminimumof15inolderIEsandsoonerinmoremodernbrowsers,butmostlikely,notin1millisecond.Theotherreasonisthatthebrowsersmaintainaqueueofwhatyourequestthemtodo.100millisecondstimeoutmeansaddtothequeueafter100milliseconds.However,ifthequeueisdelayedbysomethingslowhappening,yourfunctionwillhavetowaitandexecuteafter,say,120milliseconds.

MorerecentbrowsersimplementtherequestAnimationFrame()function.It'spreferabletothetimeoutfunctionsbecauseyou'reaskingthebrowsertocallyourfunctionwheneverithasavailableresources,notafterapredefinedtimeinmilliseconds.Tryexecutingthefollowingcodesnippetinyourconsole:

functionanimateMe(){webkitRequestAnimationFrame(function(){console.log(newDate());animateMe();});}

animateMe();

Page 376: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

window.documentproperty

Thewindow.documentpropertyisaBOMobjectthatreferstothecurrentlyloadeddocument(page).ItsmethodsandpropertiesfallintotheDOMcategoryofobjects.Takeadeepbreath(andmaybefirstlookattheBOMexercisesattheendofthechapter)andlet'sdiveintotheDOM.

Page 377: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

DOMThe DOM represents an XMLor an HTMLdocument as a tree of nodes. Using DOMmethods andproperties,youcanaccessanyelementonthepage,modifyorremoveelements,oraddnewones.TheDOMisalanguage-independentAPIandcanbeimplementednotonlyinJavaScript,butalsoinanyotherlanguage.Forexample,youcangeneratepagesontheserver-sidewithPHP'sDOMimplementation(http://php.net/dom).

TakealookatthisexampleHTMLpage:

<!DOCTYPEhtml><html><head><title>Mypage</title>

</head><body><pclass="opener">firstparagraph</p><p><em>second</em>paragraph</p><pid="closer">final</p><!--andthat'saboutit--></body></html>

Considerthesecondparagraph(<p><em>second</em>paragraph</p>).Youwillseethatit'sa<p>tag,andit'scontainedinthe<body>tag.Ifyouthinkintermsoffamilyrelationships,youcansaythat<body>istheparentof<p>and<p>isthechild.Thefirstandthe thirdparagraphswouldalsobechildrenofthe<body>tag,andatthesametime,siblingsofthesecondparagraph.The<em>tagisachildofthesecond<p>,so<p>isitsparent.Theparent-childrelationshipscanberepresentedgraphicallyinanancestrytree,calledtheDOMtree:

Page 378: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thepreviousscreenshotshowswhatyou'llseeintheWebKitconsole'sElementstabafteryouexpandeachnode.

Youcanseehowallofthetagsareshownasexpandablenodesonthetree.Althoughnotshown,thereexiststheso-calledtextnodes,forexample,thetextinsidethe<em>tag(thewordsecond)isatextnode.Whitespaceisalsoconsideredatextnode.CommentsinsidetheHTMLcodearealsonodesinthetree,the<!-andthat'saboutit->commentintheHTMLsourceisacommentnodeinthetree.

EverynodeintheDOMtreeisanobjectandthePropertiessectionontherightlistsallofthepropertiesandmethodsyoucanusetoworkwith theseobjects,followingtheinheritancechainofhowthisobjectwascreated:

Page 379: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Youcanalsoseetheconstructorfunctionthatwasusedbehindthescenestocreateeachoftheseobjects.Although,thisisnottoopracticalforday-to-daytasks,itmaybeinterestingtoknowthat,forexample,<p>iscreatedbytheHTMLParagraphElement()constructor,theobjectthatrepresentstheheadtagiscreatedbyHTMLHeadElement(),andsoon.Youcannotcreateobjectsusingtheseconstructorsdirectly,though.

Page 380: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CoreDOMandHTMLDOM

Onelastdiversionbeforemovingontomorepracticalexamples.Asyounowknow,theDOMrepresentsbothXMLdocumentsandHTMLdocuments.Infact,HTMLdocumentsareXMLdocuments,butalittlemorespecific.Therefore,aspartofDOMLevel1,thereisaCoreDOMspecificationthatisapplicabletoallXMLdocuments,andthereisalsoanHTMLDOMspecification,whichextendsandbuildsuponthecoreDOM.Ofcourse,theHTMLDOMdoesn'tapplytoallXMLdocuments,butonlytoHTMLdocuments.Let'sseesomeexamplesofCoreDOMandHTMLDOMconstructors:

Constructor Inherits fromCore orHTML

Comment

Node Core Anynodeonthetree

Document Node Core Thedocumentobject,themainentrypointtoanyXMLdocument

HTMLDocument Document HTMLThisiswindow.documentorsimplydocument,theHTML-specificversionofthepreviousobject,whichyou'lluseextensively

Element Node CoreEverytaginthesourceisrepresentedbyanelement.That'swhyyousay-thePelementmeaningthe<p></p>tag

HTMLElement Element HTML General-purposeconstructor,allconstructorsforHTMLelementsinheritfromit

HTMLBodyElement HTMLElement HTML Elementrepresentingthe<body>tag

HTMLLinkElement HTMLElement HTML AnAelement:an<ahref="..."></a>tag

Andothersuchconstructors

HTMLElement HTML AlltherestoftheHTMLelements

CharacterData Node Core General-purposeconstructorfordealingwithtexts

Text CharacterData CoreTextnodeinside atag;in<em>second</em>,youhavetheelementnodeEMandthetextnodewithvaluesecond

Comment CharacterData Core <!--anycomment-->

Attr Node CoreRepresentsanattributeofatag;in<pid="closer">,theidattributeisaDOMobjectcreatedbytheAttr()constructor

NodeList Core Alistofnodes,anarray-likeobjectthathasalengthproperty

Page 381: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

NamedNodeMap CoreSameasNodeList,butthenodescanbeaccessedbyname,notonlybynumericindex.

HTMLCollection HTML Similar to NamedNodeMap but specific for HTML.

Theseare,bynomeans,alloftheCoreDOMandHTMLDOMobjects.Forthefulllist,consulthttp://www.w3.org/TR/DOM-Level-1/.

NowthatthisbitoftheDOMtheoryisbehindyou,let'sfocusonthepracticalsideofworkingwith the DOM. In the following sections, you'll learn how to do the following topics:

AccessDOMnodesModifynodesCreatenewnodesRemovenodes

Page 382: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

AccessingDOMnodes

Beforeyoucanvalidatetheuserinputinaformonapageorswapanimage,youneedtogetaccesstotheelementyouwanttoinspectormodify.Luckily,therearemanywaystogettoanyelement,eitherbynavigatingaroundtraversingtheDOMtreeorbyusingashortcut.

It'sbestifyoustartexperimentingwithallofthenewobjectsandmethods.Theexamplesyou'llseeusethesamesimpledocumentthatyousawatthebeginningoftheDOMsection,andwhichyoucanaccessathttp://www.phpied.com/files/jsoop/ch7.html.Openyourconsole,andlet'sgetstarted.

Thedocumentnode

Thedocumentnodegivesyouaccesstothecurrentdocument.Toexplore thisobject,youcanuseyourconsoleasacheatsheet.Typeconsole.dir(document)andclickontheresult:

Alternatively,youcanbrowseallofthepropertiesandmethodsofthedocumentobjectDOMpropertiesintheElementspanel:

Page 383: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Allnodes,includingthedocumentnode,textnodes,elementnodes,andattributenodeshavenodeType,nodeNameandnodeValueproperties:

>document.nodeType;9

Thereare12nodetypes,representedbyintegers.Asyoucansee,thedocumentnodetypeis9.Themostcommonlyusedare1(element),2(attribute),and3(text).

Nodesalsohavenames.ForHTMLtags,thenodenameisthetagname(tagNameproperty).Fortextnodes,it's#text,andfordocumentnodes,thenameisasfollows:

>document.nodeName;"#document"

Nodes can also have node values. For example, for text nodes, the value is the actual text. Thedocumentnodedoesn'thaveavalue,whichcanbeseenasfollows:

>document.nodeValue;null

Page 384: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

documentElement

Now,let'smovearoundthetree.XMLdocumentsalwayshaveonerootnodethatwrapstherestofthedocument.ForHTMLdocuments,therootisthe<html>tag.Toaccesstheroot,youwillusethedocumentElementpropertyofthedocumentobject.

>document.documentElement;<html>...</html>

nodeTypeis1(anelementnode)whichcanbeseenasfollows:

>document.documentElement.nodeType;1

Forelementnodes,bothnodeNameandtagNamepropertiescontainthenameofthetag,asseeninthefollowingoutput:

>document.documentElement.nodeName;"HTML">document.documentElement.tagName;"HTML"

Childnodes

Inordertotellifanodehasanychildren,youwillusehasChildNodes(),asfollows:

>document.documentElement.hasChildNodes();true

TheHTMLelementhasthreechildren,theheadandthebodyelementsandthewhitespacebetweenthem(whitespaceiscountedinmost,butnotallbrowsers).YoucanaccessthemusingthechildNodesarray-likecollection,asfollows:

>document.documentElement.childNodes.length;3>document.documentElement.childNodes[0];<head>...</head>>document.documentElement.childNodes[1];#text>document.documentElement.childNodes[2];<body>...</body>

AnychildhasaccesstoitsparentthroughtheparentNodeproperty,asseeninthefollowingcode:

>document.documentElement.childNodes[1].parentNode;<html>...</html>

Let'sassignareferencetobodytoavariable,asfollows:

Page 385: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>varbd=document.documentElement.childNodes[2];

Howmanychildrendoesthebodyelementhave?Considerthefollowingpieceofcode

>bd.childNodes.length;9

Asarefresher,here,again,isthebodyofthedocument:

<body><pclass="opener">firstparagraph</p><p><em>second</em>paragraph</p><pid="closer">final</p><!--andthat'saboutit--></body>

Howcomebodyhas9children?Well,threeparagraphsplusonecommentmakesfournodes.Thewhitespacebetweenthesefournodesmakesthreemoretextnodes.Thismakesatotalofsevensofar.Thewhitespacebetween<body>andthefirst<p>istheeighthnode.Thewhitespacebetweenthecommentandtheclosing</body>isanothertextnode.Thismakesatotalofninechildnodes.Justtypebd.childNodesintheconsoletoinspectthemall.

Attributes

As the first child of the body is a whitespace, the second child (index 1) is the first paragraph.Refertothefollowingpieceofcode:

>bd.childNodes[1];<pclass="opener">firstparagraph</p>

YoucancheckwhetheranelementhasattributesusinghasAttributes(),asfollows:

>bd.childNodes[1].hasAttributes();true

Howmanyattributes?Inthisexample,oneistheclassattribute,whichcanbeseenasfollows:

>bd.childNodes[1].attributes.length;1

Youcanaccesstheattributesbyindexandname.YoucanalsogetthevalueusingthegetAttribute()method,whichisasfollows:

>bd.childNodes[1].attributes[0].nodeName;"class">bd.childNodes[1].attributes[0].nodeValue;"opener">bd.childNodes[1].attributes['class'].nodeValue;"opener">bd.childNodes[1].getAttribute('class');

Page 386: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"opener"

Accessingthecontentinsideatag

Let'stakealookatthefirstparagraph:

>bd.childNodes[1].nodeName;"P"

YoucangetthetextcontainedintheparagraphusingthetextContentproperty.Itdoesn'texistinolderIEs,butanotherpropertycalledinnerTextreturnsthesamevalue,asseeninthefollowingoutput:

>bd.childNodes[1].textContent;"firstparagraph"

ThereisalsotheinnerHTMLproperty.It'sarelativelynewadditiontotheDOMstandard,despitethefactthatitpreviouslyexistedinallmajorbrowsers.Itreturns(orsets)HTMLcodecontainedinanode.YoucanseehowthisisalittleinconsistentasDOMtreatsthedocumentasatreeofnodes,notasastringoftags.However,innerHTMLissoconvenienttousethatyou'llseeiteverywhere.Refertothefollowingcode:

>bd.childNodes[1].innerHTML;"firstparagraph"

The first paragraph contains only text, so innerHTML is the same as textContent (or innerTextin IE). However, the second paragraph does contain an em node, so you can see the difference asfollows:

>bd.childNodes[3].innerHTML;"<em>second</em>paragraph">bd.childNodes[3].textContent;"secondparagraph"

AnotherwaytogetthetextcontainedinthefirstparagraphisbyusingthenodeValuemethodofthetextnodecontainedinsidethepnode,asfollows:

>bd.childNodes[1].childNodes.length;1>bd.childNodes[1].childNodes[0].nodeName;"#text">bd.childNodes[1].childNodes[0].nodeValue;"firstparagraph"

DOMaccessshortcuts

UsingchildNodes,parentNode,nodeName,nodeValue,andattributes,youcannavigateupanddownthetreeanddoanythingwiththedocument.However,thefactthatwhitespaceisatextnodemakesthisafragilewayofworkingwiththeDOM.Ifthepagechanges,yourscriptmayno

Page 387: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

longerworkcorrectly.Also,ifyouwanttogettoanodedeeperinthetree,itcouldtakeabitofcodebeforeyougetthere.That'swhyyouhaveshortcutmethods,namely,getElementsByTagName(),getElementsByName(),andgetElementById().

The getElementsByTagName() method takes a tag name (the name of an element node) andreturns an HTMLcollection (array-like object) of nodes with the matching tag name. Forexample,thefollowingexampleasks-givemeacountofallparagraphs,whichisgivenasfollows:

>document.getElementsByTagName('p').length;3

Youcanaccessaniteminthelistusingthebracketsnotation,ortheitem()method,andpassingtheindex(0forthefirstelement).Usingitem()isdiscouraged,asarraybracketsaremoreconsistentandalsoshortertotype.Refertothefollowingpieceofcode:

>document.getElementsByTagName('p')[0];<pclass="opener">firstparagraph</p>>document.getElementsByTagName('p').item(0);<pclass="opener">firstparagraph</p>

Gettingthecontentsofthefirstpcanbedoneasfollows:

>document.getElementsByTagName('p')[0].innerHTML;"firstparagraph"

Accessingthelastpcanbedoneasfollows:

>document.getElementsByTagName('p')[2];<pid="closer">final</p>

Toaccesstheattributesofanelement,youcanusetheattributescollectionorgetAttribute(),asshownpreviously.However,ashorterwayistousetheattributenameasapropertyoftheelementyou'reworkingwith.So,togetthevalueoftheid attribute,youwilljustuseidasaproperty,whichisasfollows:

>document.getElementsByTagName('p')[2].id;"closer"

Gettingtheclassattributeofthefirstparagraphwon'tworkthough.It'sanexceptionbecauseitjusthappenssothatclassisareservedwordinECMAScript.YoucanuseclassNameinstead,asfollows:

>document.getElementsByTagName('p')[0].className;"opener"

UsinggetElementsByTagName(),youcangetalloftheelementsonthepage,asfollows:

Page 388: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>document.getElementsByTagName('*').length;8

InearlierversionsofIEbeforeIE7,*isnotacceptableasatagname.Togetallelements,youcanuseIE'sproprietarydocument.allcollection,although,selectingeveryelementisrarelyneeded.

TheothershortcutmentionedisgetElementById().Thisisprobablythemostcommonwayofaccessinganelement.YoujustassignIDstotheelementsyouplantoplay withandthey'llbeeasytoaccesslateron,asseeninthefollowingcode:

>document.getElementById('closer');<pid="closer">final</p>

Additionalshortcutmethodsinmorerecentbrowsersincludethefollowing:

getElementByClassName():ThismethodfindselementsusingtheirclassattributequerySelector():ThismethodfindsanelementusingaCSSselectorstringquerySelectorAll():Thismethodisthesameasthepreviousonebutreturnsallmatchingelements,notjustthefirst

Siblings,body,first, andlastchild

ThenextSiblingandpreviousSiblingaretwootherconvenientpropertiestonavigatetheDOMtreeonceyouhaveareferencetooneelement.Considerthefollowingcode:

> var para = document.getElementById('closer');>para.nextSibling;#text>para.previousSibling;#text>para.previousSibling.previousSibling;<p>...</p>>para.previousSibling.previousSibling.previousSibling;#text>para.previousSibling.previousSibling.nextSibling.nextSibling;<pid="closer">final</p>

Thebodyelementisusedsooftenthatithasitsownshortcut,whichisasfollows:

>document.body;<body>...</body>>document.body.nextSibling;null>document.body.previousSibling.previousSibling;<head>...</head>

ThefirstChildandlastChildpropertiesarealsoconvenient.ThefirstChildpropertyisthesameaschildNodes[0]andlastChildisthesameaschildNodes[childNodes.length-

Page 389: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

1]properties:

>document.body.firstChild;#text>document.body.lastChild;#text>document.body.lastChild.previousSibling;<!--andthat'saboutit-->>document.body.lastChild.previousSibling.nodeValue;

" and that's about it "

Thefollowingscreenshotshowsthefamilyrelationshipsbetweenthebodyandthethreeparagraphsinit.Forsimplicity,allthewhitespacetextnodesareremovedfromthescreenshot:

WalktheDOM

Towrapup,here'safunctionthattakesanynodeandwalksthroughtheDOMtreerecursively,startingfromthegivennode,asfollows:

functionwalkDOM(n){do{console.log(n);if(n.hasChildNodes()){walkDOM(n.firstChild);}}while(n=n.nextSibling);}

Youcantestthefunctionasfollows:

Page 390: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>walkDOM(document.documentElement);>walkDOM(document.body);

Page 391: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ModifyingDOMnodes

NowthatyouknowawholelotofmethodstoaccessanynodeoftheDOMtreeanditsproperties,let'sseehowyoucanmodifythesenodes:

Let'sassignapointertothelastparagraphtothevariablemy,asfollows:

>varmy=document.getElementById('closer');

Now,changingthetextoftheparagraphcanbeaseasyaschangingtheinnerHTMLvalue,whichisasfollows:

>my.innerHTML='final!!!';"final!!!"

AsinnerHTMLacceptsastringofHTMLsourcecode,youcanalsocreateanewemnodeintheDOMtreeasfollows:

>my.innerHTML='<em>my</em>final';"<em>my</em>final"

Thenewemnodebecomesapartofthetree.Letstakealookatthefollowingcode:

>my.firstChild;<em>my</em>>my.firstChild.firstChild;"my"

AnotherwaytochangetextistogettheactualtextnodeandchangeitsnodeValue,asshowninthefollowingpieceofcode:

>my.firstChild.firstChild.nodeValue='your';"your"

Modifyingstyles

Oftenyoudon'tchangethecontentofanode,butitspresentation.Theelementshaveastyleproperty,whichinturnhasapropertymappedtoeachCSSproperty.Forexample,changingthestyleoftheparagraphtoaddaredborder,asfollows:

>my.style.border="1pxsolidred";"1pxsolidred"

CSSpropertiesoftenhavedashes,butdashesarenotacceptableinJavaScriptidentifiers.Insuchcases,youskipthedashanduppercasethenextletter.So,padding-topbecomespaddingTop,margin-leftbecomesmarginLeft,andsoon.Takealookatthefollowingcode:

>my.style.fontWeight='bold';

Page 392: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"bold"

YoualsohaveaccesstothecssTextpropertyofstyle,whichletsyouworkwithstylesasstrings,asyoucanseeinthefollowingcodesnippet:

>my.style.cssText;"border:1pxsolidred;font-weight:bold;"

Moreover,modifyingstylesisastringmanipulation:

>my.style.cssText+="border-style:dashed;""border:1pxdashedred;font-weight:bold;border-style:dashed;"

Funwithforms

Asmentionedearlier,JavaScriptisgreatforclient-sideinputvalidationandcansaveafewround-triptotheserver.Let'spracticeformmanipulationsandplayalittlebitwithaformlocatedonapopularpage,www.google.com:

FindingthefirsttextinputusingthequerySelector()methodandaCSSselectorstringisasfollows:

>varinput=document.querySelector('input[type=text]');

Accessingthesearchbox.Considerthefollowingcode:

>input.name;"q"

Changingthesearchquerybysettingthetextcontainedinthevalueattributeisdoneasfollows:

> input.value = 'my query';"myquery"

Now,let'shavesomefunandchangethewordLuckywithTrickyinthebutton:

>varfeeling=document.querySelectorAll("button")[2];>feeling.textContent=feelingtextContent.replace(/Lu/,'Tri');"I'mFeelingTricky"

Page 393: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Now,let'simplementthetrickypartandmakethatbuttonshowandhideforonesecond.Youcandothiswithasimplefunction.Let'scallittoggle().Everytimeyoucallthefunction,itchecksthevalueoftheCSSpropertyvisibility,andsetsittovisibleifit'shiddenandviceversausingthefollowingcodesnippet:

functiontoggle(){varst=document.querySelectorAll('button')[2].style;st.visibility=(st.visibility==='hidden')?'visible'

: 'hidden';}

Insteadofcallingthefunctionmanually,let'ssetanintervalandcalliteverysecond:

>varmyint=setInterval(toggle,1000);

Theresult?Thebuttonstartsblinking,makingittrickiertoclick.Whenyou'retiredofchasingit,justremovethetimeoutintervalbywritingthefollowinglineofcode:

>clearInterval(myint);

Page 394: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Creatingnewnodes

Tocreatenewnodes,youcanusethecreateElement()andcreateTextNode()methods.Onceyouhavethenewnodes,youcanaddthemtotheDOMtreeusingappendChild(),insertBefore(),orreplaceChild().

Reloadhttp://www.phpied.com/files/jsoop/ch7.htmlandlet'splay.

CreateanewpelementandsetitsinnerHTML,asshowninthefollowingcode:

>varmyp=document.createElement('p');>myp.innerHTML='yetanother';"yetanother"

Thenewelementautomaticallygetsallthedefaultproperties,suchasstyle,whichyoucanmodifyasfollows:

>myp.style;CSSStyleDeclaration>myp.style.border='2pxdottedblue';"2pxdottedblue"

UsingappendChild(),youcanaddthenewnodetotheDOMtree.Callingthismethodonthedocument.bodynodemeanscreatingonemorechildnoderightafterthelastchild,asfollows:

>document.body.appendChild(myp);<pstyle="border:2pxdottedblue;">yetanother</p>

Here'sanillustrationofhowthepagelookslikeafterthenewnodeisappended:

DOM-onlymethod

TheinnerHTMLpropertygetsthingsdonealittlemorequicklythanusingpureDOM.InpureDOM,youwillneedtoperformthefollowingsteps:

1. Createanewtextnodecontainingyetanothertext.

Page 395: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

2. Createanewparagraphnode.3. Appendthetextnodeasachildtotheparagraph.4. Appendtheparagraphasachildtothebody.

Thisway,youcancreateanynumberoftextnodesandelementsandnestthem,howeveryoulike.Let'ssay,youwanttoaddthefollowingHTMLtotheendofthebody:

<p>onemoreparagraph<strong>bold</strong></p>

Presentingthepreceding codeasahierarchywouldbesomethinglikethefollowingcodesnippet:

Pelementtextnodewithvalue"onemoreparagraph"STRONGelementtextnodewithvalue"bold"

Thecodethataccomplishesthisisasfollows:

//createPvarmyp=document.createElement('p');

// create text node and append to Pvarmyt=document.createTextNode('onemoreparagraph');myp.appendChild(myt);//createSTRONGandappendanothertextnodetoitvarstr=document.createElement('strong');str.appendChild(document.createTextNode('bold'));//appendSTRONGtoPmyp.appendChild(str);//appendPtoBODYdocument.body.appendChild(myp);

UsingcloneNode()method

Anotherwaytocreatenodesisbycopyingorcloningexistingones.ThecloneNode()methoddoesthisandacceptsaBooleanparameter(true=deepcopywithallthechildren,false=shallowcopy,onlythisnode).Let'stestthemethod.

Gettingareferencetotheelementyouwanttoclonecanbedoneasfollows:

>varel=document.getElementsByTagName('p')[1];

Now,elreferstothesecondparagraphonthepagethatlookslikethefollowingcode:

<p><em>second</em>paragraph</p>

Let'screateashallowcloneofelandappendittothebodyasfollows:

>document.body.appendChild(el.cloneNode(false));

Page 396: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Youwon'tseeadifferenceonthepagebecausetheshallowcopyonlycopiedthePnodewithoutanychildren.Thismeansthatthetextinsidetheparagraph,whichisatext nodechild,wasnotcloned.Theprecedinglinewillbeequivalenttothefollowingcodeline:

>document.body.appendChild(document.createElement('p'));

However,ifyoucreateadeepcopy,thewholeDOMsubtreestartingfromPiscopied,andthisincludestextnodesandtheEMelement.Thislinecopies(visuallytoo)the secondparagraphtotheendofthedocument.Considerthefollowinglineofcode:

>document.body.appendChild(el.cloneNode(true));

YoucanalsocopyonlytheEMifyouwant,asshowninthefollowinglinesofcode:

>document.body.appendChild(el.firstChild.cloneNode(true));<em>second</em>

Or,youcancopyonlythetextnodewithvaluesecond,asfollows:

>document.body.appendChild(el.firstChild.firstChild.cloneNode(false));"second"

UsinginsertBefore()method

UsingappendChild(),youcanonlyaddnewchildrenattheendoftheselectedelement.Formorecontrolovertheexactlocation,thereisinsertBefore().ThisisthesameasappendChild(),butacceptsanextraparameterspecifyingwhere(beforewhichelement)toinsertthenewnode.Forexample,thefollowingcodeinsertsatextnodeattheendofthebodyelement:

>document.body.appendChild(document.createTextNode('boo!'));

Moreover,thiscreatesanothertextnodeandaddsitasthefirstchildofthebodyelement:

document.body.insertBefore(document.createTextNode('firstboo!'),document.body.firstChild);

Page 397: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Removingnodes

ToremovenodesfromtheDOMtree,youcanusetheremoveChild()method.Again,let'sstartfreshwiththesamepagewiththebody:

<body><pclass="opener">firstparagraph</p><p><em>second</em>paragraph</p><pid="closer">final</p><!--andthat'saboutit--></body>

Here'showyoucanremovethesecondparagraph:

>varmyp=document.getElementsByTagName('p')[1];>varremoved=document.body.removeChild(myp);

Themethodreturnstheremovednodeifyouwanttouseitlater.YoucanstillusealltheDOMmethodseventhoughtheelementisnolongerinthetree.Letstakealookonthefollowingcode:

>removed;<p>...</p>>removed.firstChild;<em>second</em>

There'salsothereplaceChild()methodthatremovesanodeandputsanotheroneinitsplace.

Afterremovingthenode,thetreelooksasfollows:

<body><pclass="opener">firstparagraph</p><pid="closer">final</p><!--andthat'saboutit--></body>

Now,thesecondparagraphistheonewiththeID"closer",whichisasfollows:

>varp=document.getElementsByTagName('p')[1];>p;<pid="closer">final</p>

Let'sreplacethisparagraphwiththeoneintheremovedvariable.Considerthefollowingcode:

>varreplaced=document.body.replaceChild(removed,p);

JustlikeremoveChild(),replaceChild()returnsareferencetothenodethatisnowoutofthetree:

>replaced;<pid="closer">final</p>

Page 398: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Now,thebodylookslikethefollowingpieceofcode:

<body><pclass="opener">firstparagraph</p><p><em>second</em>paragraph</p><!--andthat'saboutit--></body>

Aquickwaytowipeout allofthecontentofasubtreeistosetinnerHTMLtoablankstring.Thisremovesallthechildrenofthebodyelement:

>document.body.innerHTML='';""

Testingisdoneasfollows:

>document.body.firstChild;null

RemovingwithinnerHTMLisfastandeasy.TheDOM-onlywaywillbetogooverallofthechildnodesandremoveeachoneindividually.Here'salittlefunctionthatremovesallnodesfromagivenstartnode:

functionremoveAll(n){while(n.firstChild){n.removeChild(n.firstChild);}}

Ifyouwanttodeleteallthechildrenfromthebodyelementandleavethepagewithanempty<body></body>,usethefollowingcode:

>removeAll(document.body);

Page 399: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

HTML-onlyDOMobjects

Asyoualreadyknow,theDOMappliestobothXMLandHTMLdocuments.Whatyou'velearnedearlierabouttraversingthetreeandthenadding,removing,ormodifyingnodes,appliestoanyXMLdocument.Thereare,however,someHTML-onlyobjectsandproperties.

Thedocument.bodyisonesuchHTML-onlyobject.It'ssocommontohavea<body>taginHTMLdocuments,andit'saccessedsooften,thatitmakessensetohaveanobjectthat'sshorterandfriendlierthantheequivalentdocument.getElementsByTagName('body')[0].

Thedocument.bodyelementisoneexampleofalegacyobjectinheritedfromtheprehistoricDOMLevel0andmovedtotheHTMLextension oftheDOMspecification.Thereareotherobjectssimilartodocument.bodyelement.Forsomeofthem,thereisnocoreDOMequivalent,forothers,thereisanequivalent;however,theDOM0originalwasanywayportedforsimplicityand legacy purposes. Let's see some of those objects.

Primitivewaystoaccessthedocument

totheelementsofanHTMLdocument.Thiswasdonemainlythroughanumberofcollections,whichareasfollows:UnliketheDOM,whichgivesyouaccesstoanyelement,andevencommentsandwhitespace,initially,JavaScripthadonlylimitedaccesstotheelementsofanHTMLdocument.Thiswasdonemainlythroughanumberofcollections,whichareasfollows:

document.images:Thisisacollectionofalloftheimagesonthepage.TheCoreDOMequivalentisdocument.getElementsByTagName('img').document.applets:Thisisthesameasdocument.getElementsByTagName('applet').document.links:Thedocument.linkscollectioncontainsalistofall<ahref="..."></a>tagsonthepage,meaningthe<a>tagsthathaveanhrefattribute.document.anchors:Thedocument.anchorscollectioncontainsalllinkswithanameattribute(<aname="..."></a>).document.forms:Oneofthemostwidelyusedcollectionsisdocument.forms,whichcontainsalistof<form>elements.

Let'splaywithapagethatcontainsaformandaninput(http://www.phpied.com/files/jsoop/ch7-form.html).Thefollowinglineofcodegivesyouaccesstothefirstformonthepage:

>document.forms[0];

It'sthesameasthefollowinglineofcode:

>document.getElementsByTagName('forms')[0];

Thedocument.formscollectioncontainscollectionsofinputfieldsandbuttons,accessiblethroughtheelementsproperty.Here'showtoaccessthefirstinputofthefirstformonthepage:

Page 400: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>document.forms[0].elements[0];

Onceyouhaveaccessto anelement,youcanaccessitsattributesasobjectproperties.Thefirstfieldofthefirstforminthetestpageisasfollows:

<inputname="search"id="search"type="text"size="50"maxlength="255"value="Enteremail..."/>

Youcanchangethetextinthefield(thevalueofthevalueattribute)usingthefollowingcode:

>document.forms[0].elements[0].value='[email protected]';"[email protected]"

Ifyouwanttodisablethefielddynamically,usethefollowingcode:

>document.forms[0].elements[0].disabled=true;

Whenformsorformelementshaveanameattribute,youcanaccessthembynametoo,asshowninthefollowingcode:

>document.forms[0].elements['search'];//arraynotation>document.forms[0].elements.search;//objectproperty

Usingdocument.write()method

Thedocument.write()methodallowsyoutoinsertHTMLintothepagewhilethepageisbeingloaded.Youcanhavesomethinglikethefollowingcode:

<p>Itisnow<script>document.write("<em>"+newDate()+"</em>");</script></p>

ThisisthesameasifyouhadthedatedirectlyinthesourceoftheHTMLdocument,asfollows:

<p>Itisnow<em>FriApr26201316:55:16GMT-0700(PDT)</em></p>

Notethatyoucanonlyusedocument.write()methodwhilethepageisbeingloaded.Ifyoutryitafterpageload,itwill replacethecontentofthewholepage.

It'srarethatyouwouldneeddocument.write()method,andifyouthinkyoudo,tryanalternativeapproach.ThewaystomodifythecontentsofthepageprovidedbyDOMLevel1arepreferredandaremuchmoreflexible.

Cookies,title,referrer,anddomain

Thefouradditionalpropertiesofdocumentyou'llseeinthissectionarealsoportedfromDOM

Page 401: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Level0totheHTMLextensionofDOMLevel1. Unlikethepreviousones,fortheseproperties,therearenocoreDOMequivalents.

The document.cookie is a property that contains a string. This string is the content of thecookies exchanged between the server and the client. When the server sends a page to thebrowser,itmayincludetheSet-CookieHTTPheader.Whentheclientsendsarequesttotheserver,itsendsthecookieinformationbackwiththeCookieheader.Usingdocument.cookie,youcanalterthecookiesthebrowsersendstotheserver.Forexample,visitingcnn.comandtypingdocument.cookieintheconsolegivesyouthefollowingoutput:

>document.cookie;"mbox=check#true#1356053765|session#1356053704195-121286#1356055565;...

Thedocument.titlepropertyallowsyoutochangethetitleofthepagedisplayedinthebrowserwindow.Forexample,seethefollowingcode:

>document.title='Mytitle';"Mytitle"

Notethatthisdoesn'tchangethevalueofthe<title>element,butonlythedisplayinthebrowserwindow,soit'snotequivalenttodocument.querySelector('title').

Thedocument.referrerpropertytellsyoutheURLofthepreviouslyvisitedpage.ThisisthesamevaluethebrowsersendsintheRefererHTTPheaderwhenrequestingthepage.(NotethatRefererismisspelledintheHTTPheaders,butiscorrectinJavaScript'sdocument.referrer).Ifyou'vevisitedtheCNNpagebysearchingonYahoofirst,youcanseesomethinglikethefollowing:

>document.referrer;"http://search.yahoo.com/search?p=cnn&ei=UTF-8&fr=moz2"

Thedocument.domainpropertygivesyouaccesstothedomainnameofthecurrentlyloadedpage.Thisiscommonlyusedwhenyouneedtoperformso-calleddomainrelaxation.Imagineyourpageiswww.yahoo.com,andinsideit,youhaveaniframehostedonmusic.yahoo.comsubdomain.Thesearetwoseparatedomains,sothebrowser'ssecurityrestrictionswon'tallowthepageandtheiframetocommunicate.Toresolvethis,youcansetdocument.domainpropertyonbothpagestoyahoo.comandthey'llbeabletotalktoeachother.

Notethatyoucanonlysetthedomaintoalessspecificone,forexample,youcanchangewww.yahoo.comtoyahoo.com,butyoucannotchangeyahoo.comtowww.yahoo.com,oranyothernon-yahoodomain.Considerthefollowingcode:

>document.domain;"www.yahoo.com">document.domain='yahoo.com';"yahoo.com"

Page 402: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>document.domain='www.yahoo.com';Error:SecurityError:DOMException18>document.domain='www.example.org';Error:SecurityError:DOMException18

Previously,inthischapter,yousawthewindow.locationobject.Well,thesamefunctionalityisalsoavailableasdocument.locationobject:

>window.location===document.location;true

Page 403: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

EventsImagine you are listening to a radio program and they announce, "Big event! Huge! Aliens havelandedonEarth!"Youmightthink,"Yeah,whatever";someotherlistenersmightthink"Theycomeinpeace";andsomemightthink,"We'reallgonnadie!".Similarly,thebrowserbroadcastsevents,andyourcodecanbenotifiedshoulditdecidetotuneinandlistentotheeventsastheyhappen.Someexampleeventsareasfollows:

TheuserclicksabuttonTheusertypesacharacterinaformfieldThepagefinishesloading

YoucanattachaJavaScriptfunctioncalledevent listeneroreventhandlertoaspecificeventandthebrowserwillinvokeyourfunctionassoonastheeventoccurs.Let'sseehowthisisdone.

Page 404: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

InlineHTMLattributes

Addingspecificattributestoatagisthelaziestbuttheleastmaintainableway;takethefollowinglineofcodeasanexample:

<divonclick="alert('Ouch!')">click</div>

Inthiscase,whentheuserclickson<div>,theclickeventfiresandthestringofJavaScriptcodecontainedintheonclickattributeisexecuted.There'snoexplicitfunctionthatlistenstotheclickevent;however,behindthescenes,afunctionisstillcreated,anditcontainsthecodeyouspecifiedasavalueoftheonclickattribute.

Page 405: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ElementProperties

AnotherwaytohavesomecodeexecutedwhenaclickeventfiresistoassignafunctiontotheonclickpropertyofaDOMnodeelement.Forexample,takealookatthefollowingpieceofcode:

<divid="my-div">click</div><script>varmyelement=document.getElementById('my-div');myelement.onclick=function(){

alert('Ouch!');alert('Anddoubleouch!');};</script>

Thiswayisbetterbecauseithelpsyoukeepyour<div>tagcleanofanyJavaScriptcode.AlwayskeepinmindthatHTMLisforcontent,JavaScriptforbehavior,andCSSforformatting,andyoushouldkeepthesethreeseparateasmuchaspossible.

Thismethodhasthedrawbackthatyoucanattachonlyonefunctiontotheevent,asiftheradioprogramhasonlyonelistener.It'struethatyoucanhavealothappeninginsidethesamefunction,butthisisnotalwaysconvenient,asifalltheradiolistenersareinthesameroom.

Page 406: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

DOMeventlisteners

ThebestwaytoworkwithbrowsereventsistousetheeventlistenerapproachoutlinedinDOMLevel2,whereyoucanhavemanyfunctionslisteningtoanevent.Whenaneventfires,allthefunctionsareexecuted.Allofthelistenersdon'tneedtoknowabouteachotherandcanworkindependently.Theycantuneinandoutatanytime,withoutaffectingtheotherlisteners.

Let'susethesamesimplemarkupfromtheprevioussection,whichisavailableforyoutoplaywithathttp://www.phpied.com/files/jsoop/ch7.html.Ithasthispieceofmarkup,whichisasfollows:

<pid="closer">final</p>

YourJavaScriptcodecanassignlistenerstotheclickeventusingtheaddEventListener()method.Let'sattachtwolistenersasfollows:

varmypara=document.getElementById('closer');mypara.addEventListener('click',function(){alert('Boo!');

}, false);mypara.addEventListener('click',console.log.bind(console),false);

Asyoucansee,addEventListeners

Page 407: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Capturingandbubbling

InthecallstoaddEventListener(),therewasathirdparameter-false. Let'sseewhatitisfor.

Let'ssayyouhavealinkinsideanunorderedlist,whichisasfollows:

<body><ul><li><ahref="http://phpied.com">myblog</a></li></ul></body>

Whenyouclickonthelink,you'reactuallyalsoclickingonthelistitem,<li>,the<ul>list,the<body>tag,andeventually,thedocumentasawhole.Thisiscalledevent propagation.Aclickonalinkcanalsobeseenasaclickonthedocument.Theprocessofpropagatinganeventcanbeimplementedinthetwofollowingways:

Eventcapturing:Thisclickhappensinthedocumentfirst,thenitpropagatesdowntothebody,thelist,thelistitem,andfinally,tothelinkEventbubbling:Thisclickhappensonthelinkandthenbubblesuptothedocument

DOMlevel2eventsspecificationsuggeststhattheeventspropagateinthreephases,namely,capturing,attarget,andbubbling.Thismeansthattheeventpropagatesfromthedocumenttothelink(target)andthenbubblesbackuptothedocument.TheeventobjectshaveaneventPhaseproperty,whichreflectsthecurrentphase:

Page 408: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Historically, IE and Netscape (working on their own and without a standard to follow)implementedtheexactopposites.IEimplementedonlybubblingandNetscapeonlycapturing.Today,longaftertheDOMspecification,modernbrowsersimplementall threephases.

Page 409: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thepracticalimplicationsrelatedtotheeventpropagationareasfollows:

ThethirdparametertoaddEventListener()specifieswhetherornotcapturingshouldbeused.Inordertohaveyourcodemoreportableacrossbrowsers,it'sbettertoalwayssetthisparametertofalseandusebubblingonly.Youcanstopthepropagationoftheeventinyourlistenerssothatitstopsbubblingupandneverreachesthedocument.Todothis,youcancallthestopPropagation()methodoftheeventobject;thereisanexampleinthenextsection.Youcanalsouseeventdelegation.Ifyouhavetenbuttonsinside<div>,youcanalwaysattachteneventlisteners,oneforeachbutton.However,asmarterthingtodoistoattachonlyonelistenertothewrapping<div>andoncetheeventhappens,checkwhichbuttonwasthetargetoftheclick.

Asasidenote,thereisawaytouseeventcapturinginoldIEstoo(usingsetCapture()andreleaseCapture()methods)butonlyformouseevents.Capturinganyotherevents(keystrokeeventsforexample)isnotsupported.

Page 410: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Stoppropagation

Let'sseeanexampleofhowyoucanstoptheeventfrombubblingup.Goingbacktothetestdocument,thereisthispieceofcode:

<pid="closer">final</p>

Let'sdefineafunctionthathandlesclicksontheparagraph,asfollows:

functionparaHandler(){alert('clickedparagraph');}

Now,let'sattachthisfunctionasalistenertotheclickevent:

varpara=document.getElementById('closer');para.addEventListener('click',paraHandler,false);

Let'salsoattachlistenerstotheclickeventonthebody,thedocument,andthebrowserwindow:

document.body.addEventListener('click',function(){alert('clickedbody');},false);

document.addEventListener('click', function () {alert('clickeddoc');},false);window.addEventListener('click',function(){alert('clickedwindow');},false);

NotethattheDOMspecificationsdon'tsayanythingabouteventsonthewindow.Andwhywouldthey,asDOMdealswiththedocumentandnotthebrowser.Sobrowsersimplementwindoweventsinconsistently.

Now,ifyouclickontheparagraph,you'llseefouralertssaying:

clickedparagraphclickedbodyclickeddocclickedwindow

Thisillustrateshowthesamesingleclickeventpropagates(bubblesup)fromthetargetallthewayuptothewindow.

The opposite of addEventLister() is removeEventListener(), and it accepts exactly thesame parameters. Let's remove the listener attached to the paragraph by writing the following lineofcode:

Page 411: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>para.removeEventListener('click',paraHandler,false);

Ifyoutrynow,you'llseealertsonlyfortheclickeventonthebody,document,andwindow,butnotontheparagraph.

Now,let'sstopthepropagationoftheevent.Thefunctionyouaddasalistenerreceivestheeventobjectasaparameter,andyoucancallthestopPropagation()methodofthateventobjectasfollows:

functionparaHandler(e){alert('clickedparagraph');e.stopPropagation();}

Addingthemodifiedlistenerisdoneasfollows:

para.addEventListener('click',paraHandler,false);

Now,whenyouclickontheparagraph,youwillseeonlyonealertbecausetheeventdoesn'tbubbleuptothebody,thedocument,orthewindow.

Notethatwhenyouremovealistener,youhavetopassapointertothesamefunctionyoupreviouslyattached.Otherwise,doingthefollowingdoesnotworkbecausethesecondargumentisanewfunction,notthesameyoupassedwhenaddingtheeventlistener,evenifthebodyisexactlythesame.Considerthefollowingcode:

document.body.removeEventListener('click',function(){alert('clickedbody');},false);//doesNOTremovethehandler

Page 412: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Preventdefaultbehavior

Somebrowsereventshaveapredefinedbehavior.Forexample,clickingalinkcausesthebrowsertonavigatetoanotherpage.Youcanattachlistenerstoclicksonalink,andyoucanalsodisablethedefaultbehaviorbycallingthepreventDefault()methodontheeventobject.

Let'sseehowyoucanannoyyourvisitorsbyasking"Areyousureyouwanttofollowthislink?"everytimetheyclickalink?IftheuserclicksonCancel(causingconfirm()toreturnfalse),thepreventDefault()methodiscalled,whichisshownasfollows:

//alllinksvarall_links=document.getElementsByTagName('a');for(vari=0;i<all_links.length;i++){//loopalllinks

all_links[i].addEventListener('click',//eventtypefunction(e){//handlerif(!confirm('Sureyouwanttofollowthislink?')){e.preventDefault();}},false//don'tusecapturing);}

Notethatnotalleventsallowyoutopreventthedefaultbehavior.Mostdo,butifyouwanttobesure,youcancheckthecancellablepropertyoftheeventobject.

Page 413: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Cross-browsereventlisteners

Asyoualreadyknow,mostmodernbrowsersalmostfullyimplementtheDOMLevel1specification.However,theeventswerenotstandardizeduntilDOM2.Asaresult,therearequiteafewdifferencesinhowIE,beforeversion9,implementsthisfunctionalitycomparedtomodernbrowsers.

CheckoutanexamplethatcausesnodeNameofaclickedelement(thetargetelement)tobewrittentotheconsole:

document.addEventListener('click',function(e){console.log(e.target.nodeName);},false);

Now,let'stakealookathowIEisdifferent:

InIE,there'snoaddEventListener()method;although,sinceIEVersion5,thereisanequivalentattachEvent()method.Forearlierversions,youronlychoiceisaccessingthepropertydirectly,suchasonclick.TheclickeventbecomesonclickwhenusingattachEvent().Ifyoulistentoeventstheoldfashionedway (forexample,bysettingafunctionvaluetotheonclickproperty),whenthecallbackfunctionisinvoked,itdoesn'tgetaneventobjectpassedasaparameter.However,regardlessofhowyouattachthelistenerinIE,thereisalwaysaglobalobjectwindow.eventthatpointstothelatestevent.InIE,theeventobjectdoesn'tgetatargetattributetellingyoutheelementonwhichtheeventfired,butitdoeshaveanequivalentpropertycalledsrcElement.Asmentionedearlier,eventcapturingdoesn'tapplytoallevents,soonlybubblingshouldbeused.There'snostopPropagation()method,butyoucansettheIE-onlycancelBubblepropertytotrue.There'snopreventDefault()method,butyoucansettheIE-onlyreturnValuepropertytofalse.Tostoplisteningtoanevent,insteadofremoveEventListener()inIE,you'llneeddetachEvent().

So,here'stherevisedversionofthepreviouscodethatworksacrossbrowsers:

functioncallback(evt){//prepworkevt=evt||window.event;vartarget=evt.target||evt.srcElement;

//actualcallbackworkconsole.log(target.nodeName);}

Page 414: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

//startlisteningforclickeventsif(document.addEventListener){//Modernbrowsersdocument.addEventListener('click',callback,false);}elseif(document.attachEvent){//oldIEdocument.attachEvent('onclick',callback);}else{document.onclick=callback;//ancient}

Page 415: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Typesofevents

Nowyouknowhowtohandlecross-browserevents.However,alloftheprecedingexamplesusedonlyclickevents.Whatothereventsarehappeningoutthere?Asyoucanprobablyguess,differentbrowsersprovidedifferentevents.Thereisasubsetofcross-browserevents,andsomebrowser-specificones.Forafulllistofevents,youshouldconsultthebrowser'sdocumentation,buthere'saselectionofcross-browserevents:

Mouseeventsmouseup,mousedown,click(thesequenceismousedown-up-click),dblclickmouseover(mouseisoveranelement),mouseout(mousewasoveranelementbutleftit),mousemove

Keyboardeventskeydown,keypress,keyup(occurinthissequence)

Loading/windoweventsload(animageorapageandallofitscomponentsaredoneloading),unload(userleavesthepage),beforeunload(thescriptcanprovidetheuserwithanoptiontostoptheunload)abort(userstopsloadingthepageoranimageinIE),error(aJavaScripterror,alsowhenanimagecannotbeloadedinIE)resize(thebrowserwindowisresized),scroll(thepageisscrolled),contextmenu(theright-clickmenuappears)

Form eventsfocus(enteraformfield),blur(leavetheformfield)change(leaveafieldafterthevaluehaschanged),select(selecttextinatextfield)reset(wipeoutalluserinput),submit(sendtheform)

Additionally,modernbrowsersprovidedragevents(dragstart,dragend,drop,andamongothers)andtouchdevicesprovidetouchstart,touchmove,andtouchend.

Thisconcludesthediscussionofevents.Refertotheexercisesectionattheendofthischapterforalittlechallengeofcreatingyourowneventutilitytohandlecross-browserevents.

Page 416: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

XMLHttpRequestXMLHttpRequest() is an object (a constructor function) that allows you to send HTTP requestsfrom JavaScript. Historically, XHR (XMLHttpRequest) was introduced in IE and wasimplemented as an ActiveX object. Starting with IE7, it's a native browser object, the same wayasit'sintheotherbrowsers.Thecommonimplementationofthisobjectacrossbrowsersgavebirthtotheso-calledAjaxapplications,whereit'snolongernecessarytorefreshthewholepageeverytimeyouneednewcontent.WithJavaScript,youcanmakeanHTTPrequesttotheserver,gettheresponse,andupdateonlyapartofthepage.Thisway,youcanbuildmuchmoreresponsiveanddesktop-likewebpages.

AjaxstandsforAsynchronousJavaScriptandXML:

Asynchronousbecause,aftersendinganHTTPrequest,yourcodedoesn'tneedtowaitfortheresponse;however,itcandootherstuffandbenotified,throughanevent,whentheresponsearrives.JavaScriptbecauseit'sobviousthatXHRobjectsarecreatedwithJavaScript.XMLbecauseinitiallydevelopersweremakingHTTPrequestsforXMLdocumentsandwereusingthedatacontainedinthemtoupdatethepage.Thisisnolongeracommonpractice,though,asyoucanrequestdatainplaintext,inthemuchmoreconvenientJSONformat,orsimplyasHTMLreadytobeinsertedintothepage.

TherearetwostepstousingtheXMLHttpRequestobject,whichareasfollows:

Sendtherequest:ThisincludescreatinganXMLHttpRequestobjectandattachinganeventlistenerProcesstheresponse:Thishappenswhenyoureventlistenergetsnotifiedthattheresponsehasarrived,andyourcodegetsbusydoingsomethingamazingwiththeresponse

Page 417: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Sendingtherequest

Inordertocreateanobject,youwillsimplyusethefollowingcode(let'sdealwithbrowserinconsistenciesinjustabit):

varxhr=newXMLHttpRequest();

Thenextthingistoattachaneventlistenertothereadystatechangeeventfiredbytheobject:

xhr.onreadystatechange=myCallback;

Then,youwillneedtocalltheopen()method,asfollows:

xhr.open('GET','somefile.txt',true);

ThefirstparameterspecifiesthetypeofHTTPrequest,suchasGET,POST,HEAD,andsoon.GETandPOSTarethemostcommonones.UseGETwhenyoudon'tneedtosendmuchdatawiththerequestandyourrequestdoesn'tmodify(write)dataontheserver,otherwise,usePOST.ThesecondparameteristheURLyouarerequesting.Inthisexample,it'sthetextfilesomefile.txtlocatedinthesamedirectoryasthepage.ThelastparameterisaBooleanspecifyingwhethertherequestisasynchronous(true,alwayspreferthis)ornot(false,blocksalltheJavaScriptexecutionandwaitsuntiltheresponsearrives).

Thelaststepistofireofftherequest,whichisdoneasfollows:

xhr.send('');

Thesend()methodacceptsanydatayouwanttosendwiththerequest.ForGETrequests,thisisanemptystringbecausethedataisintheURL.ForPOSTrequest,it'saquerystringinthekey=value&key2=value2form.

Atthispoint,therequestissentandyourcodeandtheusercanmoveontoothertasks.Thecallbackfunction,myCallback,willbeinvokedwhentheresponsecomesbackfromtheserver.

Page 418: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Processingtheresponse

Alistenerisattachedtothereadystatechangeevent.So,whatexactlyisthereadystateandhowdoesitchange?

ThereisapropertyoftheXHRobjectcalledreadyState.Everytimeitchanges,thereadystatechangeeventfires.ThepossiblevaluesofthereadyStatepropertyareasfollows:

0-uninitialized1-loading2-loaded3-interactive4-complete

WhenreadyStategetsthevalueof4,itmeanstheresponseisbackandreadytobeprocessed.InmyCallback,afteryoumakesurereadyStateis4,theotherthingtocheckisthestatuscodeoftheHTTPrequest.Youmighthaverequestedanon-existingURL,forexample,andgota404(Filenotfound)statuscode.Theinterestingcode isthe200(OK)code,somyCallbackshouldcheckforthisvalue.ThestatuscodeisavailableinthestatuspropertyoftheXHRobject.

Oncexhr.readyStateis4andxhr.statusis200,youcanaccessthecontentsoftherequestedURLusingthexhr.responseTextproperty.Let'sseehowmyCallbackcanbeimplementedtosimplyalert()thecontentsoftherequestedURL:

functionmyCallback(){

if(xhr.readyState<4){return;//notreadyyet}if(xhr.status!==200){alert('Error!');//theHTTPstatuscodeisnotOKreturn;}

//allisfine,dotheworkalert(xhr.responseText);}

Onceyou'vereceivedthenewcontentyourequested,youcanaddittothepage,useitforsomecalculations,orforanyotherpurposeyoufindsuitable.

Overall, this two-step process (send request and process response) is the core of the wholeXHR/Ajaxfunctionality.Nowthatyouknowthebasics,youcanmoveontobuildingthenextGmail.Ohyes,let'stakealookatsomeminorbrowserinconsistencies.

Page 419: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

CreatingXMLHttpRequestobjectsinIEpriortoVersion7

InInternetExplorer,priortoversion7,theXMLHttpRequestobjectwasanActiveXobject,socreatinganXHRinstanceisalittledifferent.Itgoesasfollows:

varxhr=newActiveXObject('MSXML2.XMLHTTP.3.0');

MSXML2.XMLHTTP.3.0istheidentifieroftheobjectyouwanttocreate.ThereareseveralversionsoftheXMLHttpRequestobject,andifyourpagevisitordoesn'thavethelatestoneinstalled,youcantrytwoolderonesbeforeyougiveup.

Forafully-cross-browsersolution,youshouldfirsttesttoseeiftheuser'sbrowsersupportsXMLHttpRequestasanativeobject,andifnot,trytheIEway.Therefore, thewholeprocessofcreatinganXHRinstancecouldbelikethefollowing:

varids=['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'];varxhr;if(XMLHttpRequest){

xhr = new XMLHttpRequest();}else{//IE:trytofindanActiveXobjecttousefor(vari=0;i<ids.length;i++){try{xhr=newActiveXObject(ids[i]);break;}catch(e){}}}

Whatisthisdoing?TheidsarraycontainsalistofActiveXprogramIDstotry.ThexhrvariablepointstothenewXHRobject.ThecodefirstcheckstoseeifXMLHttpRequestexists.Ifso,thismeansthatthebrowsersupportsXMLHttpRequest()natively,sothebrowserisrelativelymodern.Ifitisnot,thecodeloopsthroughidstryingtocreateanobject.Thecatch(e)blockquietlyignoresfailuresandtheloopcontinues.Assoonasanxhrobjectiscreated,youbreakoutoftheloop.

Asyoucansee,thisisquiteabitofcode,soit'sbesttoabstractitintoafunction.Actually,oneoftheexercisesattheendofthechapterpromptsyoutocreateyourownAjaxutility.

Page 420: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

AisforAsynchronous

NowyouknowhowtocreateanXHRobject,giveitaURLandhandletheresponsetotherequest.Whathappenswhenyousendtworequestsasynchronously?Whatiftheresponsetothesecondrequestcomesbeforethefirst?

Intheprecedingexample,theXHRobjectwasglobalandmyCallbackwasrelyingonthepresenceofthisglobalobjectinordertoaccessitsreadyState,status,andresponseTextproperties.Anotherway,whichpreventsyoufromrelyingonglobalvariables,istowrapthecallbackinaclosure.Let'sseehow:

varxhr=newXMLHttpRequest();

xhr.onreadystatechange=(function(myxhr){returnfunction(){myCallback(myxhr);};}(xhr));

xhr.open('GET','somefile.txt',true);xhr.send('');

Inthiscase,myCallback()receivestheXHRobjectasaparameterandwillnotgolookingforitintheglobalspace.This alsomeansthatatthetimetheresponseisreceived,theoriginalxhrmightbereusedforasecondrequest.Theclosurekeepspointingtotheoriginalobject.

Page 421: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

XisforXML

AlthoughthesedaysJSON(discussedinthenextchapter)ispreferredoverXMLasadatatransferformat,XMLisstillanoption.InadditiontotheresponseTextproperty,theXHRobjectsalsohaveanotherpropertycalledresponseXML.WhenyousendanHTTPrequestforanXMLdocument,responseXMLpointstoanXMLDOMdocumentobject.Toworkwiththisdocument,youcanuseallofthecoreDOMmethodsdiscussedpreviouslyinthischapter,suchasgetElementsByTagName(),getElementById(),andsoon.

Page 422: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Anexample

Let'swrapupthedifferentXHRtopicswithanexample.Youcanvisitthepagelocatedathttp://www.phpied.com/files/jsoop/xhr.htmltoworkontheexampleyourself.

Themainpage,xhr.html,isasimplestaticpagethatcontainsnothingbutthree<div>tags,whichareasfollows:

<divid="text">Textwillbehere</div><divid="html">HTMLwillbehere</div><divid="xml">XMLwillbehere</div>

Usingtheconsole,youcanwritecodethatrequeststhreefilesandloadstheirrespectivecontentsinto each <div>.

Thethreefilestoloadareasfollows:

content.txt:ThisisasimpletextfilecontainingthetextIamatextfilecontent.html:ThisisafilecontainingHTMLcodeIam<strong>formatted</strong><em>HTML</em>

content.xml:ThisisanXMLfilecontainingthefollowingcode:

<?xmlversion="1.0"?><root>I'mXMLdata.</root>

Allofthefilesarestoredinthesamedirectoryasxhr.html.

Note

Forsecurityreasons,youcanonlyusetheoriginalXMLHttpRequesttorequestfilesthatareonthesamedomain.However,modernbrowserssupportXHR2,whichletsyoumakecross-domainrequests,providedthattheappropriateAccess-Control-Allow-OriginHTTPheaderisinplace.

First,let'screateafunctiontoabstracttherequest/responsepart:

function request(url, callback) {varxhr=newXMLHttpRequest();xhr.onreadystatechange=(function(myxhr){returnfunction(){if(myxhr.readyState===4&&myxhr.status===200){callback(myxhr);}};}(xhr));xhr.open('GET',url,true);xhr.send('');

Page 423: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}

ThisfunctionacceptsaURLtorequestandacallbackfunctiontocalloncetheresponsearrives.Let'scallthefunctionthreetimes,onceforeachfile,asfollows:

request('http://www.phpied.com/files/jsoop/content.txt',function(o){document.getElementById('text').innerHTML=o.responseText;});request('http://www.phpied.com/files/jsoop/content.html',

function (o) {document.getElementById('html').innerHTML=o.responseText;});request('http://www.phpied.com/files/jsoop/content.xml',function(o){document.getElementById('xml').innerHTML=o.responseXML.getElementsByTagName('root')[0].firstChild.nodeValue;});

Thecallbackfunctionsaredefinedinline.Thefirsttwoareidentical.TheyjustreplacetheHTMLofthecorresponding<div>withthecontentsoftherequestedfile.ThethirdoneisalittledifferentasitdealswiththeXMLdocument.First,youwillaccesstheXMLDOMobjectaso.responseXML.Then,usinggetElementsByTagName(),youwillgetalistofallthe<root>tags(thereisonlyone).ThefirstChildof<root>isatextnodeandnodeValueisthetextcontainedinit(I'mXMLdata).Then,justreplacetheHTMLof<divid="xml">withthenewcontent.Theresultisshowninthefollowingscreenshot:

Page 424: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

WhenworkingwiththeXMLdocument,youcanalsouseo.responseXML.documentElementtogettothe<root>elementinsteadofo.responseXML.getElementsByTagName('root')[0].RememberthatdocumentElementgivesyoutherootnodeofanXMLdocument.TherootinHTMLdocumentsisalwaysthe<html>tag.

Page 425: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ExercisesIn the previous chapters, the solutions to the exercises could be found in the text of the chapter.Thistime,someoftheexercisesrequireyoutodosomemorereading,orexperimentation,outsidethisbook.

1. BOM:AsaBOMexercise,trycodingsomethingwrong,obtrusive,user-unfriendly,andallinall,veryWeb1.0,theshakingbrowserwindow.Tryimplementingcodethatopensa200x200popupwindowandthenresizesitslowlyandgraduallyto400x400.Next,movethewindowaroundasifthere'sanearthquake.Allyou'llneedisoneofthemove*()functions,oneormorecallstosetInterval(),andmaybeonetosetTimeout()/clearInterval()tostopthewholething.Or,here'saneasierone-printthecurrentdate/timeindocument.titleandupdateiteverysecond,likeaclock.

2. DOM:ImplementwalkDOM()differently.Also,makeitacceptacallbackfunctioninsteadofhardcodingconsole.log().RemovingcontentwithinnerHTMLiseasy(document.body.innerHTML=''),butnotalwaysbest.Theproblemwillbewhenthereareeventlistenersattachedtotheremovedelements;theywon'tberemovedinIE,causingthebrowsertoleakmemorybecause it stores references to something that doesn't exist. Implement a general-purposefunctionthatdeletesDOMnodes,butremovesanyeventlistenersfirst.Youcanloopthroughtheattributesofanodeandcheckifthevalueisafunction.Ifitis,it'smostlikelyanattributelikeonclick.Youneedtosetittonullbeforeremovingtheelementfromthetree.Createafunctioncalledinclude()thatincludesexternalscriptsondemand.Thismeansyouneedtocreateanew<script>tagdynamically,setitssrcattribute,andappendtothedocument's<head>.Testitbyusingthefollowingcode:

>include('somescript.js');

3. Events:Createaneventutility(object)calledmyevent,whichhasthefollowingmethodsworkingcross-browser:

TheaddListener(element,event_name,callback),whereelementcanalsobeanarrayofelementsremoveListener(element,event_name,callback)getEvent(event)justtocheckforawindow.eventforolderversionsofIEgetTarget(event)stopPropagation(event)preventDefault(event)

Usageexampleisasfollows:

functionmyCallback(e){

Page 426: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

e=myevent.getEvent(e);alert(myevent.getTarget(e).href);myevent.stopPropagation(e);myevent.preventDefault(e);}myevent.addListener(document.links,'click',myCallback);

Theresultoftheexamplecodeshouldbethatallofthelinksinthedocumentleadnowhere,butonlyalertthehrefattribute.Createanabsolutelypositioned<div>,sayatx=100px,y=100px.Writethecodetobeabletomovedivaroundthepage usingthearrowkeysortheJ(left),K(right),M(down),andI(up)keys.Reuseyourowneventutilityfrom3.1.

4. XMLHttpRequest:CreateyourownXHRutility(object)calledajax.Forexample,takealookatthefollowingcode:

functionmyCallback(xhr){alert(xhr.responseText);}ajax.request('somefile.txt','get',myCallback);ajax.request('script.php','post',myCallback,'first=John&last=Smith');

Page 427: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryYou learned quite a bit in this chapter. You learned the following cross-browser BOM objects:

Propertiesoftheglobalwindowobject,suchasnavigator,location,history,frames,screen

MethodssuchassetInterval()andsetTimeout();alert(),confirm()andprompt();moveTo/By()andresizeTo/By()

Then,youlearnedabouttheDOM,anAPItorepresentanHTMLorXMLdocumentasatreestructure,whereeachtagortextisanodeonthetree.Youalsolearnedhowtoperformthefollowingactions:

Accessingnodes:Usingparent/childrelationshipproperties,suchasparentNode,childNodes,firstChild,lastChild,nextSibling,andpreviousSiblingUsinggetElementsById(),getElementsByTagName(),getElementsByName(),andquerySelectorAll()

Modifyingnodes:UsinginnerHTMLorinnerText/textContentUsingnodeValueorsetAttribute(),orjustusingattributesasobjectproperties

RemovingnodeswithremoveChild()orreplaceChild()AddingnewoneswithappendChild(),cloneNode(),andinsertBefore()

YoualsolearnedthefollowingDOM0(pre-standardization)properties,portedtoDOMLevel1:

Collections,suchasdocument.forms,images,links,anchors,applets.UsingthesearediscouragedasDOM1hasthemuchmoreflexiblegetElementsByTagName()method.Thedocument.bodyelement,whichgivesyouconvenientaccessto<body>.Thedocument.title,cookie,referrer,anddomain.

Next,youlearnedhowthebrowserbroadcastseventsthatyoucanlistento.It'snotstraightforwardtodothisinacross-browsermanner,butit'spossible.Eventsbubbleup,soyoucanuseeventdelegationtolistentoeventsmoreglobally.Youcanalsostopthepropagationofeventsandinterferewiththedefaultbrowserbehavior.

Finally,youlearnedabouttheXMLHttpRequestobjectthatallowsyoutobuildresponsivewebpagesthatdothefollowingtasks:

MakeHTTPrequeststotheservertogetpiecesofdataProcesstheresponsetoupdateportionsofthepage

Page 428: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 11. Coding and Design PatternsNow that you know all about the objects in JavaScript, mastered prototypes and inheritance, andseensomepracticalexamplesofusingbrowser-specificobjects,let'smoveforward,orrather,movealevelup.Let'stakealookatsomecommonJavaScriptpatterns.

Butfirst,what'sapattern?Inshort,apatternisagoodsolutiontoacommonproblem.Codifyingthesolutionintoapatternmakesitrepeatableaswell.

Sometimes,whenyou'refacinganewprogrammingproblem,youmayrecognizerightawaythatyou'vepreviouslysolvedanother,suspiciouslysimilarproblem.Insuchcases,it'sworthisolatingthisclassofproblemsandsearchingforacommonsolution.Apatternisaprovenandreusablesolution(oranapproach toasolution)toaclassofproblems.

Therearecaseswhereapatternisnothingmorethananideaoraname.Sometimes,justusinganame helps you think more clearly about a problem. Also, when working with other developers inateam,it'smucheasiertocommunicatewheneverybodyusesthesameterminologytodiscussaproblemorasolution.

Othertimes,youmaycomeacrossauniqueproblemthatdoesn'tlooklike anythingyou'veseenbeforeanddoesn'treadilyfitintoaknownpattern.Blindlyapplyingapatternjustforthesakeofusingapattern,isnotagoodidea.It'spreferabletonotuseanyknownpatternthantotrytotweakyourproblemsothatitfitsanexistingsolution.

Thischaptertalksabouttwotypesofpatterns,whichareasfollows:

Codingpatterns:ThesearemostlyJavaScript-specificbestpracticesDesignpatterns:Thesearelanguage-independentpatterns,popularizedbythefamousGangofFourbook

Page 429: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Coding patternsLet's start with some patterns that reflect JavaScript's unique features. Some patterns aim to helpyouorganizeyourcode,forexample,namespacing;othersarerelatedtoimprovingperformance,suchaslazydefinitionsandinit-timebranching;andsomemakeupformissingfeatures,suchasprivateproperties.Thepatternsdiscussedinthissectionincludethefollowingtopics:

SeparatingbehaviorNamespacesInit-timebranchingLazydefinitionConfigurationobjectsPrivatevariablesandmethodsPrivileged methodsPrivatefunctionsaspublicmethodsImmediatefunctionsChainingJSON

Page 430: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Separatingbehavior

Asdiscussedpreviously,thethreebuildingblocksofawebpageareasfollows:

Content (HTML)Presentation(CSS)Behavior(JavaScript)

Content

HTMListhecontentofthewebpage,theactualtext.Ideally,thecontentshouldbemarked-upusingtheleastamountof HTMLtagsthatsufficientlydescribethesemanticmeaningofthatcontent.Forexample,ifyou'reworkingonanavigationmenu,it'sagoodideatousethe<ul>and<li>tagsasanavigationmenuisinessence,justalistoflinks.

Yourcontent(HTML)shouldbefreefromanyformattingelements.VisualformattingbelongstothepresentationlayerandshouldbeachievedthroughtheuseofCSS(CascadingStyleSheets).Thismeansthefollowing:

ThestyleattributeofHTMLtagsshouldnotbeused,ifpossible.PresentationalHTMLtagssuchas<font>shouldnotbeusedatall.Tagsshouldbeusedfortheirsemanticmeaning,notbecauseofhowbrowsersrenderthembydefault.Forinstance,developerssometimesusea<div>tagwherea<p>wouldbemoreappropriate.It'salsofavorabletouse<strong>and<em>insteadof<b>and<i>asthelatterdescribethevisualpresentationratherthanthemeaning.

Presentation

Agoodapproachtokeeppresentationoutofthecontentistoresetornullifyallbrowserdefaults,forexample,usingreset.cssfromtheYahoo!UIlibrary.Thisway,thebrowser'sdefaultrenderingwon'tdistractyoufromconsciouslythinkingaboutthepropersemantictagstouse.

Behavior

Thethirdcomponentofawebpageisthebehavior.Behaviorshouldbekeptseparatefromboththecontentandthepresentation.ItisusuallyaddedbyusingJavaScriptthatisisolatedto<script>tags,andpreferablycontainedinexternalfiles.Thismeansnotusinganyinlineattributes,suchasonclick,onmouseover,andsoon.Instead,youcanusetheaddEventListener/attachEventmethodsfromthepreviouschapter.

Thebeststrategytoseparatebehaviorfromcontentisasfollows:

Minimizethenumberof<script>tagsAvoidinlineeventhandlersDonotuseCSSexpressionsTowardtheendofyourcontent,whenyouarereadytoclosethe<body>tag,insertasingle

Page 431: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

external.jsfile

Exampleofseparatingbehavior

Let'ssayyouhaveasearchformonapage,andyouwanttovalidatetheformwithJavaScript.So,yougoaheadandkeeptheformtagsfreefromanyJavaScript,andthenimmediatelybeforeclosingthe</body>tag, youinserta<script>tagthatlinkstoanexternalfile,asfollows:

<body><formid="myform"method="post"action="server.php"><fieldset><legend>Search</legend><inputname="search"id="search"type="text"/><inputtype="submit"/></fieldset></form><scriptsrc="behaviors.js"></script></body>

Inbehaviors.jsyouattachaneventlistenertothesubmitevent.Inyourlistener,youcanchecktoseeifthetextinputfieldwasleftblankand,ifso,stoptheformfrombeingsubmitted.Thisway,youwillsavearoundtripbetweentheserverandtheclientandmaketheapplicationimmediatelyresponsive.

Thecontentofbehaviors.jsisgiveninthefollowingcode.Itassumesthatyou'vecreatedyourmyeventutilityfromtheexerciseattheendofthepreviouschapter:

//initmyevent.addListener('myform','submit',function(e){//noneedtopropagatefurthere=myevent.getEvent(e);myevent.stopPropagation(e);//validatevarel=document.getElementById('search');if(!el.value){//toobad,fieldisemptymyevent.preventDefault(e);//preventtheformsubmissionalert('Pleaseenterasearchstring');}});

AsynchronousJavaScriptloading

You noticed how the script was loaded at the end of the HTML, right before closing the body. ThereasonisthatJavaScript blockstheDOMconstructionofthepage,andinsomebrowsers,evendownloadsoftheothercomponentsthatfollow.Bymovingthescriptstothebottomofthepage,youensurethatthescriptisoutoftheway,andwhenitarrives,itsimplyenhancesthealready

Page 432: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

usablepage.

AnotherwaytopreventexternalJavaScriptfilesfromblockingthepageistoloadthemasynchronously. This way you can start loading them earlier. HTML5 has the defer attribute forthis purpose. Consider the following line of code:

<scriptdefersrc="behaviors.js"></script>

Unfortunately,thedefer attributeisnotsupportedbyolderbrowsers,butluckily,thereisasolutionthatworksacrossbrowsers,oldandnew.ThesolutionistocreateascriptnodedynamicallyandappendittotheDOM.Inotherwords,youcanuseabitofinlineJavaScripttoloadtheexternalJavaScriptfile.Youcanhavethisscriptloadersnippetatthetopofyourdocumentsothatthedownloadhasanearlystart. Takealookatthefollowingcodeexample:

...<head><script>(function(){vars=document.createElement('script');s.src='behaviors.js';

document.getElementsByTagName('head')[0].appendChild(s);}());</script></head>...

Page 433: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Namespaces

Globalvariablesshouldbeavoidedinordertoreducethepossibilityofvariablenamingcollisions.Youcanminimizethenumberofglobalsbynamespacingyourvariablesandfunctions.Theideaissimple,youwillcreateonlyoneglobalobject,andallyourothervariablesandfunctionsbecomepropertiesofthatobject.

AnObjectasanamespace

Let'screateaglobalobjectcalledMYAPP:

//globalnamespacevarMYAPP=MYAPP||{};

Now,insteadofhavingaglobalmyeventutility(fromthepreviouschapter),youcanhaveitasaneventpropertyoftheMYAPPobject,asfollows:

//sub-objectMYAPP.event={};

Addingthemethodstotheeventutilityisstillthesame.Considerthefollowingexample:

//objecttogetherwiththemethoddeclarationsMYAPP.event={addListener:function(el,type,fn){//..dothething},removeListener:function(el,type,fn){//...},getEvent:function(e){//...}//...othermethodsorproperties};

Namespacedconstructors

Usinganamespacedoesn'tpreventyoufromcreatingconstructorfunctions.HereishowyoucanhaveaDOMutilitythathasanElementconstructor,whichallowsyoutocreateDOMelementseasily:

MYAPP.dom={};MYAPP.dom.Element=function(type,properties){vartmp=document.createElement(type);for(variinproperties){if(properties.hasOwnProperty(i)){tmp.setAttribute(i,properties[i]);}}

Page 434: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

returntmp;};

Similarly,youcanhaveaTextconstructortocreatetextnodes.Considerthefollowingcodeexample:

MYAPP.dom.Text=function(txt){returndocument.createTextNode(txt);};

Usingtheconstructorstocreatealinkatthebottomofapagecanbedoneasfollows:

varlink=newMYAPP.dom.Element('a',{href:'http://phpied.com',target:'_blank'});vartext=newMYAPP.dom.Text('clickme');link.appendChild(text);document.body.appendChild(link);

Anamespace()method

Youcancreateanamespaceutilitythatmakesyourlifeeasiersothatyoucanusemoreconvenientsyntaxasfollows:

MYAPP.namespace('dom.style');

Insteadofthemoreverbosesyntaxasfollows:

MYAPP.dom={};MYAPP.dom.style={};

Here's how you can create such a namespace() method. First, you will create an array bysplitting the input string using the period (.) as a separator. Then, for every element in the newarray, you will add a property to your global object, if one doesn't already exist, as follows:

varMYAPP={};MYAPP.namespace=function(name){varparts=name.split('.');varcurrent=MYAPP;for(vari=0;i<parts.length;i++){if(!current[parts[i]]){current[parts[i]]={};}current=current[parts[i]];}};

Testingthenewmethodisdoneasfollows:

MYAPP.namespace('event');MYAPP.namespace('dom.style');

Page 435: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Theresultoftheprecedingcodeisthesameasifyoudidthefollowing:

varMYAPP={event:{},dom:{style:{}}};

Page 436: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Init-timebranching

Inthepreviouschapter,younoticedthatsometimes,differentbrowsershavedifferentimplementationsforthesameorsimilarfunctionalities.Insuchcases,youwillneedtobranchyourcode,dependingon what'ssupportedbythebrowsercurrentlyexecutingyourscript.Dependingonyourprogram,thisbranchingcanhappenfartoooftenand,asaresult,mayslowdownthescriptexecution.

Youcanmitigatethisproblembybranchingsomepartsofthecodeduringinitialization,whenthescriptloads,ratherthanduringruntime.Buildingupontheabilitytodefinefunctionsdynamically,youcanbranchanddefinethesamefunctionwith adifferentbody,dependingonthebrowser.Let'sseehow.

First,let'sdefineanamespaceandplaceholdermethodfortheeventutility:

varMYAPP={};MYAPP.event={addListener:null,removeListener:null};

Atthispoint,themethodstoaddorremovealistenerarenotimplemented.Basedontheresultsfromfeaturesniffing,thesemethodscanbedefineddifferently,asfollows:

if(window.addEventListener){MYAPP.event.addListener=function(el,type,fn){el.addEventListener(type,fn,false);};MYAPP.event.removeListener=function(el,type,fn){el.removeEventListener(type,fn,false);

};}elseif(document.attachEvent){//IEMYAPP.event.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);};MYAPP.event.removeListener=function(el,type,fn){el.detachEvent('on'+type,fn);};}else{//olderbrowsersMYAPP.event.addListener=function(el,type,fn){el['on'+type]=fn;};MYAPP.event.removeListener=function(el,type){el['on'+type]=null;};}

Afterthisscriptexecutes,youhavetheaddListener()andremoveListener()methodsdefinedinabrowser-dependentway.Now,everytimeyouinvokeoneofthesemethods,there'snomore

Page 437: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

feature-sniffing,anditresultsinlessworkandfasterexecution.

Onethingtowatchoutforwhensniffingfeaturesisnottoassumetoomuchaftercheckingforonefeature. In the previous example, this rule is broken because the code only checks foraddEventListenersupport,butthendefinesbothaddListener()andremoveListener().Inthiscase,it'sprobablysafetoassumethatifabrowserimplementsaddEventListener(),italsoimplementsremoveEventListener().However,imaginewhathappensifabrowserimplementsstopPropagation()butnotpreventDefault(),andyouhaven'tcheckedfortheseindividually.YouhaveassumedthatbecauseaddEventListener()isnotdefined,thebrowsermustbeanoldIEandwriteyourcodeusingyourknowledgeandassumptionsofhowIEworks.Rememberthatallofyourknowledgeisbasedonthewayacertainbrowserworkstoday,butnotnecessarilythewayitwillworktomorrow.So,toavoidmanyrewritesofyourcodeasnewbrowserversionsareshipped,it'sbesttoindividuallycheckforfeaturesyouintendtouseanddon'tgeneralizeonwhatacertainbrowsersupports.

Page 438: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Lazydefinition

Thelazydefinitionpatternissimilartothepreviousinit-timebranchingpattern.Thedifferenceisthatthebranchinghappensonlywhenthefunctioniscalledforthefirsttime.Whenthefunctioniscalled,itredefinesitself withthebestimplementation.Unliketheinit-timebranching,wheretheifhappensonce,duringloading,hereitmaynothappenatall,incaseswhenthefunctionisnevercalled.Thelazydefinitionalsomakestheinitializationprocesslighterasthere'snoinit-timebranchingworktobedone.

Let'sseeanexamplethatillustratesthisviathedefinitionofanaddListener()function.Thefunctionisfirstdefinedwithagenericbody.Itcheckswhichfunctionalityissupportedbythebrowserwhenit'scalledforthefirsttimeandthenredefinesitselfusingthemostsuitableimplementation.Attheendofthefirstcall,thefunctioncallsitself,sothattheactualeventattachingisperformed.Thenexttimeyoucallthesamefunction,itwillbedefinedwithitsnewbodyandbereadyforuse,sonofurtherbranchingisnecessary.Thefollowingisthecodesnippet:

varMYAPP={};MYAPP.myevent={addListener:function(el,type,fn){if(el.addEventListener){MYAPP.myevent.addListener=function(el,type,fn){el.addEventListener(type,fn,false);};}elseif(el.attachEvent){MYAPP.myevent.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);};}else{MYAPP.myevent.addListener=function(el,type,fn){el['on'+type]=fn;

};}MYAPP.myevent.addListener(el,type,fn);}};

Page 439: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Configurationobject

Thispatternisconvenientwhenyouhaveafunctionormethodthatacceptsalotofoptionalparameters.It'suptoyoutodecidehowmanyconstitutesalot.Butgenerally,afunctionwithmorethanthreeparametersisnotconvenienttocall,becauseyouhavetoremembertheorderoftheparameters,anditisevenmoreinconvenientwhensomeoftheparametersareoptional.

Insteadofhavingmanyparameters,youcanuseoneparameterandmakeitanobject.Thepropertiesoftheobjectaretheactualparameters.Thisissuitabletopassconfigurationoptionsbecausethesetendtobenumerousandoptional(withsmartdefaults).Thebeautyofusingasingleobjectasopposedtomultipleparametersisdescribedasfollows:

Theorderdoesn'tmatterYoucaneasilyskip parametersthatyoudon'twanttosetIt'seasytoaddmoreoptionalconfigurationattributesItmakesthecodemorereadablebecausetheconfigurationobject'spropertiesarepresentinthecallingcodealongwiththeirnames

ImagineyouhavesomesortofUIwidgetconstructoryouusetocreatefancybuttons.Itacceptsthetexttoputinsidethebutton(thevalueattributeofthe<input>tag)andanoptionalparameterofthetypeofbutton.Forsimplicity,let'ssaythefancybuttontakesthesameconfigurationasaregularbutton.Takealookatthefollowingcode:

//aconstructorthatcreatesbuttonsMYAPP.dom.FancyButton=function(text,type){varb=document.createElement('input');b.type=type||'submit';b.value=text;returnb;

};

Usingtheconstructorissimple;youjustgiveitastring.Then,youcanaddthenewbuttontothebodyofthedocumentasfollows:

document.body.appendChild(newMYAPP.dom.FancyButton('puuush'));

Thisisallwellandworksfine,butthenyoudecideyoualsowanttobeabletosetsomeofthestylepropertiesofthebutton,suchascolorsandfonts.Youcanendupwithadefinitionlikethefollowing:

MYAPP.dom.FancyButton=function(text,type,color,border,font){//...

};

Page 440: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Now,usingtheconstructorcanbecomealittleinconvenient,especiallywhenyouwanttosetthethirdandfifthparameter,butnotthesecondorthefourth.Considerthefollowingexample:

newMYAPP.dom.FancyButton('puuush',null,'white',null,'Arial');

Abetterapproachistouseoneconfigobjectparameterforallthesettings.Thefunctiondefinitioncanbecomesomethinglikethefollowingcodesnippet:

MYAPP.dom.FancyButton=function(text,conf){vartype=conf.type||'submit';varfont=conf.font||'Verdana';//...};

Usingtheconstructorisshownasfollows:

varconfig={font:'Arial,Verdana,sans-serif',color:'white'

};newMYAPP.dom.FancyButton('puuush',config);

Anotherusageexampleisasfollows:

document.body.appendChild(newMYAPP.dom.FancyButton('dude',{color:'red'}));

Asyoucansee,it'seasytosetonlysomeoftheparametersandtoswitcharoundtheirorder.Inaddition,thecodeisfriendlierandeasiertounderstandwhenyouseethenamesoftheparametersatthesameplacewhereyoucallthemethod.

Adrawbackofthispatternisthesameasitsstrength.It'strivialtokeepaddingmoreparameters,whichmeanstrivialtoabusethetechnique.Onceyouhaveanexcusetoaddtothisfree-for-allbagofproperties,youwillfindittemptingtokeepaddingsomethatarenotentirelyoptional,orsomethataredependentonotherproperties.

Asaruleofthumb,allthesepropertiesshouldbeindependentandoptional.Ifyouhavetocheckallpossiblecombinationsinsideyourfunction("oh,Aisset,butAisonlyusedifBisalsoset"),thisisarecipeforalargefunctionbody,whichquicklybecomesconfusinganddifficult,ifnotimpossible,totest,becauseofallthecombinations.

Page 441: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Privatepropertiesandmethods

JavaScriptdoesn'thavethenotionofaccessmodifiers,whichsettheprivilegesofthepropertiesinanobject.Otherlanguagesoftenhaveaccessmodifiers,asfollows:

Public:AllusersofanobjectcanaccessthesepropertiesormethodsPrivate:OnlytheobjectitselfcanaccessthesepropertiesProtected:Onlyobjectsinheritingtheobjectinquestioncanaccesstheseproperties

JavaScriptdoesn'thaveaspecialsyntaxtodenoteprivatepropertiesormethods,butasdiscussedinChapter3,Functions, youcanuselocalvariablesandmethodsinsideafunctionandachievethesamelevelofprotection.

ContinuingwiththeexampleoftheFancyButtonconstructor,youcanhavelocalvariablestylesthatcontainsallthedefaults,andalocalsetStyle()function.Theseareinvisibletothecodeoutsideoftheconstructor.Here'showFancyButtoncanmakeuseofthelocalprivateproperties:

varMYAPP={};MYAPP.dom={};MYAPP.dom.FancyButton=function(text,conf){varstyles={font:'Verdana',border:'1pxsolidblack',color:'black',background:'grey'};functionsetStyles(b){vari;for(iinstyles){if(styles.hasOwnProperty(i)){b.style[i]=conf[i]||styles[i];}}

}conf=conf||{};varb=document.createElement('input');b.type=conf.type||'submit';b.value=text;setStyles(b);returnb;};

Inthisimplementation,stylesisaprivatepropertyandsetStyle()isaprivatemethod.Theconstructorusestheminternally(andtheycanaccessanythinginsidetheconstructor),buttheyarenotavailabletocodeoutsideofthefunction.

Page 442: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Privilegedmethods

Privilegedmethods(this termwascoinedbyDouglasCrockford)arenormalpublicmethodsthatcanaccessprivatemethodsorproperties.Theycanactlikeabridgeinmakingsomeoftheprivatefunctionalityaccessible,butinacontrolledmanner,wrappedinaprivilegedmethod.

Page 443: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Privatefunctionsaspublicmethods

Let'ssayyou'vedefinedafunctionthatyouabsolutelyneedtokeepintact, soyoumakeitprivate.However,youalsowanttoprovideaccesstothesamefunction,sothatoutsidecodecanalsobenefitfromit.Inthiscase,youcanassigntheprivatefunctiontoapubliclyavailableproperty.

Let'sdefine_setStyle()and_getStyle()asprivatefunctions,butthenassignthemtothepublicsetStyle()andgetStyle(),considerthefollowingexample:

varMYAPP={};MYAPP.dom=(function(){var_setStyle=function(el,prop,value){

console.log('setStyle');};var_getStyle=function(el,prop){console.log('getStyle');};return{setStyle:_setStyle,getStyle:_getStyle,yetAnother:_setStyle};}());

Now,whenyoucallMYAPP.dom.setStyle(),itinvokestheprivate_setStyle()function.YoucanalsooverwritesetStyle()fromtheoutsideasfollows:

MYAPP.dom.setStyle=function(){alert('b');};

Now,theresultisasfollows:

MYAPP.dom.setStylepointstothenewfunctionMYAPP.dom.yetAnotherstillpointsto_setStyle()_setStyle()isalwaysavailablewhenanyotherinternalcodereliesonittobeworkingasintended,regardlessoftheoutsidecode

Whenyouexposesomethingprivate,keepinmindthatobjects(functionsandarraysareobjectstoo)arepassedbyreferenceand,therefore,canbemodifiedfromtheoutside.

Page 444: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Immediatefunctions

Anotherpatternthathelpsyoukeeptheglobalnamespacecleanistowrapyourcodeinananonymousfunctionandexecutethatfunctionimmediately.Thisway,anyvariablesinsidethefunctionarelocal,aslongasyouusethevarstatement,andaredestroyedwhenthefunctionreturns,iftheyaren'tpartofaclosure.ThispatternwasdiscussedinmoredetailinChapter3,Functions.Takealookatthefollowingcode:

(function(){//codegoeshere...}());

Thispatternisespeciallysuitableforon-offinitializationtask,performedwhenthescriptloads.

Theimmediateself-executingfunctionpatterncanbeextendedtocreateandreturnobjects.Ifthecreationoftheseobjectsismorecomplicatedandinvolvessomeinitializationwork,thenyoucandothisinthefirstpartoftheself-executablefunctionandreturnasingleobjectthatcanaccessandbenefitfromanyprivatepropertiesatthetopportion,asfollows:

varMYAPP={};MYAPP.dom=(function(){//initializationcode...function_private(){//...

}return{getStyle:function(el,prop){console.log('getStyle');_private();},setStyle:function(el,prop,value){console.log('setStyle');}};}());

Page 445: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Modules

Combiningseveralofthepreviouspatternsgives youanewpattern,commonlyreferredtoasamodulepattern.Theconceptofmodulesinprogrammingisconvenientasitallowsyoutocodeseparatepiecesorlibrariesandcombinethemas needed,justlikepiecesofapuzzle.

Themodulepatternincludesthefollowing:

NamespacestoreducenamingconflictsamongmodulesAnimmediatefunctiontoprovideaprivatescopeandinitializationPrivatepropertiesandmethods

Note

ES5doesn'thaveabuilt-inconceptofmodules.Thereisthemodulespecificationfromhttp://www.commonjs.org,whichdefinesarequire()functionandanexportsobject.ES6,however,supportsmodules.Chapter8,ClassesandModuleshascoveredmodulesindetail.

Returninganobject thathasthepublicAPIofthemoduleasfollows:

namespace('MYAPP.module.amazing');MYAPP.module.amazing=(function(){//shortnamesfordependenciesvaranother=MYAPP.module.another;//local/privatevariablesvari,j;//privatefunctionsfunctionhidden(){}//publicAPIreturn{hi:function(){return"hello";}

};}());

And,youcanusethemoduleinthefollowingway:

MYAPP.module.amazing.hi();//"hello"

Page 446: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chaining

Chainingisapatternthatallowsyoutoinvokemultiplemethodsononelineasifthemethodsarethelinksinachain.Thisisconvenientwhencallingseveralrelatedmethods.Youinvokethenextmethodontheresultofthepreviouswithouttheuseofanintermediatevariable.

Sayyou'vecreatedaconstructorthathelpsyouworkwithDOMelements.Thecodetocreateanew<span>tagthatisaddedtothe<body>tagcanlooksomethinglikethefollowing:

varobj=newMYAPP.dom.Element('span');obj.setText('hello');obj.setStyle('color','red');obj.setStyle('font','Verdana');document.body.appendChild(obj);

Asyouknow,constructorsreturntheobjectreferredtoasthiskeywordthattheycreate.Youcanmakeyourmethods,suchassetText()andsetStyle(),alsoreturnthiskeyword,whichallowsyoutocallthenextmethodontheinstancereturnedbythepreviousone.Thisway,youcanchainmethodcalls,asfollows:

varobj=newMYAPP.dom.Element('span');obj.setText('hello').setStyle('color','red').setStyle('font','Verdana');document.body.appendChild(obj);

Youdon'tevenneedtheobjvariableifyoudon'tplanonusingitafterthe newelementhasbeenaddedtothetree,sothecodelookslikethefollowing:

document.body.appendChild(newMYAPP.dom.Element('span').setText('hello').setStyle('color','red').setStyle('font','Verdana'));

Adrawbackofthispatternisthatitmakesitalittlehardertodebugwhenanerroroccurssomewhereinalongchain,andyoudon'tknowwhichlinkistoblamebecausetheyareallonthesameline.

Page 447: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

JSON

Let'swrapupthecoding patternssectionofthischapterwithafewwordsaboutJSON.JSONisnottechnicallyacodingpattern,butyoucansaythatusingitisagoodpattern.

JSONisapopularlightweightformattoexchangedata.It'softenpreferredoverXMLwhenusingXMLHttpRequest()toretrievedatafromtheserver.There'snothingspecificallyinterestingaboutJSONotherthanthefactthatit'sextremelyconvenient.TheJSONformatconsistsofdatadefinedusingobjectandarrayliterals.HereisanexampleofaJSONstringthatyourservercanrespondwithafteranXHRrequest:

{'name':'Stoyan','family':'Stefanov','books':['OOJS','JSPatterns','JS4PHP']}

AnXMLequivalentofthiswillbesomethinglikethefollowingpieceofcode:

<?xmlversion="1.1"encoding="iso-8859-1"?><response><name>Stoyan</name><family>Stefanov</family><books><book>OOJS</book><book>JSPatterns</book><book>JS4PHP</book></books></response>

First,youcanseehowJSONislighterintermsofthenumberofbytes.However,themainbenefitisnotthesmallerbytesize,butthefactthatit'strivialtoworkwithJSONinJavaScript.Let'ssay,you'vemadeanXHRrequestandhavereceivedaJSONstringintheresponseTextpropertyoftheXHRobject.YoucanconvertthisstringofdataintoaworkingJavaScriptobjectbysimplyusingeval().Considerthefollowingexample:

//warning:counter-examplevarresponse=eval('('+xhr.responseText+')');

Now,youcanaccessthe datainobjasobjectpropertiesasfollows:

console.log(response.name);//"Stoyan"console.log(response.books[2]);//"JS4PHP"

Theproblemisthateval()isinsecure,soit'sbestifyouusetheJSONobjecttoparsetheJSONdata(afallbackforolderbrowsersisavailableathttp://json.org/).CreatinganobjectfromaJSONstringisstilltrivialasfollows:

Page 448: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varresponse=JSON.parse(xhr.responseText);

Todotheopposite,thatis,toconvertanobjecttoaJSONstring,youcanusethestringify()method,asfollows:

varstr=JSON.stringify({hello:"you"});

Due to its simplicity, JSON has quickly become popular as a language-independent format toexchangedata,andyoucaneasilyproduceJSON ontheserversideusingyourpreferredlanguage.InPHP,forexample,therearethejson_encode()andjson_decode()functionsthatletyouserializeaPHParrayorobjectintoaJSONstring,andviceversa.

Page 449: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Higherorderfunctions

Functionalprogrammingwasconfinedtoalimitedsetoflanguagessofar.Withmorelanguagesaddingfeaturestosupportfunctionalprogramming,interestintheareaisgainingmomentum.JavaScriptisevolvingtosupportcommonfeaturesoffunctionalprogramming.Youwillgraduallyseealotofcodewritteninthisstyle.Itisimportanttounderstandthefunctionalprogrammingstyle,evenifyoudon'tfeelinclinedjustyettouseitinyourcode.

Higherorderfunctionsareoneoftheimportantmainstaysoffunctionalprograming.Higherorderfunctionisafunctionthatdoesatleastoneofthefollowing:

TakesoneormorefunctionsasargumentsReturnsafunctionasaresult

AsfunctionsarefirstclassobjectsinJavaScript, passingandreturningfunctionstoandfromafunctionisaprettyroutineaffair.Callbacksarehigherorderfunctions.Let'stakealookathowwecantakethesetwoprinciplestogetherandwriteahigherorderfunction.

Let'swriteafilterfunction;thisfunctionfiltersoutvaluesfromanarraybasedonacriteriadeterminedbyafunction.Thisfunctiontakestwoarguments-afunction,whichreturnsaBooleanvalue,trueforkeepingthiselement.

Forexample,withthisfunction,wearefilteringalloddvaluesfromanarray.Considerthefollowinglinesofcode:

console.log([1,2,3,4,5].filter(function(ele){returnele%2==0;}));//[2,4]

Wearepassingananonymousfunctiontothefilterfunctionasthefirstargument.ThisfunctionreturnsaBooleanbasedonaconditionthatchecksiftheelementisoddoreven.

ThisisanexampleofoneoftheseveralhigherorderfunctionsaddedtoECMAScript5.ThepointwearetryingtomakehereisthatyouwillincreasinglyseesimilarpatternsofusageinJavaScript.Youmustfirstunderstandhowhigher orderfunctionsworkandlater,onceyouarecomfortable with the concept, try to incorporate them in your code as well.

WithES6functionsyntaxchanges,itisevenmoreeleganttowritehigherorderfunctions.Let'stakeasmallexampleinES5andseehowthattranslatesintoitsES6equivalent:

functionadd(x){returnfunction(y){returny+x;};}varadd3=add(3);

Page 450: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

console.log(add3(3));//=>6console.log(add(9)(10));//=>19

Theaddfunctiontakesx andreturnsafunctionthattakesyasanargumentandthenreturnsvalueofexpressiony+x.

Whenwelookedatarrowfunctions,wediscussedthatarrowfunctionsreturnresultsofasingleexpressionimplicitly.So,theprecedingfunctioncanbeturnedintoanarrowfunctionbymakingthebodyofthearrowfunctionanotherarrowfunction.Takealookatthefollowingexample:

constadd=x=>y=>y+x;

Here,wehaveanouterfunction,x=>[innerfunctionwithxasargument],andwehaveaninnerfunction,y=>y+x.

Thisintroductionwillhelpyougetfamiliarwiththeincreasingusageofhigherorderfunctions,andtheirincreasedimportanceinJavaScript.

Page 451: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Design patternsThe second part of this chapter presents a JavaScript approach to a subset of the design patternsintroducedbyDesignPatterns:ElementsofReusableObject-OrientedSoftware,aninfluentialbookmostcommonlyreferredtoastheBookofFour,theGangofFour,orGoF(afteritsfourauthors).ThepatternsdiscussedintheGoFbook aredividedintothethreefollowinggroups:

Creationalpatternsthatdealwithhowobjectsarecreated(instantiated)StructuralpatternsthatdescribehowdifferentobjectscanbecomposedinordertoprovidenewfunctionalityBehavioralpatternsthatdescribewaysforobjectstocommunicatewitheachother

Thereare23patternsintheBookofFour,andmorepatternshavebeenidentifiedsincethebook'spublication.It'swaybeyondthescopeofthisbooktodiscussallofthem,sotheremainderofthechapterdemonstratesonlyfour,alongwithexamplesoftheirimplementationinJavaScript.Rememberthatthepatternsaremoreaboutinterfacesandrelationshipsratherthanimplementation.Onceyouhaveanunderstandingofadesignpattern,it'softennotdifficulttoimplementit,especiallyinadynamiclanguagesuchasJavaScript.

Thepatternsdiscussedthroughtherestofthechapterareasfollows:

SingletonFactoryDecoratorObserver

Page 452: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Singletonpattern

Singletonisacreationaldesignpattern,meaningthatitsfocusisoncreatingobjects.Ithelpsyouwhenyouwanttomakesurethereisonlyoneobjectofagivenkindorclass.Inaclassicallanguage,thiswouldmeanthataninstanceofaclassisonlycreatedonce,andanysubsequentattemptstocreatenewobjectsofthesameclasswouldreturntheoriginalinstance.

InJavaScript,becausetherearenoclasses,asingletonisthedefaultandmostnaturalpattern.Everyobjectisasingletonobject.

The most basic implementation of the singleton in JavaScript is the object literal. Take a look atthefollowinglineofcode:

varsingle={};

Thatwaseasy,right?

Page 453: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Singleton2pattern

Ifyouwanttouseaclass-likesyntaxandstillimplementthesingletonpattern,thingsbecomeabitmoreinteresting.Let'ssay,youhaveaconstructorcalledLogger(),andyouwanttobeabletodosomethinglikethefollowing:

varmy_log=newLogger();my_log.log('someevent');

//...1000linesofcodelaterinadifferentscope...

varother_log=newLogger();other_log.log('somenewevent');console.log(other_log===my_log);//true

Theideaisthat,althoughyouusenew,onlyoneinstanceneedstobecreated,andthisinstanceisthenreturnedinconsecutivecalls.

Globalvariable

Oneapproachistouseaglobalvariabletostorethesingleinstance.Yourconstructorcouldlooklikethefollowingcodesnippet:

functionLogger(){if(typeofglobal_log==="undefined"){global_log=this;}returnglobal_log;}

Usingthisconstructorgivestheexpectedresult,whichisasfollows:

vara=newLogger();varb=newLogger();console.log(a===b);//true

Thedrawbackis,obviously,theuseofaglobalvariable.Itcanbeoverwrittenatanytime,evenaccidentally,andyoucanlosetheinstance.Theopposite,yourglobalvariableoverwritingsomeoneelse'sisalsopossible.

Propertyoftheconstructor

Asyouknow,functionsareobjectsandtheyhaveproperties.Youcanassignthesingleinstancetoapropertyoftheconstructorfunction,asfollows:

functionLogger(){if(!Logger.single_instance){Logger.single_instance=this;}

Page 454: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

returnLogger.single_instance;}

Ifyouwritevara=newLogger(),apointstothenewlycreatedLogger.single_instanceproperty.Asubsequentvarb=newLogger()callresultsinbpointingtothesameLogger.single_instanceproperty,whichisexactlywhatyouwant.

Thisapproachcertainlysolvestheglobalnamespaceissuebecausenoglobalvariablesarecreated.TheonlydrawbackisthatthepropertyoftheLoggerconstructor ispubliclyvisible,soitcanbeoverwrittenatanytime.Insuchcases,thesingleinstancecanbelostormodified.Ofcourse,youcanonlyprovidesomuchprotectionagainstfellowprogrammersshootingthemselvesinthefoot.Afterall,ifsomeonecanmesswiththesingle-instanceproperty,theycanmessuptheLoggerconstructordirectlyaswell.

Inaprivateproperty

Thesolutiontotheproblemofoverwritingthepubliclyvisiblepropertyisnottouseapublicproperty,butaprivateone.Youalreadyknowhowtoprotectvariableswithaclosure,soasanexercise,youcanimplementthisapproachtothesingletonpattern.

Page 455: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Factorypattern

Thefactoryisanothercreationaldesignpattern,asitdealswithcreatingobjects.Thefactorycanhelpyouwhenyouhavesimilartypesofobjectsandyoudon'tknowinadvancewhichoneyouwanttouse.Basedonuserinputorothercriteria,yourcodedeterminesthetypeofobjectitneedsonthefly.

Let'ssayyouhavethreedifferentconstructorsthatimplementsimilarfunctionality.AlltheobjectstheycreatetakeaURLbutdodifferentthingswithit.OnecreatesatextDOMnode;thesecondcreatesalink;andthethird,animage,asfollows:

varMYAPP={};MYAPP.dom={};MYAPP.dom.Text=function(url){this.url=url;this.insert=function(where){vartxt=document.createTextNode(this.url);where.appendChild(txt);};};MYAPP.dom.Link=function(url){this.url=url;this.insert=function(where){varlink=document.createElement('a');link.href=this.url;link.appendChild(document.createTextNode(this.url));where.appendChild(link);};};MYAPP.dom.Image=function(url){

this.url = url;this.insert=function(where){varim=document.createElement('img');im.src=this.url;where.appendChild(im);};};

Usingthethreedifferentconstructorsisexactlythesame-passtheurlvariableandcalltheinsert()method,asfollows:

varurl='http://www.phpied.com/images/covers/oojs.jpg';

varo=newMYAPP.dom.Image(url);o.insert(document.body);

varo=newMYAPP.dom.Text(url);o.insert(document.body);

varo=newMYAPP.dom.Link(url);

Page 456: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

o.insert(document.body);

Imagineyourprogramdoesn'tknowinadvancewhichtypeofobjectisrequired.Theuserdecides,duringruntime,byclickingonabuttonforexample.Iftypecontainstherequiredtypeofobject,you'llneedtouseaniforaswitchstatement,andwritesomethinglikethefollowingpieceofcode:

varo;if(type==='Image'){o=newMYAPP.dom.Image(url);}if(type==='Link'){o=newMYAPP.dom.Link(url);}if(type==='Text'){o=newMYAPP.dom.Text(url);

}o.url='http://...';o.insert();

Thisworksfine;however,ifyouhavealotofconstructors,thecodebecomestoolengthyandhardtomaintain.Also,ifyouarecreatingalibraryoraframeworkthatallowsextensionsorplugins,youdon'tevenknowtheexactnamesofalltheconstructorfunctionsinadvance.Insuchcases,it'sconvenienttohaveafactoryfunctionthattakescareofcreatinganobjectofthedynamicallydeterminedtype.

Let'saddafactorymethodtotheMYAPP.domutility:

MYAPP.dom.factory=function(type,url){returnnewMYAPP.dom[type](url);};

Now,youcanreplacethethreeiffunctionswiththesimplercode,asfollows:

varimage=MYAPP.dom.factory("Image",url);image.insert(document.body);

Theexamplefactory()methodinthepreviouscodewassimple;however,inareal-lifescenario,you'dwanttodosomevalidationagainstthetypevalue(forexample,checkifMYAPP.dom[type]exists)andoptionallydosomesetupworkcommontoallobjecttypes(forexample,setuptheURLallconstructorsuse).

Page 457: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Decoratorpattern

Thedecoratordesignpatternisastructuralpattern;itdoesn'thavemuchtodowithhowobjectsarecreated,butratherhowtheirfunctionalityisextended.Insteadofusinginheritance,whereyouextendinalinearway(parent-child-grandchild),youcanhaveonebaseobjectandapoolofdifferentdecoratorobjectsthatprovideextrafunctionality.Yourprogramcanpickandchoosewhichdecoratorsitwants,andinwhichorder.Foradifferentprogramor codepath,youmayhaveadifferentsetofrequirementsandpickdifferentdecoratorsoutofthesamepool.Takealookatthefollowingcodesnippettoseehowtheusagepartofthedecoratorpatterncanbeimplemented:

varobj={doSomething:function(){console.log('sure,asap');

}//...};obj=obj.getDecorator('deco1');obj=obj.getDecorator('deco13');obj=obj.getDecorator('deco5');obj.doSomething();

YoucanseehowyoucanstartwithasimpleobjectthathasadoSomething()method.Then,youcanpickoneofthedecoratorobjectsyouhavelyingaroundandwhichcanbeidentifiedbyname.AlldecoratorsprovideadoSomething()methodthatfirstcallsthesame methodofthepreviousdecoratorandthenproceedswithitsowncode.Everytimeyouaddadecorator,youoverwritethebaseobjwithanimprovedversionofit.Intheend,whenyouarefinishedaddingdecorators,youcalldoSomething().Asaresult,allofthedoSomething()methodsofallthedecoratorsareexecutedinsequence.Let'sseeanexample.

Decoratingachristmastree

Let'sillustratethedecoratorpatternwithanexampleofdecoratingaChristmastree.Youcanstartwiththedecorate()methodasfollows:

vartree={};tree.decorate=function(){alert('Makesurethetreewon'tfall');};

Now,let'simplementagetDecorator()methodthataddsextradecorators.Thedecoratorswillbeimplementedasconstructorfunctions,andthey'llallinheritfromthebasetreeobjectasfollows:

tree.getDecorator=function(deco){tree[deco].prototype=this;returnnewtree[deco];

Page 458: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

};

Now,let'screatethefirstdecorator,RedBalls(),asapropertyoftree,inordertokeeptheglobalnamespacecleaner.Theredballobjectsalsoprovideadecorate()method,buttheymakesuretheycalltheirparent'sdecorate()first.Forexample,takealookatthefollowingcode:

tree.RedBalls=function(){this.decorate=function(){this.RedBalls.prototype.decorate();alert('Putonsomeredballs');};

};

Similarly,implementBlueBalls()andAngel()decoratorsasfollows:

tree.BlueBalls=function(){this.decorate=function(){this.BlueBalls.prototype.decorate();alert('Addblueballs');};

};tree.Angel=function(){this.decorate=function(){this.Angel.prototype.decorate();alert('Anangelonthetop');};};

Now,let'saddallofthedecoratorstothebaseobject,asshowninthefollowingcodesnippet:

tree=tree.getDecorator('BlueBalls');tree=tree.getDecorator('Angel');tree=tree.getDecorator('RedBalls');

Finally,runthedecorate()methodasfollows:

tree.decorate();

Thissinglecallresultsinthefollowingalerts,specificallyinthisorder:

1. Makesurethetreewon'tfall.2. Addtheblueballs.3. Addanangelatthetop.4. Addsomeredballs.

Asyousee,thisfunctionalityallowsyoutohaveasmanydecoratorsasyoulike,andtochooseandcombinetheminanywayyoulike.

Page 459: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Observerpattern

Theobserverpattern,alsoknownasthesubscriber-publisherpattern,isabehavioralpattern,whichmeansthatitdealswithhowdifferentobjectsinteractandcommunicatewitheachother.Whenimplementingtheobserverpattern,youhavethefollowingobjects:

Oneormorepublisherobjectsthatannouncewhentheydosomethingimportant.Oneormoresubscriberstunedintooneormorepublishers.Theylistentowhatthepublishersannounceandthenactappropriately.

Theobserverpatternmaylookfamiliartoyou.Itsoundssimilartothebrowsereventsdiscussedinthepreviouschapter,andrightlyso,becausethebrowsereventsareoneexampleapplicationofthispattern.Thebrowseristhepublisher;itannouncesthefactthatanevent,suchasaclick,hashappened.Youreventlistenerfunctionsthataresubscribedtolistentothistypeofeventwillbenotifiedwhenithappens.Thebrowser-publishersendsaneventobjecttoallofthesubscribers.Inyourcustomimplementations,youcansendanytypeofdatayoufindappropriate.

Therearetwosubtypesoftheobserverpattern:pushandpull.Pushiswherethepublishersareresponsibletonotifyeachsubscriber,andpulliswherethesubscribersmonitorforchangesinapublisher'sstate.

Let'stakealookatanexampleimplementationofthepushmodel.Let'skeeptheobserver-relatedcodeinaseparateobjectandthenusethisobjectasamix-in,addingitsfunctionalitytoanyotherobjectthatdecidestobeapublisher.Inthisway,anyobjectcanbecomeapublisherandanyfunctioncanbecomeasubscriber.Theobserverobjectwillhavethefollowingpropertiesandmethods:

AnarrayofsubscribersthatarejustcallbackfunctionsTheaddSubscriber()andremoveSubscriber()methodsthataddto,andremovefrom,thesubscriberscollectionApublish()methodthattakesdataandcallsallsubscribers,passingthedatatothemAmake()methodthattakesanyobjectandturnsitintoapublisherbyaddingallofthemethodsmentionedpreviouslytoit

Here'stheobservermix-inobjectthatcontainsallthesubscription-relatedmethodsandcanbeusedtoturnanyobjectintoapublisher:

varobserver={addSubscriber:function(callback){if(typeofcallback==="function"){this.subscribers[this.subscribers.length]=callback;}},removeSubscriber:function(callback){for(vari=0;i<this.subscribers.length;i++){if(this.subscribers[i]===callback){

Page 460: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

deletethis.subscribers[i];}}},publish:function(what){for(vari=0;i<this.subscribers.length;i++){if(typeofthis.subscribers[i]==='function'){this.subscribers[i](what);}}},make:function(o){//turnsanobjectintoapublisherfor(variinthis){if(this.hasOwnProperty(i)){o[i]=this[i];o.subscribers=[];}}}};

Now,let'screatesomepublishers.Apublishercanbeanyobjectanditsonlydutyistocallthepublish()methodwheneversomethingimportantoccurs.Here'sabloggerobjectthatcallspublish()everytimeanewblogpostingisready:

varblogger={writeBlogPost:function(){varcontent='Todayis'+newDate();this.publish(content);}};

AnotherobjectcanbetheLATimesnewspaperthatcallspublish()whenanewnewspaperissueisout.Considerthefollowinglinesofcode:

varla_times={newIssue:function(){varpaper='MartianshavelandedonEarth!';this.publish(paper);}};

Youcanturntheseobjectsintopublishersasfollows:

observer.make(blogger);observer.make(la_times);

Now,let'shavethefollowingtwosimpleobjects,jackandjill:

varjack={read:function(what){console.log("Ijustreadthat"+what)

Page 461: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}};varjill={gossip:function(what){console.log("Youdidn'thearitfromme,but"+what)}};

Thejackandjillobjectscansubscribetothebloggerobjectbyprovidingthecallbackmethodstheywanttocallwhensomethingispublished,asfollows:

blogger.addSubscriber(jack.read);blogger.addSubscriber(jill.gossip);

Whathappensnow,whenthebloggerobjectwritesanewpost?Theresultisthatjackandjillwillgetnotified:

>blogger.writeBlogPost();IjustreadthatTodayisFriJan04201319:02:12GMT-0800(PST)Youdidn'thearitfromme,butTodayisFriJan04201319:02:12GMT-

0800(PST)

Atanytime,jillmaydecidetocancelhersubscription.Then,whenwritinganotherblogpost,theunsubscribedobjectisnolongernotified.Considerthefollowingcodesnippet:

>blogger.removeSubscriber(jill.gossip);>blogger.writeBlogPost();IjustreadthatTodayisFriJan04201319:03:29GMT-0800(PST)

ThejillobjectmaydecidetosubscribetoLATimes,asanobjectcanbeasubscribertomanypublishers,asfollows:

>la_times.addSubscriber(jill.gossip);

Then,whenLATimespublishesanewissue,jillgetsnotifiedandjill.gossip()isexecuted,asfollows:

>la_times.newIssue();Youdidn'thearitfromme,butMartianshavelandedonEarth!

Page 462: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryIn this chapter, you learned about common JavaScript coding patterns and learned how to makeyourprogramscleaner,faster,andbetteratworkingwithotherprogramsandlibraries.Then,yousawadiscussionandsampleimplementationsofahandfulofthedesignpatternsfromtheBookofFour.YoucanseehowJavaScriptisafullyfeatureddynamicprogramminglanguage,andthatimplementingclassicalpatternsinadynamiclooselytypedlanguageisprettyeasy.Thepatternsare,ingeneral,alargetopic,andyoucanjointheauthorofthisbookinafurtherdiscussionoftheJavaScriptpatternsatJSPatterns.com,ortakealookattheJavaScriptPatternsbook.Thenextchapterfocusesontestinganddebuggingmethodologies.

Page 463: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 12. Testing and DebuggingAs you write JavaScript applications, you will soon realize that having a sound testing strategy isindispensable.Infact,notwritingenoughtestsisalmostalwaysabadidea.Itisessentialtocoverallnontrivialfunctionalityofyourcodetomakesureofthefollowingpoints:

ExistingcodebehavesasperthespecificationsAnynewcodedoesnotbreakthebehaviordefinedbythespecifications

Both these points are very important. Many engineers consider only the first point as the solereasontocoveryourcodewithenoughtests.Themostobviousadvantage oftestcoverageistoreallymakesurethatthecodebeingpushedtoproductionsystemismostlyerrorfree.Writingtestcasestosmartlycovermaximumfunctionalareas ofthecode,generallygivesgoodindicationaroundtheoverallqualityofthecode.Thereshouldbenoargumentsorcompromisesaroundthispoint.Although,itisunfortunatethatmanyproductionsystemsarestillbereftofadequatecodecoverage.Itisveryimportanttobuildanengineeringculturewheredevelopersthinkaboutwritingtestsasmuchastheythinkaboutwritingcode.

Thesecondpointisevenmoreimportant.Legacysystemsareusuallyverydifficulttomanage.Whenyouareworkingoncode,eitherwrittenbysomeoneelseorwritten byalargedistributedteam,itisfairlyeasytointroducebugsandbreakthings.Eventhebestengineersmakemistakes.Whenyouareworkingonalargecodebaseyouareunfamiliarwith,ifthereisnosoundtestcoveragetohelpyou,youwillintroducebugs.Asyouwon'thavetheconfidenceinthechangesyouaremaking,becausetherearenotestcasestoconfirmyourchanges,yourcodereleaseswillbeshaky,slow,andobviouslyfullofhiddenbugs.

You will refrain from refactoring or optimizing your code, because you won't be really sure whatchangestothecodebasewouldpotentiallybreaksomething(again,becausetherearenotestcasetoconfirmyourchanges);allthisisaviciouscircle.It'slikeacivilengineersaying-althoughIhaveconstructedthisbridge,Ihavenoconfidenceonthequalityoftheconstruction.Itmaycollapseimmediatelyornever.Althoughthismaysoundlikeanexaggeration,Ihaveseenalotofhighimpactproductioncodebeingpushedwithnotestcoverage.Thisisriskyandshouldbeavoided.Whenyouarewritingenoughtestcasestocovermajorityofyourfunctionalcode,whenyoumakechangetothosepieces,youwillimmediatelyrealizeifthereisaproblemwiththisnewchange.Ifyourchangesmakethetestcasefail,youwillrealizetheproblem.Ifyourrefactorbreaksthetestscenario,youwillrealizetheproblem;allofthishappensmuchbeforethecodeispushedtoproduction.

Inrecentyears,ideasliketest-drivendevelopmentandself-testingcodearegainingprominence,especiallyinagilemethodology.Thesearefundamentallysoundideasandwillhelpyouwriterobustcode-thecodeyouareconfidentof.Wewilldiscussalltheseideasinthischapter.WewillunderstandhowtowritegoodtestcasesinmodernJavaScript.Wewillalsolookatseveraltoolsandmethodstodebugyourcode.JavaScriptwastraditionallyabitdifficulttotestand

Page 464: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

debug,primarilyduetolackoftools,butmoderntoolsmakebothoftheseeasyandnatural.

Page 465: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Unit testingWhen we talk about test cases, we mostly mean unit tests. It is incorrect to assume that the unit wewanttotestisalwaysafunction.Theunit,orunitofwork,isalogicalunitthatconstitutessinglebehavior.Thisunitshouldbeabletobeinvokedviaapublicinterfaceandshouldbetestableindependently.

Thus,aunittestcanperformthefollowingfunctions:

It tests a single logical functionItcanrunwithoutaspecificorderofexecutionIttakescareofitsowndependenciesandmockdataItalwaysreturnsthesameresultforthesameinputItshouldbeself-explanatory,maintainable,andreadable

MartinFowleradvocatestheTestPyramid(http://martinfowler.com/bliki/TestPyramid.html)strategytomakesurewehaveahighnumberofunitteststoensuremaximumcodecoverage.Therearetwoimportanttestingstrategiesthatwewilldiscussinthischapter.

Page 466: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TestDrivenDevelopment

Testdrivendevelopment(TDD)hasgainedalotofprominenceinthelastfewyears.Theconceptwasfirstproposedaspartoftheextremeprogrammingmethodology.Theideaistohaveshortrepetitivedevelopmentcycleswherethefocusisonwritingthetestcasesfirst.Thecyclelookslikethefollowing:

1. Addatestcaseasperthespecificationsforthespecificunitofcode.2. Runexistingsuiteoftestcasestoseeifthenewtestcaseyouwrotefails;itshould,becausethereisnocodefor thatunityet.Thisstepensuresthatthecurrenttestharnessworkswell.

3. Writethecodethatmainlyservestoconfirmtothetestcase.Thiscodeisnotoptimized,refactored,orevenentirelycorrect.However,thisisfineatthismoment.

4. Reruntestsandseeifallthetestcasespass.Afterthisstep,youareconfidentthatthenewcodeisnotbreakinganything.

5. Refactorcodetomakesureyouareoptimizingtheunitandhandlingallcornercases

Thesestepsarerepeatedforanynewcodeyouadd.Thisisanelegantstrategythatworksreallywellforagilemethodology.TDDwillbesuccessfulonlyifthetestableunitsofcodearesmallandconfirmsonlytothetestcase.

Page 467: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BehaviorDrivenDevelopment

AverycommonproblemwhiletryingtofollowTDDisvocabularyandthedefinitionofcorrectness.BDDtriestointroduceaubiquitouslanguagewhilewritingthetestcaseswhenyouarefollowingTDD.Thislanguagemakessurethatboththebusinessandtheengineeringaretalkingaboutthesamething.

WewilluseJasmineastheprimaryBDDframeworkandexplorevarioustestingstrategies.

Note

YoucaninstallJasminebydownloadingthestandalonepackagefromhttps://github.com/jasmine/jasmine/releases/download/v2.3.4/jasmine-standalone-2.3.4.zip.

Whenyouunzipthispackage,youwillseethefollowingdirectorystructure:

Page 468: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ThelibdirectorycontainstheJavaScriptfilesthatyouneedinyourprojecttostartwritingJasminetestcases.IfyouopenSpecRunner.html,youwillfindthefollowingJavaScriptfilesincludedinit:

<scriptsrc="lib/jasmine-2.3.4/jasmine.js"></script><scriptsrc="lib/jasmine-2.3.4/jasmine-html.js"></script><scriptsrc="lib/jasmine-2.3.4/boot.js"></script>

<!--includesourcefileshere...--><scriptsrc="src/Player.js"></script><scriptsrc="src/Song.js"></script>

Page 469: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

<!--includespecfileshere...--><scriptsrc="spec/SpecHelper.js"></script><scriptsrc="spec/PlayerSpec.js"></script>

ThefirstthreeareJasmine'sownframeworkfiles.Thenextsectionincludesthesourcefileswewanttotestandtheactualtestspecifications.

Let'sexperimentwithJasmineviaaveryordinaryexample.Createabigfatjavascriptcode.jsfileandplaceitinthesrc/directory.Thefunctionwewilltestisasfollows:

functioncapitalizeName(name){returnname.toUpperCase();}

Thisisasimplefunctionthatdoesonesinglething.Itreceivesastringandreturnsacapitalizedstring.Wewilltestvariousscenariosaroundthisfunction.Thisistheunit ofcode,whichwediscussedearlier.

Next,createthetestspecifications.CreateoneJavaScriptfile,test.spec.js,andplaceitinthespec/directory.YouwillneedtoaddthefollowingtwolinesintoyourSpecRunner.html:Thefileshouldcontainthefollowing:

<scriptsrc="src/bigfatjavascriptcode.js"></script><scriptsrc="spec/test.spec.js"></script>

Theorderofthisinclusiondoesnotmatter.WhenwerunSpecRunner.html,youwillseesomethinglikethefollowingimage:

Page 470: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ThisistheJasminereportthatshowsdetailsaboutthenumberofteststhatwereexecutedandthecountoffailuresandsuccesses.Now,let'smakethetestcasefail.Wewanttotestacasewhereanundefined variable is passed to the function. Let's add one more test case, as follows:

it("canhandleundefined",function(){varstr=undefined;expect(capitalizeName(str)).toEqual(undefined);});

Now,whenyourunSpecRunner,youwillseethefollowingresult:

Asyoucansee,thefailureisdisplayedforthistestcaseinadetailederrorstack.Now,wewillgoaboutfixingthis.InyouroriginalJScode,handleundefinedasfollows:

functioncapitalizeName(name){if(name){returnname.toUpperCase();}}

Withthischange,yourtestcasewillpass,andyouwillseethefollowingresultintheJasminereport:

Page 471: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thisisverysimilartowhatatest-drivendevelopmentwouldlooklike.Youwritetestcasesandthenfillthenecessarycodetoconfirmtothespecificationsandrerunthetestsuite.Let'sunderstandthestructureoftheJasminetests.

Ourtestspecificationlookslikethefollowingpieceofcode:

describe("TestStringUtilities",function(){it("convertstocapital",function(){varstr="albert";expect(capitalizeName(str)).toEqual("ALBERT");});it("canhandleundefined",function(){varstr=undefined;expect(capitalizeName(str)).toEqual(undefined);});});

Thedescribe("TestStringUtilities"iswhatatestsuiteis.Thenameofthetestsuiteshoulddescribetheunit-of-codewearetesting;thiscanbeafunctionoragroupofrelatedfunctionality.Inside the specs, you will call the global Jasmine function,it, to which you will pass the title ofthe spec and the function that validates the condition of the testcase This function is the actual testcase.Youcancatchoneormoreassertionsorthegeneralexpectationsusingtheexpectfunction.Whenallexpectationsaretrue,yourspecispassed.YoucanwriteanyvalidJavaScriptcodeinsidedescribeanditfunctions.Thevaluesyouverifyaspartoftheexpectationsarematchedusingamatcher.Inourexample,toEqualisthematcherthatmatchestwovaluesforequality.Jasminecontainsarichsetofmatchestosuitmostofthecommonusecases.SomecommonmatcherssupportedbyJasmineareasfollows:

Page 472: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

toBe:Thismatcher checksiftwoobjectsbeingcomparedareequal. Thisissameasthe===comparison.Forexample,checkoutthefollowingcodesnippet:

vara={value:1};varb={value:1};expect(a).toEqual(b);//success,sameas==comparisonexpect(b).toBe(b);//failure,sameas===comparisonexpect(a).toBe(a);//success,sameas===comparison

not:Youcannegateamatcherwithanotprefix.Forexample,expect(1).not.toEqual(2);willnegatethematchmadebytoEqual().toContain:Thischecksifanelementispartofanarray.ItisnotanexactobjectmatchastoBe.Forexample,takealookatthefollowinglinesofcode:

expect([1,2,3]).toContain(3);expect("astronomy is a science").toContain("science");

toBeDefinedandtoBeUndefined:Thesetwomatchesarehandytocheckwhetheravariableisundefinedornot.toBeNull:Thischecksifavariable'svalue isnull.toBeGreaterThanandtoBeLessThan:Thesematcherperformsnumericcomparison(worksonstringstoo).Forexample,considerthefollowingpieceofcode:

expect(2).toBeGreaterThan(1);expect(1).toBeLessThan(2);expect("a").toBeLessThan("b");

AninterestingfeatureofJasmineisthespies.Whenyouarewritingalargesystem,itisnotpossibletomakesurethatallsystemsarealwaysavailableandcorrect.Atthesametime,youdon't want your unit tests to fail due to a dependency that may be broken or unavailable. Tosimulateasituationwherealldependenciesareavailableforaunitofcodewewanttotest,wewillmockthisdependencytoalwaysgivetheresponseweexpect.Mockingisanimportantaspectoftesting,andmosttestingframeworksprovidesupportformocking.JasmineallowsmockingusingafeaturecalledaSpy.Jasminespiesessentiallystubsthefunctionswemaynothavereadyatthetimeof writingthetestcase,butaspartofthefunctionality,wewillneedtotrackthatweareexecutingthosedependenciesandnotignoringthem.Considerthefollowingexample:

describe("mockingconfigurator",function(){varcofigurator=null;varresponseJSON={};

beforeEach(function(){configurator={submitPOSTRequest:function(payload){//Thisisamockservicethatwilleventuallybereplaced//byarealserviceconsole.log(payload);

Page 473: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

return{"status":"200"};}};spyOn(configurator,'submitPOSTRequest').and.returnValue({"status":"200"});configurator.submitPOSTRequest({"port":"8000","client-encoding":"UTF-8"});});

it("thespywascalled",function(){expect(configurator.submitPOSTRequest).toHaveBeenCalled();});

it("theargumentsofthespy'scallaretracked",function(){expect(configurator.submitPOSTRequest).toHaveBeenCalledWith({"port":"8000","client-encoding":"UTF-8"});});});

Inthisexample,whilewearewritingthistestcase,weeitherdon'thavetherealimplementationofthedependency,configurator.submitPOSTRequest(),orsomeoneisfixingthisparticulardependency;inanycase,wedon'thaveitavailable.Forourtesttowork,wewillneedtomockit.Jasminespiesallowustoreplaceafunctionwithitsmockandallowsustotrackitsexecution.

Inthiscase,wewillneedtoensurethatwecalledthedependency.Whentheactualdependencyisready,wewillrevisitthistestcasetomakesureitfitsthespecifications;however,atthistime,allweneedtoensurethatthedependencyiscalled.JasminefunctiontohaveBeenCalled()letsustracktheexecutionofafunctionthatmaybeamock.WecanusetoHaveBeenCalledWith(),whichallowsustodetermineifthestubfunctionwascalledwithcorrectparameters.ThereareseveralotherinterestingscenariosyoucancreateusingJasminespies.Thescopeofthischapterwon'tpermitustocoverthemall,butIwouldencourageyoutodiscoverthoseareasonyourown.

Page 474: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Mocha,ChaiandSinon

ThoughJasmineisthemostprominentJavaScripttestingframework,mochaandchaiaregainingprominenceintheNode.jsenvironment:

Mocha is the testing framework used to describe and run test casesChaiistheassertionlibrarysupportedbyMochaSinoncomesinhandywhilecreatingmocksandstubsforyourtests

Wewon'tdiscusstheseframeworksinthisbook;however,experienceonJasminewillbehandyifyouwanttoexperimentwiththeseframeworks.

Page 475: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

JavaScript debuggingIf you are not a completely new programmer, I am sure you must have spent some amount of timedebuggingyourorsomeoneelse'scode.Debuggingisalmostlikeanartform.Everylanguagehasdifferentmethodsandchallengesaroundthedebugging.JavaScriptistraditionallyadifficultlanguagetodebug.Ihavespentdaysandnightsinmisery,tryingtodebugbadlywrittenJavaScriptcodeusingalert()functions.Fortunately,modernbrowsers,suchasMozilla,Firefox,andGoogleChrome,haveexcellentDeveloperToolstohelpdebugJavaScriptinthebrowser.ThereareIDEslikeIntelliJIDEAandWebStormwithgreatdebuggingsupportforJavaScriptandNode.js.Inthischapter,wewillfocusprimarilyonGoogleChrome'sbuilt-indevelopertool.FirefoxalsosupportsFirebugextensionandhasexcellent built-indevelopertools,butastheybehave moreorlessthesameasGoogleChrome'sDeveloperTools,wewilldiscusscommondebuggingapproachesthatworkinbothofthesetools.

Beforewetalkaboutthe specificdebuggingtechniques,let'sunderstandthetypeoferrorswewouldbeinterestedinwhilewetrytodebugourcode.

Page 476: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Syntaxerrors

WhenyourcodehassomethingthatdoesnotconfirmtotheJavaScriptlanguagegrammar,theinterpreterrejectsthatpieceofcode.TheseareeasytocatchifyourIDEishelpingyouwithsyntaxchecking.MostmodernIDEshelpwiththeseerrors.Earlier,wediscussedtheusefulnessoftools,suchasJSLintandJSHint,aroundcatchingsyntaxissueswithyourcode.Theyanalyzethecodeandflagerrorsinthesyntax.TheJSHintoutputcanbeveryilluminating.Forexample,thefollowingoutputshowsupsomanythingswe canchangeinthecode.Thefollowingcodesnippetisfromoneofmyexistingprojects:

tempgit:(dev_branch)Xjshinttest.jstest.js:line1,col1,Usethefunctionformof"usestrict".test.js:line4,col1,'destructuringexpression'isavailableinES6(useesnextoption)orMozillaJSextensions(usemoz).test.js:line44,col70,'arrowfunctionsyntax(=>)'isonlyavailableinES6(useesnextoption).test.js:line61,col33,'arrowfunctionsyntax(=>)'isonlyavailableinES6(useesnextoption).test.js:line200,col29,Expected')'tomatch'('fromline200andinsteadsaw':'.test.js:line200,col29,'functionclosureexpressions'isonlyavailableinMozillaJavaScriptextensions(usemozoption).test.js:line200,col37,Expected'}'tomatch'{'fromline36andinsteadsaw')'.test.js:line200,col39,Expected')'andinsteadsaw'{'.test.js:line200,col40,Missingsemicolon.

Usingstrict

Webrieflydiscussedthe strictmodeinearlierchapters.Whenyouenablestrictmode,JavaScriptstopsbeingacceptingofsyntacticalerrorsinyourcode.Ratherthansilentlyfailing,strictmodemakesthesefailurethrowerrorsinstead.Italsohelpsyouconvertmistakesintoactualerrors.Therearetwowaysofenforcingstrictmode.Ifyouwantthestrictmodefortheentirescript,youcanjustaddtheusestrictstatement(withthequotes)asthefirstlineofyourJavaScriptprogram.Ifyouwantaspecificfunctiontoconfirmtostrictmode,youcanaddthedirectiveasthefirst line of a function. For example, take a look at the following code snippet:

functionstrictFn(){//ThislinemakesEVERYTHINGunderthisscrictmode'usestrict';...functionnestedStrictFn(){//Everythinginthisfunctionisalsonested...}}

Page 477: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Runtimeexceptions

Theseerrorsappearwhenyouexecutethecode,trytorefertoanundefinedvariable,ortrytoprocessanull.Whenaruntimeexceptionoccurs,anycodeafterthatparticularline,whichcausedtheexception,doesnotgetexecuted.Itisessentialtocorrectlyhandlesuchexceptionalscenariosinthecode.Whileexceptionhandlingcanhelppreventcrashes,theyalsoaidindebugging.Youcanwrapthecodethatmayencounteraruntimeexceptionintoatry{}block.Whenanycodeinsidethisblockgeneratesaruntimeexception,acorrespondinghandlercapturesit.Thehandlerisdefinedbyacatch(exception){}block.Let'sclarifythisusingthefollowingexample:

try{vara=doesnotexist;//throwsaruntimeexception}catch(e){console.log(e.message);//handletheexception//prints-"doesnotexistisnotdefined"}

Inthisexample,thevara=doesnotexistlinetriestoassignanundefinedvariable,doesnotexist,toanothervariablea.Thiscausesaruntimeexception.Whenwewrapthisproblematiccodeintotry{}catch(){}blockorwhentheexceptionoccurs(oristhrown),theexecutionstopsinthetry{}blockandgoesdirectlytothecatch(){}handler.Thecatchhandlerisresponsibleforhandlingtheexceptionalscenario.Inthiscase,wearedisplayingtheerrormessageontheconsolefordebuggingpurposes.Youcanexplicitlythrowanexceptiontotriggeranunhandledscenariointhecode.Considerthefollowingexample:

functionengageGear(gear){if(gear==="R"){console.log("Reversing");}if(gear==="D"){console.log("Driving");}if(gear==="N"){console.log("Neutral/Parking");}thrownewError("InvalidGearState");}try{engageGear("R");//ReversingengageGear("P");//InvalidGearState}catch(e){console.log(e.message);}

Inthisexample,wearehandlingvalidstatesofagearshift:R,N,andD;however,whenwereceiveaninvalidstate,weareexplicitlythrowinganexceptionclearlystatingthereason.Whenwecallthefunctionwhichwethinkmaythrowanexception,wewillwrapthecodeinthetry{}blockandattachacatch(){}handlerwithit.Whentheexceptioniscaughtbythecatch()block,wewillhandletheexceptionalconditionappropriately.

Page 478: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Console.logandasserts

Displayingthestateofexecutiononconsolecanbeveryusefulwhiledebugging.Although,moderndevelopertoolsallowyoutoputbreakpointsandhaltexecutiontoinspectaparticularvalueduringruntime.Youcanquicklydetectsmallissuesbyloggingsomevariablestateontheconsole.

Withtheseconceptswithus,let'sseehowwecanuseChromeDeveloperToolstodebugJavaScriptcode.

ChromeDeveloperTools

You can start Chrome Developer Tools by clickingmenu |More tools |Developer Tools. Take alookatthefollowingscreenshot:

Page 479: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chromedevelopertoolopensuponthelowerpaneofyourbrowserandhasabunchofveryusefulsections.Considerthefollowingscreenshot:

TheElementspanelhelpsyouinspectandmonitortheDOMtreeandassociatedstylesheetforeachofthesecomponents.

TheNetworkpanelisusefultounderstandnetworkactivity.Forexample,youcanmonitortheresourcesbeingdownloadedoverthenetworkinrealtime.

ThemostimportantpaneforusistheSourcespane.ThispaneiswheretheJavaScriptandthedebuggeraredisplayed.Let'screateasampleHTMLwiththefollowingcontent:

<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>Thistest</title><scripttype="text/javascript">functionengageGear(gear){if(gear==="R"){console.log("Reversing");}if(gear==="D"){console.log("Driving");}if(gear==="N"){console.log("Neutral/Parking");}thrownewError("InvalidGearState");}try{engageGear("R");//ReversingengageGear("P");//InvalidGearState}catch(e){console.log(e.message);

}</script></head><body></body></html>

Page 480: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SavethisHTMLfileandopenitinGoogleChrome.OpenDeveloperToolsinthebrowser,andyouwillseethefollowingscreen:

ThisistheviewoftheSourcespanel.YoucanseetheHTMLandembeddedJavaScriptsourceinthispanel.YoucanseetheConsolewindowaswell,andyoucanseethatthefileisexecutedandtheoutputisdisplayedonconsole.

Ontherightside,youwillseethedebuggerwindow,asshowninthefollowingscreenshot:

Page 481: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

IntheSourcespanel,clickonthelinenumbers8and15toaddabreakpoint.Thebreakpointsallowyoutostopexecutionofthescriptatthespecifiedpoint.Considerthefollowingscreenshot:

Page 482: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inthedebugpane,youcanseeallexistingbreakpoints.Takealookatthefollowingscreenshot:

Now,whenyourerunthesamepage,youwillseethattheexecutionstopsatthedebugpoint.Considerthefollowingscreenshot:

Page 483: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

This window now has all the action. You can see that the execution is paused on line 15. In thedebugwindow,youcanseewhichbreakpointisbeingtriggered.YoucanalsoseetheCallStackandresumeexecutioninseveralways.Thedebugcommandwindowhasabunchofactions.Takealookatthefollowingscreenshot:

Youcanresumeexecution,whichwillexecuteuntilthenextbreakpoint,byclickingonthefollowingbutton:

Whenyoudothat,theexecutioncontinuesuntilthenextbreakpointisencountered.Inourcase,wewillhaltatline8.Considerthefollowingscreenshot:

Page 484: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

YoucanobservethattheCallStackwindowshowshowwearrivedatline8.TheScopepanelshowstheLocalscopewhereyoucanseethevariablesinthescopewhenthebreakpointwasarrivedat.YoucanalsoStep-IntoorStep-overthenextfunction.

ThereareotherveryusefulmechanismstodebugandprofileyourcodeusingChromeDeveloperTools.Iwouldsuggestyoutoexperimentwiththetoolandmakeitapartofyourregulardevelopmentflow.

Page 485: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryBoth testing and debugging phases are essential to developing robust JavaScript code. TDD andBDDareapproachescloselyassociatedwiththeagilemethodologyandiswidelyembracedbytheJavaScriptdevelopercommunity.Inthischapter,wereviewedbestpracticesaroundTDDandtheusageofJasmineasthetestingframework.Additionally,wesawvariousmethodsofdebuggingJavaScriptusingChromeDeveloperTools.

Inthenextchapter,wewillexplorethenewandexcitingworldofES6,DOMManipulationandcross-browserstrategies.

Page 486: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 13. Reactive Programming andReactAlongwithES6,severalnewideasareemerging.Thesearepowerfulideasandcanhelpyoubuildpowerfulsystemswithmorestreamlinedcodeanddesign.Inthischapter,wewillintroduceyoutotwosuchideas-reactiveprogrammingandreact.Althoughtheysoundsimilar,theyareverydifferent.Thischapterdoesnotgointopracticaldetailsoftheseideasbutgivesyounecessaryinformationtobecomeawareofwhattheseideasarecapableof.Withthatinformation,youcanstartincorporatingtheseideasandframeworksintoyourprojects.Wewilldiscussthebasicideaofreactiveprogrammingandtakeabitmoredetailedlookatreact.

Page 487: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Reactive programmingReactive programming is getting a lot of focus lately. This idea is relatively new and, like manynewideas,haslotsofconfusing,andsometimescontradictoryinformationfloatingaround.Wediscussedasynchronousprogrammingearlierinthisbook.JavaScripttakesasynchronousprogrammingtonewheightsbyprovidingfirstclasslanguageconstructsthatsupportit.

Reactiveprogrammingisessentiallyprogrammingwithasynchronouseventstreams.Aneventstreamisasequenceofeventshappeningovertime.Considerthefollowingdiagram:

Intheprecedingdiagram,timepassesfromlefttorightanddifferenteventsoccurovertime.Astheeventhappensovertime,wecanaddaneventlistenertothiswholesequence.Wheneveraneventhappens,wecanreacttoitbydoingsomething.

AnothertypeofsequenceinJavaScriptisanarray.Forexample,considerthefollowinglinesofcode:

vararr=[1,1,13,'Rx',0,0];console.log(arr);>>>[1,1,13,"Rx",0,0]

Inthiscase,theentiresequencelivesinmemoryatthesametime.However,incaseofeventstream,eventshappenovertimeandthereisnostateatthispointoftime.Considerthefollowinglinesofcode:

vararr=Rx.Observable.interval(500).take(9).map(a=>[1,1,13,'Rx',0,0][a]);

Page 488: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varresult=arr;result.subscribe(x=>console.log(x));

Don'tworrytoomuchaboutwhatisgoingoninthisexamplejustyet.Here,eventsarehappeningovertime.Insteadofhavingafixedbunchofelementsinanarray,heretheyarehappeningovertime,after500ms.

Wewilladdaneventlistenertothearreventstream,andwhenaneventhappens,wewillprinttheelementonconsole.Youcanseeasimilaritybetweenthemethodsinarraysandtheeventstreams.Now,toexpandonthissimilarity,let'ssay,youwanttofilterallnon-numbersfromthislist.Youcanusethemapfunctiontothiseventstream,justlikeyouwoulduseitonanarray,andthenyouwouldwanttofiltertheresultstoshowonlyintegers.Considerthefollowinglinesofcode:

vararr=[1,1,13,'Rx',0,0];varresult=arr.map(x=>parseInt(x)).filter(x=>!isNan(x));console.log(result);

Interestingly,thesamemethodsworkforeventstreamsaswell.Takealookatthefollowingcodeexample:

vararr=Rx.Observable.interval(500).take(9).map(a=>[1,1,13,'Rx',0,0][a]);varresult=arr.map(x=>parseInt(x)).filter(x=>!isNaN(x));result.subscribe(x=>console.log(x));

Thesearesimplerexamplesjusttomakesureyoustartseeinghoweventstreamsflowovertime.Pleasedon'tbotheraboutthesyntaxandconstructjustyet.Beforewecanlookatthem,wewillneedtomakesureweunderstandhowtothinkinreactiveprogramming.Eventstreamsarefundamentaltoreactiveprogramming;theyallow youtodefinethedynamicbehaviorofavalueatdeclarationtime(definitiontakenfromAndreStaltz'sblog).

Let'ssayyouhaveanavariable,whichhasinitiallythevalue3.Then,youhaveabvariable,whichis10*a.Ifweconsolelogoutb,wewillsee30.Considerthefollowinglinesofcode:

leta=3;let b = a * 10;

console.log(b);//30a=4;console.log(b);//Still30

Weknowtheresultisverystraightforward.Whenwechangethevalueofato4,thevalueofbwillnotchange.Thisishowstaticdeclarationworks.Whenwetalkaboutreactiveprogrammingandeventstreams,thisistheareawherepeoplefinddifficultyinunderstandinghoweventsflow.Ideally, we want to create a formula, b=a*10, and over time, whenever the value of a changes,the changed value is reflected in the formula.

Page 489: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thatiswhatwecanaccomplishwitheventstreams.Let'ssayaisaneventstreamofjustthevalue3.Then,wehavestreamB,whichisstreamAmapped.Eachoftheseavalueswillbemappedto10*a.

IfweaddaneventlistenertothatstreamB,andweconsolelog,wewillseebbeing30.Takealookatthefollowingexample:

varstreamA=Rx.Observable.of(3,4);varstreamB=streamA.map(a=>10*a);streamB.subscribe(b=>console.log(b));

Ifwedothis,wehaveaneventstreamthatsimplyhasjusttwoevents.Ithasevent3,andthenithasevent4,andbwillchangeaccordinglywheneverachanges.Ifwerunthis,weseebbeing30and40.

Nowthatwehavespentsometimeingettingthebasicsofreactiveprogrammingsorted,youmayaskthefollowingquestion.

Page 490: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Whyshouldyouconsiderreactiveprogramming?

AswewritehighlyresponsiveandinteractiveUIapplicationsonmodernwebandmobile,thereisastrongneedtofinda waytodealwithreal-timeeventswithoutstoppingtheuserinteractionsontheUI.WhenyouaredealingwithmultipleUI andservereventsbeingfired,youwillbespendingmostofyourtimewritingcodetodealwiththeseevents.Thisistedious.Reactiveprogramminggivesyouastructuredframeworktodealwithasynchronouseventswithminimalcodewhileyoufocusonthebusinesslogicforyourapplication.

ReactiveprogrammingisnotlimitedtoJavaScript.Reactiveextensionsareavailableinmanyplatformsandlanguages,suchasJava,Scala,Clojure,Ruby,Python,andObjectC/Cocoa.Rx.jsandBacon.jsarepopularJavaScriptlibrariesthatprovidereactiveprogrammingsupport.

AdeepdiveintoRx.jsisnottheintentionofthischapter.Theideawastointroduceyoutotheideaofreactiveprogramming.Ifyouarekeenonadoptingreactiveprogrammingforyourprojects,youshouldtakelookatAndreStaltz'sexcellentintroduction(https://gist.github.com/staltz/868e7e9bc2a7b8c1f754).

Page 491: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ReactReact is taking the JavaScript world by storm. Facebook created the react framework to solve anage-oldproblem-howtodealefficientlywiththeviewpartofthetraditionalModel-View-Controllerapplications.

Reactprovidesadeclarativeandflexiblewaytobuilduserinterfaces.Themostimportantthingtorememberaboutreactisthatitdealswithonlyonething-theview,ortheUI.Reactdoesnotdealwithdata,databindings,oranythingelse.Therearecompleteframeworks,suchasAngular,thatdealwithdata,bindings,andUI;Reactisnotthat.

ReactgivesatemplatelanguageandasmallsetoffunctionstorenderHTML.Reactcomponentscanstoretheirownstateinmemory.Tobuildafull-fledgedapplication,youwillneedotherpiecesaswell;Reactisjusttohandletheviewpartofthatapplication.

A big challenge when writing complex UI is to manage state of the UI elements when the modelchanges.ReactprovidesadeclarativeAPIsothatyoudon'thavetoworryaboutexactlywhatchangesoneveryupdate.Thismakeswritingapplicationsaloteasier.ReactusesVirtualDOManddiffingalgorithm,sothatcomponentupdatesarepredictablewhilebeingfastenoughforhigh-performanceapps.

Page 492: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Virtual DOMLet's take a moment to understand what is a Virtual DOM. We discussed DOM (document objectmodel),atreestructureofHTMLelementonawebpage.DOMisdefacto,andtheprimaryrenderingmechanismoftheweb.TheDOMAPIs,suchasgetElementById(),allowtraversingandmodificationoftheelementsintheDOMtree.DOMisatreeandthisstructureworksprettywellwithtraversalandupdatingofelements.However,boththetraversingandupdatingofDOMisnotveryquick.Foralargepage,theDOMtreecanbeprettybig.When youwantacomplexUIthathasbunchofuserinteractions,updatingDOMelementscanbetediousandslow.WehavetriedjQueryandotherlibrariestoreducethetedioussyntaxforfrequentDOMmodifications,butDOMasastructureitselfisquitelimited.

Whatifwedon'thavetotraversetheDOMoverandoveragaintomodifyelements?Whatifyoujustdeclarehowacomponentshouldlooklikeandletsomeonehandlethelogicofhowtorenderthatcomponent?reactdoesexactlythat.ReactletsyoudeclarehowyouwantyourUIelementtolooklikeandabstractsoutlow-levelDOMmanipulationAPIs.Apartfromthisveryusefulabstraction,reactdoessomethingprettysmarttosolvetheperformanceproblemaswell.

ReactusessomethingcalledaVirtualDOM.AvirtualDOMisalightweightabstractionoftheHTMLDOM.Youcanthinkofitasalocalin-memorycopyoftheHTMLDOM.Reactusesittodo all computations necessary to render the state of a UI component.

Youcanfindmoredetailsofthisoptimizationathttps://facebook.github.io/react/docs/reconciliation.html.

React'sprimarystrength,however,isnotjustVirtualDOM.Reactisafantasticabstractionthatmakescomposition,unidirectionaldataflow,andstaticmodelingeasierwhiledevelopinglargeapplications.

Page 493: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Installing and running reactFirst, let's install react. Earlier, installing and getting react set up on your machine needed a bunchofdependenciestobetakencareof.However,wewillusearelativelyfasterwaytogetreactupandrunning.Wewillusecreate-react-apptowhichwecaninstallreactwithoutanybuildconfiguration.Installationisdonevianpmwhichisasfollows:

npminstall-gcreate-react-app

Here,weareinstallingthecreate-react-appnodemoduleglobally.Oncecreate-react-appisinstalled,youcansetupthedirectoryforyourapplication.Considerthefollowingcommands:

create-react-appreact-appcdreact-app/

npm start

Then,openhttp://localhost:3000/toseeyourapp.Youshouldseesomethinglikethefollowingscreenshot:

Ifyouopenthedirectory inaneditor,youwillseeseveralfilescreatedforyou,asyoucanseein

Page 494: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

thefollowingscreenshot:

Page 495: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Inthisproject,node_modulesarethedependenciesrequiredtorunthisprojectanddependenciesofreactitself.Theimportantdirectoryissrc,wherethesourcecodeiskept.Forthisexample,let'skeeponlytwofiles-App.jsandindex.js.The/public/index.htmlfileshouldcontainjusttherootdiv,whichwillbeusedasatargetforourreactcomponents.Considerthefollowingcodesnippet:

<!doctypehtml><html lang="en">

<head><title>ReactApp</title></head><body><divid="root"></div></body></html>

Themomentyoumakethischange,youwillseethefollowingerror:

Beauty of developing with react is that the code changes are live-reloaded, and you can getimmediatefeedback.

Next,clearoffallcontentofApp.js,andreplaceitwiththefollowinglinesofcode:

importReactfrom'react';constApp=()=><h1>HelloReact</h1>exportdefaultApp

Now,gotoindex.jsandremovetheimport./index.css;line.Withoutyoudoinganything,suchasrestartingserverandrefreshingbrowser,youwillseethemodifiedpageonthebrowser.Considerthefollowingscreenshot:

Page 496: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BeforewecreateaHelloWorldreactcomponent,acoupleofimportantthingstonoticesofar.

InApp.jsandindex.js,weareimportingtwolibrariesnecessarytocreatereactcomponents.Considerthefollowinglinesofcode:

importReactfrom'react';importReactDOMfrom'react-dom';

Here,we'reimportingReact,whichisthelibrarythatallowsustobuildreactcomponents.We'realsoimportingReactDOM,whichisthelibrarythatallowsustoplaceourcomponentsandworkwiththeminthecontextoftheDOM.Then,we'reimportingthecomponentthatwejustworkedon-theAppcomponent.

We also created our first component in App.js. Consider the following line of code:

constApp=()=><h1>HelloReact</h1>

Thisisastatelessfunctioncomponent.Theotherwaytocreateacomponentistocreateaclasscomponent.Wecanreplacetheprecedingcomponentwiththefollowingclasscomponent:

classAppextendsReact.Component{render(){return<h1>HelloWorld</h1>}}

Thereareabunchofinterestingthingsgoingonhere.First,wearecreatingaclasscomponentwiththeclasskeywordthatextendsfromthesuperclassReact.Component.

OurcomponentAppisareactcomponentclassorreactcomponenttype.Acomponenttakesinparameters,alsocalledprops,andreturnsahierarchyofviewstodisplayviatherenderfunction.

Page 497: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Therendermethodreturnsadescriptionofwhatyouwanttorender,andthenreacttakesthatdescriptionandrendersittothescreen.Inparticular,renderreturnsareactelement,whichisalightweightdescriptionofwhattorender.MostreactdevelopersuseaspecialsyntaxcalledJSX,whichmakesiteasiertowritethesestructures.The<div/>syntaxistransformedatbuildtimetoReact.createElement('div').TheJSXexpression,<h1>HelloWorld</h1>,istransformedatbuildtimeintothefollowing:

returnReact.createElement('h1',null,'HelloWorld');

Thedifferencebetweentheclasscomponentandstatelessfunctioncomponentisthattheclasscomponentcancontaina statewhilethestateless(hencethename)functioncomponentcannot.

Therendermethodofthereactcomponentisallowedtoreturnonlyasinglenode.Ifyoudosomethinglikethefollowing:

return<h1>HelloWorld</h1><p>ReactRocks</p>

Youwillgetthefollowingerror:

Errorin./src/App.jsSyntaxerror:AdjacentJSXelementsmustbewrappedinanenclosingtag(4:31)

ThisisbecauseyouareessentiallyreturningtwoReact.createElement functions,andthatisnotvalidJavaScript.Whilethismayseemlikeadealbreaker,thisiseasytosolve.Wecanwrapournodesintoaparentnodeandreturnthatparentnodefromtherenderfunction.Wecancreateaparentdivandwrapothernodesunderit.Considerthefollowingexample:

render(){return(<div><h1>HelloWorld</h1><p>ReactRocks</p></div>)}

Page 498: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Componentsandprops

ComponentscanbeconceptuallyconsideredasJavaScriptfunctions.Theytakearbitrarynumberofinputslikenormalfunctions.Theseinputsarecalledprops.Toillustratethis,let'sconsiderthefollowingfunction:

functionGreet(props){return<h1>Hello,{props.name}</h1>;}

Thisisanormalfunctionandalsoavalidreactcomponent.IttakesaninputcalledpropsandreturnsavalidJSX.Wecanusethepropsinside JSXusingcurlybracesandpropertiessuchasnameusingastandardobjectnotation.NowthatGreetisafirstclassreactcomponent,let'suseitintherender()functionasfollows:

render(){return(return<Greetname="Joe"/>)}

WearecallingGreet()asanormalcomponentandpassingthis.propstoit.Itisrequiredtocapitalizeyourowncomponents.ReactconsiderscomponentnamesstartingwithalowercaseasstandardHTMLtagsandexpectscustomcomponentnamestostartwithacapitalletter.Aswesawearlier,wecancreateaclasscomponentusingES6class.ThiscomponentisasubclassofReact.component.AnequivalentcomponenttoourGreetfunctionisasfollows:

classGreetextendsReact.Component{render(){return<h1>Hello,{this.props.name}</h1>}}

Forallpracticalpurposes,wewillusethismethodofcreatingcomponents.Wewillsoonknowwhy.

Oneimportantpointtonoteisthatacomponentcannotmodifyitsownprops.Thismayseemlikealimitationbecause,inalmostallnon-trivialapplications,youwillwantuserinteractionswheretheUIcomponentstateischangedinreact,forexample,updatedateofbirthinaform,propsareread-onlybutthereisamuchrobustmechanismtohandleUIupdates.

Page 499: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

State

Stateissimilartoprops,butitisprivateandfullycontrolledbythecomponent.Aswesawearlierthatbothfunctionalandclasscomponentsareequivalentinreact,oneimportantdistinctionisthatthestateisavailableonlyinclasscomponents.Hence,forallpracticalpurposes,wewilluseclasscomponents.

Wecanchangeourexistinggreetingexampletousestate,andwheneverthestatechanges,wewillupdateourGreetcomponenttoreflectthechangedvalue.

First,wewillsetupthestateinsideourApp.js,asfollows:

classGreetextendsReact.Component{constructor(props){super(props);

this.state={greeting:"thisisdefaultgreetingtext"}

}render(){return<h1>{this.state.greeting},{this.props.name}</h1>}}

Thereareafewimportantthingstonoticeinthisexample.First,wearecallingclassconstructortoinitializethis.state.Wealsocallthebaseclassconstructor,super(),andpasspropstoit.Aftercallingsuper(),weinitializeourdefaultstatebysettingthis.statetoanobject.Forexample,weassignagreetingpropertywithavaluehere.Intherendermethod,wewillusethispropertyusing{this.state.greeting}.Havingsetupourinitialstate,wecanaddUIelementstoupdatethisstate.Let'saddaninputbox,andonchangeofthatinputbox,wewillupdateourstateandthegreetingelement.Considerthefollowinglinesofcode:

classGreetextendsReact.Component{constructor(props){super(props);this.state={greeting:"thisisdefaultgreetingtext"}}

updateGreeting(event){this.setState({greeting:event.target.value,})}render(){

Page 500: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

return(<div><inputtype="text"onChange={this.updateGreeting.bind(this)}/><h1>{this.state.greeting},{this.props.name}</h1></div>)}}

Here,weaddaninputboxandupdatethestateofthecomponentwhentheonChangemethodoftheinputboxisinvoked. WeuseacustomupdateGreeting()methodtoupdatethestatebycallingthis.setStateandupdatingtheproperty.Whenyourunthisexample,youwillnoticethatasyoutypesomethingonthetextbox,onlythegreetingelementisupdatedandnotthename.Takealookatthefollowingscreenshot:

Animportantfeatureofreactisthefactthatareactcomponentcanoutputorrenderotherreactcomponents.We'vegotaverysimplecomponenthere.Ithasastatewithavalueoftext.It'sgotanupdatemethodwhichwillupdatethatvalueoftextfromanevent.Whatwe'lldoiscreateanewcomponent.Thiswillbeastatelessfunctioncomponent.We'llcallitwidget.Itwilltakeinprops.We'llreturnthisJSXinputrighthere.Considerthefollowingcodesnippet:

render(){return(<div><Widgetupdate={this.updateGreeting.bind(this)}/>

<Widget update={this.updateGreeting.bind(this)} />

<Widgetupdate={this.updateGreeting.bind(this)}/><h1>{this.state.greeting},{this.props.name}</h1></div>)}

Page 501: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}constWidget=(props)=><inputtype="text"onChange={props.update}/>

First,weextractourinputelementintoastatelessfunctioncomponentandcallitaWidget.Wepasspropstothiscomponent.Then,wechangeonChangetouseprops.update.Now,insideourrendermethod,weusetheWidgetcomponentandpassapropupdatethatbindstheupdateGreeting()method.NowthatWidgetisacomponent,wecanreuseitanywhereintheGreetcomponent.WearecreatingthreeinstancesoftheWidget,andwhenanyoftheWidgetisupdated,thegreetingtextisupdated,asshowninthefollowingscreenshot:

Page 502: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Lifecycleevents

Whenyouhaveabunchofcomponentswithseveralstatechangesandevents,thehousekeepingbecomesimportant.Reactprovidesyouwithseveralcomponentlifecyclehookstohandlelifecycleeventsofcomponents.Understandingthecomponentlifecyclewillenableyoutoperformcertainactionswhenacomponentiscreatedordestroyed.Furthermore,itgivesyoutheopportunitytodecideifacomponentshouldbeupdatedinthefirstplace,andtoreacttopropsorstatechangesaccordingly.

Therearethreephasesthatthecomponentgoesthrough-mounting,updating,andunmouting.Foreachofthesestages,wehavehooks.Takealookatthefollowingdiagram:

Twomethodsarecalledwhenacomponentisinitiallyrendered,getDefaultPropsandgetInitialState,and, astheirnamessuggest,wecansetdefaultprops andinitialstateofacomponentinthesemethods.

ThecomponentWillMountiscalledbeforetherendermethodisexecuted.Wealreadyknowrendertobetheplacewherewereturnthecomponenttoberendered.Assoonastherendermethodfinishes,thecomponentDidMountmethodisinvoked.YoucanaccessDOMinthismethod,anditisrecommendedtoperformanyDOMinteractionsinthismethod.

Statechangesinvokeafewmethods.TheshouldComponentUpdatemethodisinvokedbeforetherendermethod,anditletsusdecideifweshouldallowrerenderingorskipit.Thismethodisnevercalledontheinitialrendering.ThecomponentWillUpdatemethod getscalledimmediatelyoncetheshouldComponentUpdatemethodreturnstrue.ThecomponentDidUpdatemethodisrenderedafterrenderfinishes.

Page 503: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Anychangetothepropsobjecttriggerssimilarmethodsasastatechange.OneadditionalmethodcallediscomponentWillReceiveProps;itiscalledonlywhenthepropshavechanged,anditisnotinitialrendering.Youcanupdatestatebasedonnewandoldpropsinthismethod.

WhenacomponentisremovedfromDOM,componentWillUnmountiscalled.Thisisausefulmethodtoperformcleanups.

Greatthingaboutreactisthatwhenyoustartusingit,theframeworkfeels verynaturaltoyou.Thereareveryfewmovingpartsyouwillneedtolearn,andtheabstractionisjustright.

Page 504: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

SummaryThis chapter was aimed at some of the important new ideas that are gaining a lot of prominencelately.Bothreactiveprogrammingandreactcansignificantlyboostprogrammerproductivity.ReactisdefinitelyoneofthemostimportantemergingtechnologiesbackedbythelikesofFacebookandNetflix.

Thischapterwasintendedtogiveyouanintroductiontoboththesetechnologiesandhelpyoustartexploringtheminmoredetail.

Page 505: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Appendix A. Reserved WordsThis appendix provides two lists of reserved keywords as defined in ECMAScript 5 (ES5). Thefirstoneisthecurrentlistofwords,andthesecondisthelistofwordsreservedforfutureimplementations.

There'salsoalistofwordsthatarenolongerreserved,althoughtheyusedtobeinES3.

Youcannotusereservedwordsasvariablenames:

varbreak=1;//syntaxerror

Ifyouusethesewordsasobjectproperties,youhavetoquotethem:

varo={break:1};//OKinmanybrowsers,errorinIEvaro={"break":1};//AlwaysOKalert(o.break);//errorinIEalert(o["break"]);//OK

Page 506: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

KeywordsThe list of words currently reserved in ES5 is as follows:

break

case

catch

continue

debugger

default

delete

do

else

finally

for

function

if

in

instanceof

new

return

switch

this

throw

try

typeof

var

void

while

with

Page 507: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6 reserved wordsThe following keywords are reserved in ES6:

class

const

enum

export

extends

implements

import

interface

let

package

private

protected

public

static

super

yield

Page 508: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Futurereservedwords

Thesekeywordsarenotusedcurrentlybuttheyarereservedforthefutureversions:

enum

await

Page 509: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Previously reserved wordsThe following words are no longer reserved starting with ES5, but it's best to stay away fromthemforthesakeofolderbrowsers:

abstract

boolean

byte

char

double

final

float

goto

int

long

native

short

synchronized

throws

transient

volatile

Page 510: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Appendix B. Built-in FunctionsThis appendix contains a list of the built-in functions (methods of the global object), discussed inChapter3,Functions:

Function Description

parseInt()

Takestwoparameters:aninputobjectandradix;thentriestoreturnanintegerrepresentationoftheinput.Doesn'thandleexponentsintheinput.Thedefaultradixis10(adecimalnumber).ReturnsNaNonfailure.Omittingtheradixmayleadtounexpectedresults(forexampleforinputssuchas08),soit'sbesttoalwaysspecifyit:

>parseInt('10e+3');10 >parseInt('FF');NaN>parseInt('FF',16);255

parseFloat()

Takesaparameterandtriestoreturnafloating-pointnumberrepresentationofit.Understandsexponentsintheinput:

>parseFloat('10e+3');10000>parseFloat('123.456test');123.456

isNaN()

Abbreviatedfrom"IsNotaNumber".Acceptsaparameterandreturnstrueiftheparameterisnotavalidnumber,falseotherwise.Attemptstoconverttheinputtoanumberfirst:

>isNaN(NaN);true>isNaN(123);false>isNaN(parseInt('FF'));true>isNaN(parseInt('FF',16));false

isFinite()

Returnstrueiftheinputisanumber(orcanbeconvertedtoanumber),butifitisnotanumberInfinityor-Infinity.Returnsfalseforinfinityornon-numericvalues:

>isFinite(1e+1000);false>isFinite(-Infinity);false>isFinite("123");true

encodeURIComponent()

ConvertstheinputintoaURL-encodedstring.FormoredetailsonhowURLencodingworks,refertotheWikipediaarticleathttp://en.wikipedia.org/wiki/Url_encode:

>encodeURIComponent('http://phpied.com/');"http%3A%2F%2Fphpied.com%2F">encodeURIComponent('somescript?key=v@lue');

Page 511: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"some%20script%3Fkey%3Dv%40lue"

decodeURIComponent()

TakesanURL-encodedstringanddecodesit:

>decodeURIComponent('%20%40%20');"@"

encodeURI()

URL-encodestheinput,butassumesafullURLisgiven,soreturnsavalidURLbynotencodingtheprotocol(forexample,http://)andhostname(forexample,www.phpied.com):

> encodeURI('http://phpied.com/');"http://phpied.com/">encodeURI('somescript?key=v@lue');"some%20script?key=v@lue"

decodeURI()

OppositeofencodeURI():

>decodeURI("some%20script?key=v@lue");"somescript?key=v@lue"

eval()

AcceptsastringofJavaScriptcodeandexecutesit.Returnstheresultofthelastexpressionintheinputstring.

Tobeavoidedwherepossible:

>eval('1+2');3 >eval('parseInt("123")');123>eval('newArray(1,2,3)');[1,2,3]>eval('newArray(1,2,3);1+2;');3

Page 512: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Appendix C. Built-in ObjectsThis appendix lists the built-in constructor functions outlined in the ECMAScript (ES) standard,togetherwiththepropertiesandmethodsoftheobjectscreatedbytheseconstructors.ES5-specificAPIsarelistedseparately.

Page 513: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ObjectObject() is a constructor that creates objects, for example:

>varo=newObject();

Thisisthesameasusingtheobjectliteral:

>varo={};//recommended

Youcanpassanythingto theconstructoranditwilltrytoguesswhatitisanduseamoreappropriateconstructor.Forexample,passingastringtonewObject()willbethesameasusingthenewString()constructor.Thisisnotarecommendedpractice(it'sbettertobeexplicitthanletguessescreepin),butstillpossible:

>varo=newObject('something');>o.constructor;functionString(){[nativecode]}>varo=newObject(123);>o.constructor;functionNumber(){[nativecode]}

Allotherobjects,built-inorcustom,inheritfrom Object.Sothepropertiesandmethodslistedinthefollowingsectionsapplytoalltypesofobjects.

Page 514: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheObjectconstructor

FollowingarethemembersoftheObjectconstructor:

Property/method Description

Object.prototype

Theprototypeofallobjects(alsoanobjectitself).Anythingyouaddtothisprototypewillbeinheritedbyallotherobjects,sobecareful:

>vars=newString('noodles');>Object.prototype.custom=1;1>s.custom;1

Page 515: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheObject.prototypemembers

Insteadofsaying"membersoftheObjectscreatedbytheObjectconstructor",let'ssayheadings"Object.prototypemembers".ItisthesameforArray.prototypeandsoonfurtherinthisappendix:

Property/method Description

constructor

Pointsbacktotheconstructorfunctionusedtocreatetheobject,inthiscase,Object:

>Object.prototype.constructor===Object;true>varo=newObject();>o.constructor===Object;true

toString(radix)

Returnsastringrepresentationoftheobject.IftheobjecthappenstobeaNumberobject,theradixparameterdefinesthebaseofthereturnednumber.Thedefaultradixis10:

>varo={prop:1};>o.toString();"[objectObject]">varn=newNumber(255);>n.toString();"255">n.toString(16);"ff"

toLocaleString()

SameastoString(),butmatchingthecurrentlocale.Meanttobecustomizedbyobjects,suchasDate(),Number(),andArray()andprovidelocale-specificvalues,suchasdifferentdateformatting.InthecaseofObject()instancesaswithmostothercases,itjustcallstoString().

Inbrowsers,youcanfigureoutthelanguageusingthepropertylanguage(oruserLanguageinIE)ofthenavigatorBOMobject:

>navigator.language;"en-US"

valueOf()

Returnsaprimitiverepresentationofthis,ifapplicable.Forexample,NumberobjectsreturnaprimitivenumberandDateobjectsreturnatimestamp.Ifnosuitableprimitivemakessense,itsimplyreturnsthis:

>varo={};>typeofo.valueOf();"object">o.valueOf()===o;true>varn=newNumber(101);

> typeof n.valueOf();"number">n.valueOf()===n;false>vard=newDate();>typeofd.valueOf();"number">d.valueOf();1357840170137

Page 516: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

hasOwnProperty(prop)

Returnstrueifapropertyisanownpropertyoftheobject,orfalseifitwasinheritedfromtheprototypechain.Alsoreturnsfalseifthepropertydoesn'texist:

>varo={prop:1};>o.hasOwnProperty('prop');true>o.hasOwnProperty('toString');false>o.hasOwnProperty('fromString');false

isPrototypeOf(obj)

Returnstrueifanobjectisusedasaprototypeofanotherobject.Anyobjectfromtheprototypechaincanbetested,notonlythedirectcreator:

>vars=newString('');>Object.prototype.isPrototypeOf(s);true>String.prototype.isPrototypeOf(s);true>Array.prototype.isPrototypeOf(s);false

propertyIsEnumerable(prop)

Returnstrueifapropertyshowsupinafor...inloop:

>vara=[1,2,3];>a.propertyIsEnumerable('length');false>a.propertyIsEnumerable(0);true

Page 517: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript5additionstoobjects

InECMAScript3allobjectpropertiescanbechanged,added,ordeletedatanytime,exceptforafewbuilt-inproperties(forexample,Math.PI).InES5youhavetheabilitytodefinepropertiesthatcannotbechangedordeleted,aprivilegepreviouslyreservedforbuilt-ins.ES5introducestheconceptofpropertydescriptorsthatgiveyoutightercontroloverthepropertiesyoudefine.

Thinkofapropertydescriptorasanobjectthatspecifiesthefeaturesofaproperty.Thesyntaxtodescribethesefeaturesisaregularobjectliteral, sopropertydescriptorshavepropertiesandmethodsoftheirown,butlet'scallthemattributestoavoidconfusion.Theattributesare:

value-whatyougetwhenyouaccessthepropertywritable-canyouchangethispropertyenumerable-shoulditappearinfor...inloopsconfigurable-canyoudeleteitset()-afunctioncalledanytimeyouupdatethevalueget()-calledwhenyouaccessthevalueoftheproperty

Furtherthere'sadistinctionbetweendatadescriptors(youdefinethepropertiesenumerable,configurable,value,andwritable)andaccessordescriptors(youdefineenumerable,configurable,set(),andget()).Ifyoudefineset()orget(),thedescriptorisconsideredanaccessorandattemptingtodefinevalueorwritablewillraiseanerror.

DefiningaregularoldschoolES3-styleproperty:

varperson={};person.legs=2;

SameusinganES5datadescriptor:

varperson={};Object.defineProperty(person,"legs",{value:2,writable:true,configurable:true,enumerable:true

});

Thevalueofvalueifsettoundefinedbydefault,allothersarefalse.Soyouneedtosetthemtotrueexplicitlyifyouwanttobeabletochangethispropertylater.

OrthesamepropertyusinganES5accessordescriptor:

varperson={};Object.defineProperty(person,"legs",{set:function(v){this.value=v;},get:function(v){returnthis.value;},

Page 518: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

configurable:true,enumerable:true});person.legs=2;

Asyoucanseepropertydescriptorsarealotmorecode,soyouonlyusethemifyoureallywanttopreventsomeonefrommanglingyourproperty,andalsoyouforgetaboutbackwardscompatibilitywithES3browsersbecause,unlikeadditionstoArray.prototypeforexample,youcannot"shim"thisfeatureinoldbrowsers.

Andthepowerofthedescriptorsinaction(defininganonmalleableproperty):

>varperson={};>Object.defineProperty(person,'heads',{value:1});>person.heads=0;0>person.heads;1>deleteperson.heads;false>person.heads;

1

ThefollowingisalistofallES5additionstoObject:

Property/method Description

Object.getPrototypeOf(obj)

WhileinES3youhavetoguesswhatistheprototypeofagivenobjectisusingthemethodObject.prototype.isPrototypeOf(),inES5 youcandirectlyask"Whoisyourprototype?"

>Object.getPrototypeOf([])===Array.prototype;true

Object.create(obj,descr)

DiscussedinChapter7,Inheritance.Createsanewobject,setsitsprototypeanddefinespropertiesofthatobjectusingpropertydescriptors(discussedearlier):

>varparent={hi:'Hello'};>varo=Object.create(parent,{prop:{value:1}});>o.hi;"Hello"

Itevenletsyoucreateacompletelyblankobject,somethingyoucannotdoinES3:

> var o = Object.create(null);>typeofo.toString;"undefined"

Allowsyoutoinspecthowapropertywasdefined.Youcanevenpeekintothebuilt-ins and see all these previously hidden attributes:

>Object.getOwnProperty

Page 519: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object.getOwnPropertyDescriptor(obj,property)

Descriptor(Object.prototype,'toString');Objectconfigurable:trueenumerable:falsevalue:functiontoString(){[nativecode]}writable:true

Object.getOwnPropertyNames(obj)

Returnsanarrayofallownpropertynames(asstrings),enumerableornot.UseObject.keys()togetonlyenumerableones:

>Object.getOwnPropertyNames(Object.prototype);["constructor","toString","toLocaleString","valueOf",...

Object.defineProperty(obj,descriptor)

Definesapropertyofanobjectusingapropertydescriptor.Seethediscussionprecedingthistable.

Object.defineProperties(obj,descriptors)

SameasdefineProperty(),butletsyoudefinemultiplepropertiesatonce:

>varglass=Object.defineProperties({},{"color":{value:"transparent",writable:true

},"fullness":{value:"half",writable:false}});>glass.fullness;"half"

Object.preventExtensions(obj)

Object.isExtensible(obj)

preventExtensions()disallowsaddingfurtherpropertiestoanobjectandisExtensible()checkswhetheryoucanaddproperties:

>vardeadline={};>Object.isExtensible(deadline);true>deadline.date="yesterday";"yesterday">Object.preventExtensions(deadline);>Object.isExtensible(deadline);false>deadline.date="today";

"today">deadline.date;"today"

Attemptingtoaddpropertiestoanon-extensibleobjectisnotanerror,butsimplydoesn'twork:

>deadline.report=true;>deadline.report;undefined

Page 520: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object.seal(obj)

Object.isSealed(obj)

seal()doesthesameaspreventExtensions()andadditionallymakesallexistingpropertiesnon-configurable.

Thismeansyoucanchangethevalueofanexistingproperty,butyoucannotdeleteitorreconfigureit(usingdefineProperty()won'twork).Soyoucannot,forexample,makeanenumerablepropertynon-enumerable.

Object.freeze(obj)

Object.isFrozen(obj)

Everythingthatseal()doespluspreventschangingthevaluesofproperties:

>vardeadline=Object.freeze({date:"yesterday"});>deadline.date="tomorrow";>deadline.excuse="lame";

> deadline.date;"yesterday">deadline.excuse;undefined>Object.isSealed(deadline);true

Object.keys(obj)

Analternativetoafor...inloop.Returnsonlyownproperties(unlikefor...in).Thepropertiesneedtobeenumerableinordertoshowup(unlikeObject.getOwnPropertyNames()).Thereturnvalueisanarrayofstrings.

>Object.prototype.customProto=101;>Object.getOwnPropertyNames(

Object.prototype);

["constructor","toString",...,"customProto"]

>Object.keys(Object.prototype);

["customProto"]>varo={own:202};>o.customProto;101>Object.keys(o);"own"]

Page 521: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6 addition to objectsES6 has a few interesting object definition and property syntax. This new syntax is to makeworkingwithobjectseasierandconcise.

Page 522: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Propertyshorthand

ES6providesashortersyntaxforcommonobjectdefinition.

ES5:obj={x:x,y:y};

ES6:obj={x,y};

Page 523: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Computedpropertynames

Itispossibletocompute propertynamesinthenewES6objectdefinitionsyntax:

let obj = {foo:"bar",["baz"+q()]:42}

Herethepropertynameiscomputedwhere"baz"isconcatenatedwiththeresultofthefunctioncall.

Page 524: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Object.assign

TheObject.assign()methodisusedtocopythevaluesofallenumerableownpropertiesfromoneormoresourceobjectstoatargetobject:

var dest = { quux: 0 }varsrc1={foo:1,bar:2}varsrc2={foo:3,baz:4}Object.assign(dst,src1,src2)

Page 525: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ArrayThe Array constructor creates array objects:

>vara=newArray(1,2,3);

Thisisthesameasthearrayliteral:

>vara=[1,2,3];//recommended

WhenyoupassonlyonenumericvaluetotheArrayconstructor,it'sassumedtobethearraylength:

>varun=newArray(3);>un.length;3

Yougetanarraywiththedesiredlengthandifyouaskforthevalueofeachofthearrayelements,you get undefined:

>un;[undefined,undefined,undefined]

Thereisasubtledifferencebetweenanarrayfullofelementsandarraywithnoelements,butjustlength:

>'0'ina;true>'0'inun;false

ThisdifferenceintheArray()constructor'sbehaviorwhenyouspecifyoneversusmoreparameterscanleadtounexpectedbehavior.Forexample,thefollowinguseofthearrayliteralisvalid:

>vara=[3.14];>a;[3.14]

However, passing the floating-point number to the Array constructor is an error:

>vara=newArray(3.14);RangeError:invalidarraylength

Page 526: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheArray.prototypemembers

ThefollowingarethelistofalltheelementsofanArray:

Property/method Description

length

Thenumberofelementsinthearray:

>[1,2,3,4].length;4

concat(i1,i2,i3,...)

Mergesarraystogether:

>[1,2].concat([3,5],[7,11]);[1,2,3,5,7,11]

join(separator)

Turnsanarrayintoastring.Theseparatorparameterisastringwithcommaasthedefaultvalue:

>[1,2,3].join();"1,2,3">[1,2,3].join('|');"1|2|3">[1,2,3].join('islessthan');"1islessthan2islessthan3"

pop()

Removesthelastelementofthearrayand returnsit:

>vara=['une','deux','trois'];>a.pop();"trois">a; ["une","deux"]

push(i1,i2,i3,...)

Appendselementstotheendofthearrayandreturnsthelengthofthemodifiedarray:

>vara=[];>a.push('zig','zag','zebra','zoo');4

reverse()

Reversestheelementsofthearrayandreturnsthemodifiedarray:

>vara=[1,2,3];>a.reverse();[3,2,1]>a; [3,2,1]

shift()

Likepop()butremovesthefirstelement,notthelast:

>vara=[1,2,3];>a.shift();1>a; [2,3]

Page 527: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

slice(start_index,end_index)

Extractsapieceofthearrayandreturnsit asanewarray,withoutmodifyingthesourcearray:

>vara=['apple','banana','js','css','orange'];>a.slice(2,4);["js","css"]>a; ["apple","banana","js","css","orange"]

sort(callback)

Sortsanarray.Optionallyacceptsacallbackfunctionforcustomsorting.Thecallbackfunctionreceivestwoarrayelementsasargumentsandshouldreturn0iftheyareequal,apositivenumberifthefirstisgreater,andanegativenumberifthesecondisgreater.

Anexampleofacustomsortingfunctionthatdoesapropernumericsort(sincethedefaultischaractersorting):

functioncustomSort(a,b){ if(a>b)return1; if(a<b)return-1; return0;}Exampleuseofsort():>vara=[101,99,1,5];>a.sort();[1, 101,5,99]>a.sort(customSort);[1,5,99,101]>[7,6,5,9].sort(customSort);[5,6,7,9]

splice(start,delete_count,i1,i2,i3,...)

Removesandaddselementsatthesametime.Thefirstparameteriswheretostartremoving,thesecondishowmanyitemstoremoveandtherestoftheparametersarenewelementstobeinsertedintheplaceoftheremovedones:

>vara=['apple','banana','js','css','orange'];>a.splice(2,2,'pear','pineapple');["js","css"]>a; ["apple","banana","pear","pineapple","orange"]

unshift(i1,i2,i3,...)

Likepush()butaddstheelementsatthebeginningofthearrayasopposedtotheend.Returnsthelengthofthemodifiedarray:

>vara=[1,2,3];>a.unshift('one','two');5>a; ["one","two",1,2,3]

Page 528: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript5additionstoArray

FollowingaretheECMAScript5additionstoArray:

Property/method Description

Array.isArray(obj)

Tellsifanobjectisanarraybecausetypeofisnotgoodenough:

>vararraylike={0:101,length:1};>typeofarraylike;"object">typeof[];"object"

Neitherisduck-typing(ifitwalkslikeaduckandquackslikeaduck,itmustbeaduck):

typeofarraylike.length;"number"

InES3youneedtheverbose:

>Object.prototype.toString.call([])==="[objectArray]";true>Object.prototype.toString.call(arraylike)==="[objectArray]";false

InES5yougettheshorter:

Array.isArray([]);trueArray.isArray(arraylike);false

Array.prototype.indexOf(needle,idx)

Searchesthearrayandreturnstheindexofthefirstmatch.Returns-1ifthere'snomatch.Optionallycansearchstartingfromaspecifiedindex:

>varar=['one','two','one','two'];>ar.indexOf('two');1>ar.indexOf('two',2);3>ar.indexOf('toot');-1

Array.prototype.lastIndexOf(needle,idx)

LikeindexOf()onlysearchesfromtheend:

>varar=['one','two','one','two'];>ar.lastIndexOf('two');3>ar.lastIndexOf('two',2);1>ar.indexOf('toot');-1

Page 529: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array.prototype.forEach(callback,this_obj)

Analternativetoaforloop.Youspecifyacallbackfunctionthatwillbecalledforeachelementofthe array.Thecallbackfunctiongetsthearguments:theelement,itsindexandthewholearray:

>varlog=console.log.bind(console);>varar=['itsy','bitsy','spider'];>ar.forEach(log);itsy0["itsy","bitsy","spider"]bitsy1["itsy","bitsy","spider"]spider2["itsy","bitsy","spider"]

Optionally,youcanspecifyasecondparameter:theobjecttobeboundtothisinsidethecallbackfunction.Sothisworkstoo:

>ar.forEach(console.log,console);

Array.prototype.every(callback,this_obj)

Youprovideacallbackfunctionthattestseachelementofthearray.YourcallbackisgiventhesameargumentsasforEach()anditmustreturntrueorfalsedependingonwhetherthegivenelementsatisfiesyourtest.

Ifallelementssatisfyyourtest,every()returnstrue.Ifatleastonedoesn't,every()returnsfalse:

> function hasEye(el, idx,ar){returnel.indexOf('i')!==-1;}>['itsy','bitsy','spider'].every(hasEye);true>['eency','weency','spider'].every(hasEye);false

Ifatsomepointduringtheloopitbecomesclearthattheresultwillbefalse,theloopstopsandreturnsfalse:

>[1,2,3].every(function(e){console.log(e);returnfalse;});1false

Array.prototype.some(callback,this_obj)

Likeevery(),onlyitreturnstrueifatleastoneelementsatisfiesyourtest:

>['itsy','bitsy','spider'].some(hasEye);true>['eency','weency','spider'].some(hasEye);true

Page 530: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array.prototype.filter(callback,this_obj)

Similartosome()andevery()butitreturnsanewarrayofallelementsthatsatisfyyourtest:

>['itsy','bitsy','spider'].filter(hasEye);["itsy","bitsy","spider"]>['eency','weency','spider'].filter(hasEye);["spider"]

Array.prototype.map(callback,this_obj)

SimilartoforEach()becauseitexecutesacallbackforeachelement,butadditionallyitconstructsanewarraywiththereturnedvaluesofyourcallbackandreturnsit.Let'scapitalizeallstringsinanarray:

>functionuc(element,index,array){returnelement.toUpperCase();}>['eency','weency','spider'].map(uc);["EENCY","WEENCY","SPIDER"]

Array.prototype.reduce(callback,start)

Executesyourcallbackforeachelementofthearray.Yourcallbackreturnsavalue.Thisvalueispassedbacktoyourcallbackwiththenextiteration.Thewholearrayiseventuallyreducedtoasinglevalue:

>functionsum(res,element,idx,arr){returnres+element;}>[1,2,3].reduce(sum);6

Optionallyyoucanpassastartvaluewhichwillbeusedbythefirstcallbackcall:

>[1,2,3].reduce(sum,100);106

Array.prototype.reduceRight(callback,start)

Likereduce()butloopsfromtheendofthearray:

>functionconcat(result_so_far,el){

return "" + result_so_far+el;}>[1,2,3].reduce(concat);"123">[1,2,3].reduceRight(concat);"321"

Page 531: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ES6additiontoarrays

Followingaretheadditiontoarrays:

Array.from(arrayLike, mapFunc?,thisArg?)

TheArray.from()method'sbasicfunctionalityistoconverttwokindsofvaluestoarrays-arrayLikevaluesandIterablevalues:

constarrayLike={length:2,0:'a',1:'b'};constarr =Array.from(arrayLike);for(constxofarr){//OK,iterableconsole.log(x);}//Output://a//b

Array.of(...items)

Createsanarrayoutoftheitemspassedtothemethod

leta=Array.of(1,2,3,'foo');console.log(a);//[1,2,3,"foo"]

Array.prototype.entries()

Array.prototype.keys()

Array.prototype.values()

The result of these methods is a sequence of values. These methods returns aniteratorofkeys,valuesandentriesrespectively.

leta=Array.of(1,2,3,'foo');letk,v,e;for(kof a.keys()){

console.log(k); //0 1 2 3}for(vof a.values()){console.log(v);//123foo}for(eof a.entries()){console.log(e);}//[[0,1],[1,2],[2,3][3,'foo']]

Array.prototype.find(predicate,thisArg?)

Returnsthefirstarrayelementforwhichthecallbackfunctionreturnstrue.Ifthereisnosuchelement,itreturnsundefined:

[1,-2,3].find(x=>x<0)//-2

Array.prototype.findIndex(predicate,thisArg?)

Returnstheindexofthefirstelementforwhichthecallbackfunctionreturnstrue.Ifthereisnosuchelement,itreturns-1:

[1, -2, 3].find(x => x < 0)//1

Itfillsanarraywiththegivenvalue:

Page 532: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Array.prototype.fill(value:any,start=0,end=this.length):This

constarr=['a','b','c'];arr.fill(7)[7,7,7]Youcanspecifystartandendranges.['a','b','c'].fill(7,1,2)['a',7,'c' ]

Page 533: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

FunctionJavaScript functions are objects. They can be defined using the Function constructor, like so:

varsum=newFunction('a','b','returna+b;');

Thisisa(generallynotrecommended)alternativetothefunctionliteral(alsoknownasfunctionexpression):

varsum=function(a,b){returna+b;};

Or,themorecommonfunctiondefinition:

functionsum(a,b){returna+b;}

Page 534: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheFunction.prototypemembers

FollowingarethelistofmembersoftheFunctionconstructor:

Property/Method Description

apply(this_obj,params_array)

Allowsyoutocallanotherfunctionwhileoverwritingtheotherfunction'sthisvalue.Thefirstparameterthatapply()acceptsistheobjecttobeboundtothisinsidethefunctionandthesecondisanarrayofargumentstobesenttothefunctionbeingcalled:

functionwhatIsIt(){returnthis.toString();}>varmyObj={};>whatIsIt.apply(myObj);"[objectObject]">whatIsIt.apply(window);

"[object Window]"

call(this_obj,p1,p2,p3,...) Sameasapply()butacceptsargumentsonebyone,asopposedtoasonearray.

length

Thenumberofparametersthefunctionexpects:

>parseInt.length;2

Ifyouforgetthedifferencebetweencall()andapply():

>Function.prototype.call.length;1>Function.prototype.apply.length;2

Thecall() property'slengthis1becauseallargumentsexceptthefirstoneareoptional.

Page 535: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript5additionstoaFunction

FollowingaretheECMAScript5additiontoaFunctionconstructor:

Property/method Description

Function.prototype.bind()

Whenyouwanttocallafunctionthatusesthisinternallyandyouwanttodefinewhatthisis.Themethodscall()andapply()invokethefunctionwhilebind()returnsanewfunction.Usefulwhenyouprovideamethodasacallbacktoamethodofanotherobjectandandyouwantthistobeanobjectofyourchoice:

>whatIsIt.apply(window); "[objectWindow]"

Page 536: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript6additionstoaFunction

FollowingaretheECMAScript6additiontoaFunctionconstructor:

ArrowFunctions

Anarrowfunctionexpressionhasashortersyntaxcomparedtofunctionexpressionsanddoesnot binditsownthis,arguments,super,ornew.target.Arrowfunctionsarealwaysanonymous.

()=>{...}//noparameterx=>{...}//oneparameter,anidentifier(x,y)=>{...}//severalparametersconstsquares=[1,2,3].map(x=>x*x);

StatementBodiesaremoreexpressiveandconciseclosuresyntax

arr.forEach(v=>{if(v%5===0)filtered:ist.push(v)})

Page 537: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

BooleanThe Boolean constructor creates Boolean objects (not to be confused with Boolean primitives).The Boolean objects are not that useful and are listed here for the sake of completeness.

>varb=newBoolean();>b.valueOf();false>b.toString();"false"

ABooleanobjectisnotthesameasaBooleanprimitivevalue.Asyouknow,allobjectsaretruthy:

>b===false;false>typeofb;"object"

Booleanobjectsdon'thaveanypropertiesotherthantheonesinheritedfromObject.

Page 538: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

NumberThis creates number objects:

>varn=newNumber(101);>typeofn;"object">n.valueOf();101

TheNumberobjectsarenotprimitiveobjects,butifyouuseanyNumber.prototypemethodonaprimitivenumber,theprimitivewillbeconvertedtoaNumberobjectbehindthescenesandthecodewillwork.

>varn=123;>typeofn;"number">n.toString();"123"

Usedwithoutnew,theNumberconstructorreturnsaprimitivenumber.

>Number("101");101>typeofNumber("101");"number">typeofnewNumber("101");"object"

Page 539: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheNumberconstructor

ConsiderthefollowingmembersoftheNumberconstructor:

Property/method Description

Number.MAX_VALUE

Aconstantproperty(cannotbechanged)thatcontainsthemaximumallowednumber:

>Number.MAX_VALUE; 1.7976931348623157e+308

Number.MIN_VALUE

ThesmallestnumberyoucanworkwithinJavaScript:

>Number.MIN_VALUE; 5e-324

Number.NaN

ContainstheNotANumbernumber.SameastheglobalNaN:

>Number.NaN; NaN

NaNisnotequaltoanythingincludingitself:

>Number.NaN===Number.NaN; false

Number.POSITIVE_INFINITY SameastheglobalInfinitynumber.

Number.NEGATIVE_INFINITY Sameas-Infinity.

Page 540: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheNumber.prototypemembers

FollowingarethemembersoftheNumberconstructor:

Property/method Description

toFixed(fractionDigits)

Returnsastringwiththefixed-pointrepresentationofthenumber.Roundsthereturnedvalue:

>varn=newNumber(Math.PI);>n.valueOf();3.141592653589793>n.toFixed(3);"3.142"

toExponential(fractionDigits)

Returnsastringwithexponentialnotationrepresentationofthenumberobject.Roundsthereturnedvalue:

>varn=newNumber(56789);>n.toExponential(2);"5.68e+4"

toPrecision(precision)

Stringrepresentationofanumberobject,eitherexponentialorfixed-point,dependingonthenumberobject:

>varn=newNumber(56789);>n.toPrecision(2);"5.7e+4">n.toPrecision(5);"56789">n.toPrecision(4);"5.679e+4">varn=newNumber(Math.PI);>n.toPrecision(4);"3.142"

Page 541: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

StringThe String() constructor creates string objects. Primitive strings are turned into objects behindthe scenes if you call a method on them as if they were objects. Omitting new gives you primitivestrings.

Creatingastringobjectandastringprimitive:

>vars_obj=newString('potatoes');>vars_prim='potatoes';>typeofs_obj;"object">typeofs_prim;"string"

Theobjectandtheprimitivearenotequalwhencomparedbytypewith===,buttheyarewhencomparedwith==whichdoestypecoercion:

>s_obj===s_prim;false>s_obj==s_prim;true

lengthisapropertyofthestringobjects:

>s_obj.length;8

Ifyouaccesslengthonaprimitivestring,theprimitiveisconvertedtoanobjectbehindthescenesandtheoperation issuccessful:

>s_prim.length;8

Stringliteralsworkfinetoo:

>"giraffe".length;7

Page 542: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheStringconstructor

FollowingarethemembersoftheStringconstructor:

Property/method Description

String.fromCharCode(code1,code2,code3,...)

ReturnsastringcreatedusingtheUnicodevaluesoftheinput:

>String.fromCharCode(115,99,114,105,112,116);"script"

Page 543: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheString.prototypemembers

ConsiderthefollowingString.prototypemembers:

Property/method Description

length

Thenumberofcharactersinthestring:

> newString('four').length;4

charAt(position)

Returnsthecharacteratthespecifiedposition.Positionsstartat0:

> "script".charAt(0);"s"

SinceES5,it'salsopossibletousearraynotationforthesamepurpose.(Thisfeaturehasbeenlongsupported in many browsers before ES5, but not IE):

> "script"[0];"s"

charCodeAt(position)

Returnsthenumericcode(Unicode)ofthecharacteratthespecifiedposition:

> "script".charCodeAt(0);115

concat(str1,str2,....)

Returnsanewstringgluedfromtheinputpieces:

> "".concat('zig','-','zag');"zig-zag"

indexOf(needle,start)

Iftheneedlematchesapartofthestring,thepositionofthematchisreturned.Theoptionalsecondparameterdefineswherethesearchshouldstartfrom.Returns-1ifnomatchisfound:

> "javascript".indexOf('scr');4 > "javascript".indexOf('scr',5);-1

lastIndexOf(needle,start)

Same as indexOf() but starts the search from the end of the string. The last occurrence of a:

> "javascript".lastIndexOf('a');3

localeCompare(needle)

Comparestwostringsinthecurrentlocale.Returns0ifthetwostringsareequal,1iftheneedlegetssortedbeforethestringobject,-1otherwise:

> "script".localeCompare('crypt');1 > "script".localeCompare('sscript');-1> "script".localeCompare('script');0

Page 544: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

match(regexp)

Acceptsaregularexpressionobjectandreturnsanarrayofmatches:

> "R2-D2andC-3PO".match(/[0-9]/g);["2","2","3"]

replace(needle,replacement)

Allowsyoutoreplacethematchingresultsofaregexppattern.Thereplacementcanalsobeacallbackfunction.Capturinggroupsareavailableas$1,$2,...$9:

> "R2-D2".replace(/2/g,'-two');"R-two-D-two"> "R2-D2".replace(/(2)/g,'$1$1');"R22-D22"

search(regexp)

Returns the position of the first regular expression match:

> "C-3PO".search(/[0-9]/);2

slice(start,end)

Returnsthepartofastringidentifiedbythestartandendpositions.Ifstartisnegative,thestartpositionislength+start,similarlyiftheendparameterisnegative,theendpositionislength+end:

> "R2-D2andC-3PO".slice(4,13);"2andC-3"> "R2-D2andC-3PO".slice(4,-1);"2andC-3P"

split(separator,limit)

Turnsastringintoanarray.Thesecondparameter,limit,isoptional.Aswithreplace(),search(),andmatch(),theseparatorisaregularexpressionbutcanalsobeastring:

> "1,2,3,4".split(/,/);["1","2","3","4"]> "1,2,3,4".split(',',2);["1","2"]

substring(start,end)

Similartoslice().Whenstartorendarenegativeorinvalid,theyareconsidered0.Iftheyaregreaterthanthestringlength,theyareconsideredtobethelength.Ifendisgreaterthanstart,theirvaluesareswapped.

> "R2-D2andC-3PO".substring(4,13);"2 and C-3"

> "R2-D2andC-3PO".substring(13,4);"2andC-3"

toLowerCase()

toLocaleLowerCase()

Transformsthestringtolowercase:

> "Java".toLowerCase();"java"

toUpperCase()

toLocaleUpperCase()

Transformsthestringtouppercase:

> "Script".toUpperCase();"SCRIPT"

Page 545: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript5additionstoString

FollowingaretheECMAScript5additionstoString:

Property/method Description

String.prototype.trim()

Insteadofusingaregularexpressiontoremovewhitespacebeforeandafterastring(asinES3),youhaveatrim()methodinES5.

>"\tbeard\n".trim(); "beard" OrinES3:

> " \t beard \n".replace(/\s/g, ""); "beard"

Page 546: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript6additionstoString

FollowingarethelistofalltheECMAScript6additionstoString:

TemplateLiteralsareusedtointerpolatesingleormulti-linestrings.

Templateliteralsareenclosedbytheback-tick(``)(graveaccent)characterinsteadofdoubleorsinglequotes.Templateliteralscancontainplaceholders.TheseareindicatedbytheDollarsignandcurlybraces(${expression}).Theexpressionsintheplaceholdersandthetextbetweenthemgetpassedtoafunction.Thedefaultfunctionjustconcatenatesthepartsintoasinglestring.

vara=5;varb=10;console.log(`Fifteenis${a+b}`);

String.prototype.repeat-thismethodallowsyoutorepeatastringnnumberoftimes"".repeat(4*depth)"foo".repeat(3)

String.prototype.startsWith

String.prototype.endsWith

String.prototype.includes

Thesearenewstringsearchingmethods

"hello".startsWith("ello",1)//true"hello".endsWith("hell",4)//true"hello".includes("ell")//true"hello".includes("ell",1)//true"hello".includes("ell",2)//false

Page 547: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

DateThe Date constructor can be used with several types of input:

Youcanpassvaluesforyear,month,dateof themonth,hour,minute,second,andmillisecond,likeso:

>newDate(2015,0,1,13,30,35,505);ThuJan01201513:30:35GMT-0800(PST)

Youcanskipanyoftheinputparameters,inwhichcasetheyareassumedtobe0.Notethatmonthvaluesarefrom0(January)to11(December),hoursarefrom0to23,minutesandseconds0to59,andmilliseconds0to999.Youcanpassatimestamp:

>newDate(1420147835505);ThuJan01201513:30:35GMT-0800(PST)

Ifyoudon'tpassanything,thecurrentdate/timeisassumed:

>newDate();FriJan11201312:20:45GMT-0800(PST)

Ifyoupassastring, it'sparsedinanattempttoextractapossibledatevalue:

>newDate('May4,2015');MonMay04201500:00:00GMT-0700(PDT)

Omittingnewgivesyouastringversionofthecurrentdate:

>Date()===newDate().toString();true

Page 548: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheDateconstructor

FollowingarethemembersoftheDateconstructor:

Property/method Description

Date.parse(string)

SimilartopassingastringtonewDate()constructor,thismethodparsestheinputstringinattempttoextractavaliddatevalue.Returnsatimestamponsuccess,NaNonfailure:

>Date.parse('May5, 2015');1430809200000>Date.parse('4th');

NaN

Date.UTC(year,month,date,hours,minutes,seconds,ms)

ReturnsatimestampbutinUTC(CoordinatedUniversalTime),notinlocaltime.

>Date.UTC(2015,0,1,13,30, 35,505);1420119035505

Page 549: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheDate.prototypemembers

FollowingarethelistofDate.prototypemembers:

Property/method Description/example

toUTCString()

SameastoString()butinuniversaltime.Here'showPacificStandard(PST)localtimediffersfromUTC:

>vard=newDate(2015,0,1);>d.toString();"ThuJan01201500:00:00GMT-0800(PST)">d.toUTCString();"Thu,01Jan201508:00:00GMT"

toDateString()

ReturnsonlythedateportionoftoString():

>newDate(2015,0,1).toDateString();"ThuJan012010"

toTimeString()

ReturnsonlythetimeportionoftoString():

>newDate(2015,0,1).toTimeString();"00:00:00GMT-0800(PST)"

toLocaleString()

toLocaleDateString()

toLocaleTimeString()

EquivalenttotoString(),toDateString(),andtoTimeString()respectively,butinafriendlierformat, according to the current user's locale:

>newDate(2015,0,1).toString();"ThuJan01201500:00:00GMT-0800(PST)">newDate(2015,0,1).toLocaleString();"1/1/201512:00:00AM"

getTime()

setTime(time)

Getorsetthetime(usingatimestamp)ofadateobject.Thefollowingexamplecreatesadateandmovesitonedayforward:

>vard=newDate(2015,0,1);>d.getTime();1420099200000>d.setTime(d.getTime()+ 1000*60*60*24);1420185600000

> d.toLocaleString();"FriJan02201500:00:00 GMT-0800(PST)"

getFullYear()

getUTCFullYear()

setFullYear(year,month,date)

setUTCFullYear(year,month,date)

GetorsetafullyearusinglocalorUTCtime.ThereisalsogetYear()butitisnotY2Kcompliant,souse getFullYear() instead:

>vard=newDate(2015,0,1);>d.getYear();115>d.getFullYear();2015>d.setFullYear(2020);1577865600000>d;

Page 550: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

WedJan01202000:00:00GMT-0800 (PST)

getMonth()

getUTCMonth()

setMonth(month,date)

setUTCMonth(month,date)

Getorsetmonth,startingfrom0(January):

>vard=newDate(2015,0,1);>d.getMonth();0>d.setMonth(11);1448956800000>d.toLocaleDateString();"12/1/2015"

getDate()

getUTCDate()

setDate(date)

setUTCDate(date)

Getorsetdateofthemonth.

>vard=newDate(2015,0,1);>d.toLocaleDateString();"1/1/2015">d.getDate();1>d.setDate(31);1422691200000>d.toLocaleDateString();"1/31/2015"

getHours()

getUTCHours()

setHours(hour,min,sec,ms)

setUTCHours(hour,min,sec,ms)

getMinutes()

getUTCMinutes()

setMinutes(min,sec,ms)

setUTCMinutes(min,sec,ms)

getSeconds()

getUTCSeconds()

setSeconds(sec,ms)

setUTCSeconds(sec,ms)

getMilliseconds()

getUTCMilliseconds()

setMilliseconds(ms)

setUTCMilliseconds(ms)

Get/Sethour,minutes,seconds,milliseconds,allstartingfrom0:

>vard=newDate(2015,0,1);> d.getHours() + ':' + d.getMinutes();

"0:0">d.setMinutes(59);1420102740000>d.getHours()+':'+d.getMinutes();"0:59"

Returnsthedifferencebetweenlocalanduniversal(UTC)time,measuredinminutes.ForexamplethedifferencebetweenPST(PacificStandardTime)andUTC:

>newDate().getTimezoneOffset();

Page 551: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

getTimezoneOffset() 480>420/60;//hours8

getDay()

getUTCDay()

Returns the day of the week, starting from 0 (Sunday):

>vard=newDate(2015,0,1);>d.toDateString();"ThuJan012015">d.getDay();4>vard=newDate(2015,0,4);>d.toDateString();"SatJan042015">d.getDay();0

Page 552: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ECMAScript5additionstoDate

FollowingaretheadditionstotheDateconstructor:

Property/method Description

Date.now()

Aconvenientwaytogetthecurrenttimestamp:

>Date.now()===newDate().getTime();true

Date.prototype.toISOString()

YetanothertoString():

>vard=newDate(2015,0,1);>d.toString();"ThuJan01201500:00:00GMT-0800(PST)">d.toUTCString();"Thu,01Jan201508:00:00GMT">d.toISOString();"2015-01-01T00:00:00.000Z"

Date.prototype.toJSON()

UsedbyJSON.stringify()(refertotheendofthisappendix)andreturnsthesameastoISOString():

>vard=newDate();>d.toJSON()===d.toISOString();true

Page 553: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MathMath is a different from the other built-in objects because it cannot be used as a constructor tocreate objects. It's just a collection of static functions and constants. Some examples to illustratethedifferenceareasfollows:

>typeofDate.prototype;"object">typeofMath.prototype;"undefined">typeofString;"function">typeofMath;"object"

Page 554: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheMathobject

FollowingarethemembersoftheMathobject:

Property/method Description

Math.E

Math.LN10

Math.LN2

Math.LOG2E

Math.LOG10E

Math.PI

Math.SQRT1_2

Math.SQRT2

Thesearesomeusefulmathconstants,allread-only.Herearetheirvalues:

>Math.E;2.718281828459045>Math.LN10;2.302585092994046>Math.LN2;0.6931471805599453

> Math.LOG2E;1.4426950408889634>Math.LOG10E;0.4342944819032518>Math.PI;3.141592653589793>Math.SQRT1_2;0.7071067811865476>Math.SQRT2;1.4142135623730951

Math.acos(x)

Math.asin(x)

Math.atan(x)

Math.atan2(y,x)

Math.cos(x)

Math.sin(x)

Math.tan(x)

Trigonometricfunctions

Math.round(x)

Math.floor(x)

Math.ceil(x)

round()givesyouthenearestinteger,ceil()roundsup,andfloor()roundsdown:

>Math.round(5.5);6>Math.floor(5.5);5>Math.ceil(5.1);

6

Math.max(num1,num2,num3,...)

Math.min(num1,num2,num3,...)

max()returnsthelargestandmin()returnsthesmallestofthenumberspassedtothemasarguments.IfatleastoneoftheinputparametersisNaN,theresultisalsoNaN:

>Math.max(4.5,101,Math.PI);101>Math.min(4.5,101,Math.PI);3.141592653589793

Absolutevalue:

>Math.abs(-101);

Page 555: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Math.abs(x) 101>Math.abs(101);101

Math.exp(x)

Exponentialfunction:Math.Etothepowerofx:

>Math.exp(1)===Math.E;true

Math.log(x)

Naturallogarithmofx:

>Math.log(10)===Math.LN10;true

Math.sqrt(x)

Squarerootofx:

>Math.sqrt(9);3>Math.sqrt(2)===Math.SQRT2;true

Math.pow(x,y)

xtothepowerofy:

>Math.pow(3,2);9

Math.random()

Randomnumberbetween0and1(including0).

>Math.random();0.8279076443185321

For an random integer in a range,saybetween10and100:>Math.round(Math.random()*90+10);79

Page 556: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

RegExpYou can create a regular expression object using the RegExp() constructor. You pass theexpression pattern as the first parameter and the pattern modifiers as the second:

>varre=newRegExp('[dn]o+dle','gmi');

Thismatches"noodle","doodle","doooodle",andsoon.It'sequivalenttousingtheregularexpressionliteral:

>varre=('/[dn]o+dle/gmi');//recommended

Chapter4,ObjectsandAppendixD,RegularExpressionscontainmoreinformationonregularexpressionsandpatterns.

Page 557: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheRegExp.prototypemembers

FollowingaretheRegExp.prototypemembers:

Property/method Description

global Read-onlytrueifthegmodifierwassetwhencreatingtheregexpobject.

ignoreCase Read-only.trueiftheimodifierwassetwhencreatingtheregexpobject.

multiline Read-only.trueifthemmodifierwassetwhencreatingtheregexpobject

lastIndex

Containsthepositioninthestringwherethenextmatchshouldstart.test()andexec()setthispositionafterasuccessful match.Onlyrelevantwhentheg(global)modifierwasused:

>varre=/[dn]o+dle/g;>re.lastIndex;0>re.exec("noodledoodle");["noodle"]>re.lastIndex;6>re.exec("noodledoodle");["doodle"]>re.lastIndex;13>re.exec("noodledoodle");null>re.lastIndex;0

source

Read-only.Returnstheregularexpressionpattern(withoutthemodifiers):

>varre=/[nd]o+dle/gmi;>re.source;"[nd]o+dle"

exec(string)

Matchestheinputstringwiththeregularexpression.Onasuccessfulmatchreturnsanarraycontainingthematchandanycapturinggroups.Withthegmodifier,itmatchesthefirstoccurrenceandsetsthelastIndexproperty. Returns null when there's no match:

>varre=/([dn])(o+)dle/g;>re.exec("noodledoodle");["noodle","n","oo"]>re.exec("noodledoodle");["doodle","d","oo"]

Thearraysreturnedbyexec()havetwoadditionalproperties:index(ofthematch)andinput(theinputstringbeingsearched).

test(string)

Sameasexec()butonlyreturnstrueorfalse:

>/noo/.test('Noodle');false>/noo/i.test('Noodle');true

Page 558: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare
Page 559: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Error objectsError objects are created either by the environment (the browser) or by your code:

>vare=newError('jaavcsritpis_not_howyouspellit');>typeofe;"object"

OtherthantheErrorconstructor,sixadditionalonesexistandtheyallinheritError:

EvalErrorRangeErrorReferenceErrorSyntaxErrorTypeErrorURIError

Page 560: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

TheError.prototypemembers

FollowingaretheError.prototypemembers:

Property Description

name

Thenameoftheerrorconstructorusedtocreatetheobject:

>vare=newEvalError('Oops');>e.name;"EvalError"

message

Additionalerrorinformation:

>vare=newError('Oops...again');>e.message;"Oops...again"

Page 561: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

JSONThe JSON object is new to ES5. It's not a constructor (similarly to Math) and has only twomethods: parse() and stringify(). For ES3 browsers that don't support JSON natively, youcan use the "shim" from http://json.org.

JSONstandsforJavaScriptObjectNotation.It'salightweightdatainterchangeformat.It'sasubsetofJavaScriptthatonlysupportsprimitives,objectliterals,andarrayliterals.

Page 562: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

MembersoftheJSONobject

FollowingarethemembersoftheJSONobject:

Method Description

parse(text,callback)

TakesaJSON-encodedstringandreturnsanobject:

>vardata='{"hello":1,"hi":[1,2,3]}';>varo=JSON.parse(data);>o.hello;1>o.hi;[1,2,3]

Theoptionalcallbackletsyouprovideyourownfunctionthatcaninspectandmodifytheresult.Thecallbacktakeskeyandvalueargumentsandcanmodifythevalueordeleteit(byreturningundefined).

>functioncallback(key,value){console.log(key,value);if(key==='hello'){return'bonjour';}if(key==='hi'){

return undefined;}returnvalue;}>varo=JSON.parse(data,callback);hello1011223hi[1,2,3]Object{hello:"bonjour"}>o.hello;"bonjour">'hi'ino;false

stringify(value,callback,white)

Takesanyvalue(mostcommonlyanobjectoranarray)andencodesittoaJSONstring.

>varo={hello:1,hi:2,when:newDate(2015,0,1)};>JSON.stringify(o);"{"hello":1,"hi":2,"when":"2015-01-01T08:00:00.000Z"}"

Thesecondparameterletsyouprovideacallback(orawhitelistarray)tocustomizethereturnvalue.Thewhitelistcontainsthekeysyou'reinterestedin:

JSON.stringify(o,['hello','hi']);"{"hello":1,"hi":2}"

Thelastparameterhelpsyougetahuman-readableversion.Youspecifythenumberofspacesasastringoranumber:

>JSON.stringify(o,null,4);

Page 563: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

"{"hello":1,"hi":2,"when":"2015-01-01T08:00:00.000Z"}"

Page 564: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Appendix D. Regular ExpressionsWhen you use regular expressions (discussed in Chapter 4, Objects), you can match literalstrings,forexample:

>"sometext".match(/me/);["me"]

However,thetruepowerofregularexpressionscomesfrommatchingpatterns,notliteralstrings.Thefollowingtabledescribesthedifferentsyntaxyoucanuseinyourpatterns,andprovidessomeexamplesoftheiruse:

Pattern Description

[abc]

Matchesaclassofcharacters:

>"sometext".match(/[otx]/g);["o","t","x","t"]

[a-z]

Aclassofcharactersdefinedasarange.Forexample,[a-d]isthesameas[abcd],[a-z]matchesalllowercasecharacters,[a-zA-Z0-9_]matchesallcharacters,numbers,andtheunderscorecharacter:

>"SomeText".match(/[a-z]/g);["o","m","e","e","x","t"]>"SomeText".match(/[a-zA-Z]/g);

["S", "o", "m", "e", "T", "e", "x", "t"]

[^abc]

Matcheseverythingthatisnotmatchedbytheclassofcharacters:

>"SomeText".match(/[^a-z]/g);["S","","T"]

a|b

Matchesaorb.ThepipecharactermeansOR,anditcanbeusedmorethanonce:

>"SomeText".match(/t|T/g);["T","t"]>"SomeText".match(/t|T|Some/g);["Some","T","t"]

a(?=b)

Matchesaonlyiffollowedbyb:

>"SomeText".match(/Some(?=Tex)/g);null>"SomeText".match(/Some(?=Tex)/g);["Some"]

a(?!b)

Matchesaonlywhennotfollowedbyb:

>"SomeText".match(/Some(?!Tex)/g);null>"SomeText".match(/Some(?!Tex)/g);["Some"]

Page 565: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

\

Escapecharacterusedtohelpyoumatchthespecialcharactersusedinpatternsasliterals:

>"R2-D2".match(/[2-3]/g);["2","2"] >"R2-D2".match(/[2\-3]/g);["2","-","2"]

\n

\r

\f

\t

\v

Newline

Carriagereturn

Formfeed

Tab

Verticaltab

\s

Whitespace,oranyofthepreviousfiveescapesequences:

>"R2\nD2".match(/\s/g);["\n", " "]

\S

Oppositeoftheabove;matcheseverythingbutwhitespace.Sameas[ \̂s]:

>"R2\nD2".match(/\S/g);["R","2","D","2"]

\w

Anyletter,number,orunderscore.Sameas[A-Za-z0-9_]:

>"S0m3text!".match(/\w/g);["S","0","m","3","t","e","x","t"]

\W

Oppositeof\w:

>"S0m3text!".match(/\W/g);["","!"]

\d

Matchesanumber,sameas[0-9]:

>"R2-D2andC-3PO".match(/\d/g);["2","2","3"]

\D

Oppositeof\d;matchesnon-numbers,sameas[^0-9]or[ \̂d]:

>"R2-D2andC-3PO".match(/\D/g);["R","-","D","","a","n","d","","C", "-","P","O"]

\b

Matchesawordboundarysuchasspaceorpunctuation.

MatchingRorDfollowedby2:

> "R2D2 and C-3PO".match(/[RD]2/g);["R2","D2"]

Sameasabovebutonlyattheendofaword:

Page 566: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>"R2D2and C-3PO".match(/[RD]2\b/g);["D2"]

Samepatternbuttheinputhasadash,whichisalsoanendofaword:

>"R2-D2andC-3PO".match(/[RD]2\b/g);["R2","D2"]

\B

Theoppositeof\b:

>"R2-D2andC-3PO".match(/[RD]2\B/g);null>"R2D2and C-3PO".match(/[RD]2\B/g);["R2"]

[\b] Matchesthebackspacecharacter.

\0 Thenullcharacter.

\u0000

MatchesaUnicodecharacter,representedbyafour-digithexadecimalnumber:

>"стоян".match(/\u0441\u0442\u043E/);["сто"]

\x00

Matchesacharactercoderepresentedbyatwo-digithexadecimalnumber:

>"\x64";"d">"dude".match(/\x64/g);["d","d"]

^

Thebeginningofthestringtobematched.Ifyousetthemmodifier(multi-line),itmatchesthebeginningofeachline:

>"regular\nregular\nexpression".match(/r/g);["r","r","r","r","r"]>"regular\nregular\nexpression".match(/^r/g);["r"]>"regular\nregular\nexpression".match(/^r/mg);["r","r"]

$

Matchestheendoftheinputor,whenusingthemultilinemodifier,theendofeachline:

>"regular\nregular\nexpression".match(/r$/g);null>"regular\nregular\nexpression".match(/r$/mg);["r","r"]

.

Matchesanysinglecharacterexceptforthenewlineandthelinefeed:

>"regular".match(/r./g);["re"]>"regular".match(/r.../g);["regu"]

Page 567: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

*

Matchestheprecedingpatternifitoccurszeroormoretimes.Forexample,/.*/willmatchanythingincludingnothing(anempty input):

>"".match(/.*/);[""]>"anything".match(/.*/);["anything"]>"anything".match(/n.*h/);["nyth"]

Keepinmindthatthepatternis"greedy",meaningitwillmatchasmuchaspossible:

>"anything within".match(/n.*h/g);["nythingwith"]

?

Matchestheprecedingpatternifitoccurszerooronetimes:

>"anything".match(/ny?/g);["ny","n"]

+

Matchestheprecedingpatternifitoccursatleastonce(ormoretimes):

>"anything".match(/ny+/g);["ny"]>"R2-D2andC-3PO".match(/[a-z]/gi);["R","D","a","n","d","C","P","O"]>"R2-D2andC-3PO".match(/[a-z]+/gi);["R","D","and","C","PO"]

{n}

Matchestheprecedingpatternifitoccursexactlyntimes:

>"regularexpression".match(/s/g);["s","s"] >"regularexpression".match(/s{2}/g);["ss"]>"regularexpression".match(/\b\w{3}/g);["reg","exp"]

{min,max}

Matchestheprecedingpatternifitoccursbetweenminandmaxnumberoftimes.Youcanomitmax,whichwillmeannomaximum,butonlyaminimum.Youcannotomitmin.

Anexamplewheretheinputis"doodle"withthe"o"repeated10times:

>"doooooooooodle".match(/o/g);["o","o","o","o","o","o","o","o","o","o"]>"doooooooooodle".match(/o/g).length;10>"doooooooooodle".match(/o{2}/g);["oo","oo","oo","oo","oo"]>"doooooooooodle".match(/o{2,}/g);["oooooooooo"]>"doooooooooodle".match(/o{2,6}/g);["oooooo","oooo"]

Whenthepatternisinparentheses,itisrememberedsothatitcanbeusedforreplacements.Thesearealsoknownascapturingpatterns.

Thecapturedmatchesareavailableas$1,$2,...$9

Matchingall"r"occurrencesandrepeatingthem:

Page 568: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

(pattern) >"regularexpression".replace(/(r)/g,'$1$1');"rregularrexprression"

Matching"re"andturningitto"er":

>"regularexpression".replace(/(r)(e)/g,'$2$1');"ergularexperssion"

(?:pattern)

Non-capturingpattern,notrememberedandnotavailablein$1,$2...

Here'sanexampleofhow"re"ismatched,butthe"r"isnotrememberedandthesecondpatternbecomes$1:

>"regularexpression".replace(/(?:r)(e)/g,'$1$1');"eegularexpeession"

Makesureyoupayattentionwhenaspecialcharactercanhavetwomeanings,asisthecasewith^,?,and\b.

Page 569: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Appendix E. Answers to Exercise QuestionsThis appendix lists possible answers to the exercises at the end of the chapters. Possible answersmeaningtheyarenottheonlyones,sodon'tworryifyoursolutionisdifferent.

Aswiththerestofthebook,youshouldtrytheminyourconsoleandplayaroundabit.

Thefirstandthelastchaptersdon'thavetheExercisessection,solet'sstartwithChapter2,PrimitiveDataTypes,Arrays,Loops,andConditions.

Page 570: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 2, Primitive Data Types, Arrays,Loops,andConditionsLetstryandsolvethefollowingexercises:

Page 571: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Theresultwillbeasfollows:

>vara;typeofa;"undefined"

Whenyoudeclareavariablebutdonotinitializeitwithavalue,itautomaticallygetstheundefinedvalue.Youcanalsocheck:

>a===undefined;true

Thevalueofvwillbe:

>vars='1s';s++;NaN

Adding 1 to the string '1s' returns the string '1s1', which is Not A Number, but the ++operator should return a number; so it returns the special NaN number.

Theprogramisasfollows:

>!!"false";true

Thetrickypartofthequestionisthat"false"isastringandallstringsaretruewhencasttoBooleans(excepttheemptystring"").Ifthequestionwasn'taboutthestring"false"buttheBooleanfalseinstead,thedoublenegation!!returnsthesameBoolean:

>!!false;false

Asyou'dexpect,singlenegationreturnstheopposite:

>!false;true>!true;false

YoucantestwithanystringanditwillcasttoaBooleantrue,excepttheemptystring:

>!!"hello";true>!!"0";true>!!"";false

Theoutputafterexecutingundefinedisasfollows:

Page 572: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>!!undefined;false

Hereundefinedis oneofthefalsyvaluesanditcaststofalse.Youcantrywithanyoftheotherfalsyvalues,suchtheemptystring""inthepreviousexample,NaN,or0.

> typeof -Infinity;"number"

Thenumbertypeincludesallnumbers,NaN,positiveandnegativeInfinity.

Theoutputafterexecutingthefollowingis:

>10%"0";NaN

Thestring"0"iscasttothenumber0.Divisionby0isInfinity,whichhasnoremainder.

Theoutputafterexecutingthefollowingis:

>undefined==null;true

Comparison with == operator doesn't check the types, but converts the operands; in this caseboth are falsy values. Strict comparison checks the types too:

>undefined===null;false

Thefollowingisthecodelineanditsoutput:

>false==="";false

Strictcomparisonbetweendifferenttypes(inthiscaseBooleanandstring)isdoomedtofail,nomatterwhat thevaluesare.

Thefollowingisthecodelineanditsoutput:

>typeof"2E+2";"string"

Anythinginquotesisastring,eventhough:

>2E+2;200>typeof2E+2;"number"

Thefollowingisthecodelineanditsoutput:

Page 573: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>a=3e+3;a++;3000

3e+3is3withthreezeroes,meaning3000.Then++isapost-increment,meaningitreturnstheoldvalueandthenitincrementsitandassignsittoa.That'swhyyougetthereturnvalue3000intheconsole,althoughaisnow3001:

> a;3001

2. Thevalueofvafterexecutingthefollowingis:

>varv=v||10;>v;10

Ifvhasneverbeendeclared,it'sundefinedsothisisthesameas:

>varv=undefined||10;>v;10

However,ifvhasalreadybeendefinedandinitializedwithanon-falsyvalue,you'llgetthepreviousvalue.

>varv=100;>varv=v||10;>v;100

Theseconduseofvardoesn't"reset"thevariable.

Ifvwasalreadyafalsyvalue(nota100),thecheckv||10willreturn10.

>varv=0;> var v = v || 10;

>v;10

3. Forprintingmultiplicationtables,performthefollowing:

for(vari=1;i<=12;i++){for(varj=1;j<=12;j++){console.log(i+'*'+j+'='+i*j);}}

Or:

vari=1,j=1;while(i<=12){

while (j <= 12) {

Page 574: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

console.log(i+'*'+j+'='+i*j);j++;}i++;j=1;}

Page 575: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 3, FunctionsLets do the following exercises:

Page 576: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. ToconvertHexcolorstoRGB,performthefollowing:

functiongetRGB(hex){return"rgb("+parseInt(hex[1]+hex[2],16)+","+parseInt(hex[3]+hex[4],16)+","+parseInt(hex[5]+hex[6],16)+")";}Testing:>getRGB("#00ff00");"rgb(0,255,0)">getRGB("#badfad");"rgb(186,223,173)"

One problemwith this solution is that array access to strings like hex[0] is not inECMAScript 3, although many browsers have supported it for a long time and is nowdescribedinES5.

However,Butatthispointinthebook,therewasasyetnodiscussionofobjectsandmethods.OtherwiseanES3-compatiblesolutionwouldbetouseoneofthestringmethods,suchascharAt(),substring(),orslice().Youcanalsouseanarraytoavoidtoomuchstringconcatenation:

function getRGB2(hex) {varresult=[];result.push(parseInt(hex.slice(1,3),16));result.push(parseInt(hex.slice(3,5),16));result.push(parseInt(hex.slice(5),16));return"rgb("+result.join(",")+")";}

Bonusexercise:Rewritetheprecedingfunctionusingaloopsoyoudon'thavetotypeparseInt()threetimes,butjustonce.

2. Theresultisasfollows:

>parseInt(1e1);10Here,you'reparsingsomethingthatisalreadyaninteger:>parseInt(10);10>1e1;10

Here,theparsingofastringgivesuponthefirstnon-integervalue.parseInt()doesn'tunderstandexponentialliterals,itexpectsintegernotation:

>parseInt('1e1');1

Page 577: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Thisisparsingthestring'1e1'whileexpectingittobeindecimalnotation,includingexponential:

>parseFloat('1e1');10

Thefollowingisthecodelineanditsoutput:

>isFinite(0/10);true

Because0/10is0and0isfinite.

Thefollowingisthecodelineanditsoutput:

>isFinite(20/0);false

Becausedivisionby0isInfinity:

>20/0;Infinity

Thefollowingisthecodelineanditsoutput:

>isNaN(parseInt(NaN));true

ParsingthespecialNaNvalueisNaN.3. Whatistheresultof:

vara=1;functionf(){functionn(){alert(a);}vara=2;n();}f();

Thissnippetalerts2eventhoughn()wasdefinedbeforetheassignment,a=2.Insidethefunctionn()youseethevariableathatisinthesamescope,andyouaccessitsmostrecentvalueatthetimeinvocationoff()(andhencen()).Duetohoistingf()actsasifitwas:

functionf(){vara;functionn(){alert(a);}a=2;

Page 578: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

n();}

Moreinterestingly,considerthiscode:

vara=1;functionf(){functionn(){alert(a);

}n();vara=2;n();}f();

Italertsundefinedandthen2.Youmightexpectthefirstalerttosay1,butagainduetovariablehoisting,thedeclaration(notinitialization)ofaismovedtothetopofthefunction.Asiff()was:

var a = 1;functionf(){vara;//aisnowundefinedfunctionn(){alert(a);}n();//alertundefineda=2;n();//alert2}f();

Thelocala"shadows"theglobala,evenifit'satthebottom.4. Whyallthesealert"Boo!"

ThefollowingistheresultofExample1:

varf=alert;eval('f("Boo!")');

ThefollowingistheresultofExample2.Youcanassignafunctiontoadifferentvariable.Sof()pointstoalert().Evaluatingthisstringislikedoing:

>f("Boo");

Thefollowingistheoutputafterweexecute eval():

vare;varf=alert;eval('e=f')('Boo!');

Page 579: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ThefollowingistheoutputofExample3.eval()returnstheresultontheevaluation.Inthiscaseit'sanassignmente=fthatalsoreturnsthenewvalueofe.Likethefollowing:

>vara=1;>varb;>varc=(b=a);>c;1

Soeval('e=f')givesyouapointertoalert()thatisexecutedimmediatelywith"Boo!".

Theimmediate(self-invoking)anonymousfunctionreturnsapointertothefunctionalert(),whichisalsoimmediatelyinvokedwithaparameter"Boo!":

(function(){returnalert;})()('Boo!');

Page 580: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 4, ObjectsLets solve the following exercises:

Page 581: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Whathappenshere?Whatisthisandwhat'so?

functionF(){functionC(){returnthis;}returnC();}varo=newF();

Here, this === window because C() was called without new.

Alsoo===windowbecausenewF()returnstheobjectreturnedbyC(),whichisthis,andthisiswindow.

YoucanmakethecalltoC()aconstructorcall:

function F() {functionC(){returnthis;}returnnewC();}varo=newF();

Here,thisistheobjectcreatedbytheC()constructor.Soiso:

>o.constructor.name;"C"

ItbecomesmoreinterestingwithES5'sstrictmode.Inthestrictmode,non-constructorinvocationsresultinthisbeingundefined,nottheglobalobject.With"usestrict"insideF()orC()constructor'sbody,thiswouldbeundefinedinC().Therefore,returnC()cannotreturnthenon-objectundefined(becauseallconstructorinvocationsreturnsomesortofobject)andreturnsFinstances' this(whichisintheclosurescope).Tryit:

functionF(){"usestrict";this.name="IamF()";functionC(){console.log(this);//undefinedreturnthis;}

return C();}

Testing:

Page 582: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>varo=newF();>o.name;"IamF()"

2. Whathappenswheninvokingthisconstructorwithnew?

functionC(){this.a=1;returnfalse;}Andtesting:>typeofnewC();"object">newC().a;1

newC()isanobject,notBoolean,becauseconstructorinvocationsalwaysproduceanobject.It'sthethisobjectyougetunlessyoureturnsomeotherobjectinyourconstructor.Returningnon-objectsdoesn'tworkandyoustillgetthis.

3. Whatdoesthisdo?

>varc=[1,2,[1,2]];>c.sort();>c;[1,Array[2],2]

Thisisbecausesort()comparesstrings.[1,2].toString()is"1,2",soitcomesafter"1"andbefore"2".

Thesamethingwithjoin():

>c.join('--');>c;"1--1,2--2"

4. PretendString()doesn'texistandcreateMyString()mimickingString().Treattheinputprimitivestringsasarrays(arrayaccessofficiallysupportedinES5).

Here'sasampleimplementationwithjustthemethodstheexerciseaskedfor.Feelfreetocontinuewiththerestofthemethods.RefertoAppendixC,Built-inObjectsforthefulllist.

functionMyString(input){varindex=0;//casttostringthis._value=''+input;//setallnumericpropertiesforarrayaccesswhile(input[index]!==undefined){this[index]=input[index];index++;

Page 583: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}//rememberthelengththis.length=index;}MyString.prototype={constructor:MyString,valueOf:functionvalueOf(){returnthis._value;},toString:functiontoString(){returnthis.valueOf();},charAt:functioncharAt(index){returnthis[parseInt(index,10)||0];},concat:functionconcat(){varprim=this.valueOf();for(vari=0,len=arguments.length;i<len;i++){prim+=arguments[i];

}returnprim;},slice:functionslice(from,to){varresult='',original=this.valueOf();if(from===undefined){returnoriginal;}if(from>this.length){returnresult;}if(from<0){from=this.length-from;}if(to===undefined||to>this.length){to=this.length;}if(to<0){to=this.length+to;}//endofvalidation,actualslicingloopnowfor(vari=from;i<to;i++){result+=original[i];}

return result;},split:functionsplit(re){varindex=0,result=[],original=this.valueOf(),match,

Page 584: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

pattern='',modifiers='g';if(reinstanceofRegExp){//splitwithregexpbutalwaysset"g"pattern=re.source;modifiers+=re.multiline?'m':'';modifiers+=re.ignoreCase?'i':'';}else{//notaregexp,probablyastring,we'llconvertitpattern=re;}re=RegExp(pattern,modifiers);while(match=re.exec(original)){result.push(this.slice(index,match.index));index=match.index+newMyString(match[0]).length;}result.push(this.slice(index));returnresult;}

};

Testing:

>vars=newMyString('hello');>s.length;5>s[0];"h">s.toString();"hello">s.valueOf();"hello"

> s.charAt(1);"e">s.charAt('2');"l">s.charAt('e');"h">s.concat('world!');"helloworld!">s.slice(1,3);"el">s.slice(0,-1);"hell">s.split('e');["h","llo"]>s.split('l');["he","","o"]

Feelfreetoplaysplittingwitharegularexpression.5. UpdateMyString()withareverse()method:

Page 585: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

>MyString.prototype.reverse=functionreverse(){returnthis.valueOf().split("").reverse().join("");};>newMyString("pudding").reverse();"gniddup"

6. ImagineArray()isgoneandtheworldneedsyoutoimplementMyArray().Hereareahandfulofmethodstogetyoustarted:

functionMyArray(length){//singlenumericargumentmeanslengthif(typeoflength==='number'&&arguments[1]===undefined){this.length=length;returnthis;}//usualcasethis.length=arguments.length;for(vari=0,len=arguments.length;i<len;i++){this[i]=arguments[i];}returnthis;//laterinthebookyou'lllearnhowtosupport

// a non-constructor invocation too}MyArray.prototype={constructor:MyArray,join:functionjoin(glue){varresult='';if(glue===undefined){glue=',';}for(vari=0;i<this.length-1;i++){result+=this[i]===undefined?'':this[i];result+=glue;}result+=this[i]===undefined?'':this[i];returnresult;},toString:functiontoString(){returnthis.join();},push:functionpush(){for(vari=0,len=arguments.length;i<len;i++){this[this.length+i]=arguments[i];}this.length+=arguments.length;

return this.length;},pop:functionpop(){

Page 586: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

varpoppd=this[this.length-1];deletethis[this.length-1];this.length--;returnpoppd;}};

Testing:

> var a = new MyArray(1, 2, 3, "test");>a.toString();"1,2,3,test">a.length;4>a[a.length-1];"test">a.push('boo');5>a.toString();"1,2,3,test,boo">a.pop();"boo">a.toString();"1,2,3,test">a.join(',');"1,2,3,test">a.join('isn't');"1isn't2isn't3isn'ttest"

Ifyoufoundthisexerciseamusing,don'tstopwithjoin();goonwithasmanymethodsaspossible.

7. CreateMyMathobjectthatalsohasrand(),min([]),max([]).

ThepointhereisthatMathisnotaconstructor,butanobjectthathassome"static"propertiesandmethods.Belowaresomemethodstogetyoustarted.

Let's also use an immediate function to keep some private utility functions. You can also takethisapproachwithMyStringabove,wherethis._valuecouldbereallyprivate.

varMyMath=(function(){functionisArray(ar){returnObject.prototype.toString.call(ar)==='[objectArray]';}functionsort(numbers){//notusingnumbers.sort()directlybecause//`arguments`isnotanarrayanddoesn'thavesort()returnArray.prototype.sort.call(numbers,function(a,b){

Page 587: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

if(a===b){return0;}return1*(a>b)-0.5;//returns0.5or-0.5});}return{PI:3.141592653589793,E:2.718281828459045,LN10:2.302585092994046,LN2:0.6931471805599453,//...moreconstantsmax:functionmax(){//allowunlimitednumberofarguments//oranarrayofnumbersasfirstargumentvarnumbers=arguments;if(isArray(numbers[0])){numbers=numbers[0];}//wecanbelazy:

// let Array sort the numbers and pick the lastreturnsort(numbers)[numbers.length-1];},min:functionmin(){//differentapproachtohandlingarguments://callthesamefunctionagainif(isArray(numbers)){returnthis.min.apply(this,numbers[0]);}//Differentapproachtopickingthemin://sortingthearrayisanoverkill,it'stoomuch//worksincewedon'tworryaboutsortingbutonly//aboutthesmallestnumber.//Solet'sloop:varmin=numbers[0];for(vari=1;i<numbers.length;i++){if(min>numbers[i]){min=numbers[i];}}returnmin;},rand:functionrand(min,max,inclusive){if(inclusive){

return Math.round(Math.random() * (max - min) + min);//testboundariesforrandomnumber//between10and100*inclusive*://Math.round(0.000000*90+10);//10//Math.round(0.000001*90+10);//10//Math.round(0.999999*90+10);//100

Page 588: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

}returnMath.floor(Math.random()*(max-min-1)+min+1);//testboundariesforrandomnumber//between10and100*non-inclusive*://Math.floor(0.000000*(89)+(11));//11//Math.floor(0.000001*(89)+(11));//11//Math.floor(0.999999*(89)+(11));//99}};})();

AfteryouhavefinishedthebookandknowaboutES5youcantryusingdefineProperty()fortightercontrolandcloserreplicationofthebuilt-ins.

Page 589: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 5, PrototypeLets try and solve the following exercise:

Page 590: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. CreateanobjectcalledshapethathasatypepropertyandagetType()method:

varshape={type:'shape',getType:function(){returnthis.type;}};

2. ThefollowingistheprogramforaTriangle()constructor:

functionTriangle(a,b,c){this.a = a;

this.b=b;this.c=c;}Triangle.prototype=shape;Triangle.prototype.constructor=Triangle;Triangle.prototype.type='triangle';

3. ToaddthegetPerimeter()method,usethefollowingcode:

Triangle.prototype.getPerimeter=function(){returnthis.a+this.b+this.c;};

4. Testthefollowingcode:

>vart=newTriangle(1,2,3);>t.constructor===Triangle;true>shape.isPrototypeOf(t);true>t.getPerimeter();6>t.getType();"triangle"

5. Loopovertshowingonlyownpropertiesandmethods:

for(variint){if(t.hasOwnProperty(i)){console.log(i,'=',t[i]);}}

6. Randomizearrayelementsusingthefollowingcodesnippet:

Array.prototype.shuffle=function(){returnthis.sort(function(){returnMath.random()-0.5;

Page 591: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

});};

Testing:

>[1,2,3,4,5,6,7,8,9].shuffle();[4,2,3,1,5,6,8,9,7]>[1,2,3,4,5,6,7,8,9].shuffle();[2,7,1,3,4,5,8,9,6]

> [1, 2, 3, 4, 5, 6, 7, 8, 9].shuffle();[4,2,1,3,5,6,8,9,7]

Page 592: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 6, InheritanceLets solve the following exercise:

Page 593: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Multipleinheritancebymixingintotheprototype,forexample:

varmy=objectMulti(obj,another_obj,a_third,{additional:"properties"});Apossiblesolution:functionobjectMulti(){varConstr,i,prop,mixme;//constructorthatsetsownpropertiesvarConstr=function(props){for(varpropinprops){this[prop]=props[prop];}};//mixintotheprototype

for (var i = 0; i < arguments.length - 1; i++) {varmixme=arguments[i];for(varpropinmixme){Constr.prototype[prop]=mixme[prop];}}returnnewConstr(arguments[arguments.length-1]);}

Testing:

>varobj_a={a:1};> var obj_b = {a: 2, b: 2};

>varobj_c={c:3};>varmy=objectMulti(obj_a,obj_b,obj_c,{hello:"world"});>my.a;2

Propertyais2becauseobj_boverwrotethepropertywiththesamenamefromobj_a(lastonewins):

>my.b;2>my.c;3>my.hello;

"world">my.hasOwnProperty('a');false>my.hasOwnProperty('hello');true

Page 594: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

2. Practicewiththecanvasexampleathttp://www.phpied.com/files/canvas/.

Drawafewtrianglesusingthefollowingcodesnippet:

newTriangle(newPoint(100,155),newPoint(30,50),newPoint(220,00)).draw();newTriangle(newPoint(10,15),newPoint(300,50),newPoint(20,400)).draw();

Drawafewsquaresusingthefollowingcodesnippet:

newSquare(newPoint(150,150),300).draw();newSquare(newPoint(222,222),222).draw();

Drawafewrectanglesusingthefollowingcodesnippet:

newRectangle(newPoint(100,10),200,400).draw();newRectangle(newPoint(400,200),200,100).draw();

3. ToaddRhombus,Kite,Pentagon,Trapezoid,andCircle(reimplementsdraw()),usethefollowingcode:

functionKite(center,diag_a,diag_b,height){this.points=[newPoint(center.x-diag_a/2,center.y),newPoint(center.x,center.y+(diag_b-height)),newPoint(center.x+diag_a/2,center.y),newPoint(center.x,center.y-height)];this.getArea=function(){returndiag_a*diag_b/2;};}functionRhombus(center,diag_a,diag_b){Kite.call(this,center,diag_a,diag_b,diag_b/2);}functionTrapezoid(p1,side_a,p2,side_b){

this.points = [p1, p2, new Point(p2.x + side_b, p2.y),newPoint(p1.x+side_a,p1.y)];this.getArea=function(){varheight=p2.y-p1.y;returnheight*(side_a+side_b)/2;};}

Page 595: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

//regularpentagon,alledgeshavethesamelengthfunctionPentagon(center,edge){varr=edge/(2*Math.sin(Math.PI/5)),x=center.x,y=center.y;this.points=[newPoint(x+r,y),newPoint(x+r*Math.cos(2*Math.PI/5),y-r*Math.sin(2*Math.PI/5)),newPoint(x-r*Math.cos(Math.PI/5),y-r*Math.sin(Math.PI/5)),newPoint(x-r*Math.cos(Math.PI/5),y+r*Math.sin(Math.PI/5)),newPoint(x+r*Math.cos(2*Math.PI/5),y+r*Math.sin(2*Math.PI/5))];this.getArea=function(){return1.72*edge*edge;};

}functionCircle(center,radius){this.getArea=function(){returnMath.pow(radius,2)*Math.PI;};this.getPerimeter=function(){return2*radius*Math.PI;};this.draw=function(){varctx=this.context;ctx.beginPath();ctx.arc(center.x,center.y,radius,0,2*Math.PI);ctx.stroke();};}(function(){vars=newShape();Kite.prototype=s;Rhombus.prototype=s;Trapezoid.prototype=s;Pentagon.prototype=s;

Circle.prototype = s;}());

Testing:

newKite(newPoint(300,300),200,300,100).draw();newRhombus(newPoint(200,200),350,200).draw();

Page 596: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

newTrapezoid(newPoint(100,100),100,newPoint(50,250),400).draw();newPentagon(newPoint(400,400),100).draw();newCircle(newPoint(500,300),270).draw();

Theresultoftestingnewshapes4. Thinkofanotherwaytodotheinheritancepart.Useubersokidscanhaveaccesstotheirparents.Also,getparentstobeawareoftheirchildren.

KeepinmindthatnotallchildreninheritShape;forexample,RhombusinheritsKiteandSquareinheritsRectangle.Youendupwithsomethinglikethis:

//inherit(Child,Parent)inherit(Rectangle,Shape);

Page 597: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

inherit(Square,Rectangle);

Intheinheritancepatternfromthechapterandthepreviousexercise,allchildrenweresharingthesameprototype,forexample:

vars=newShape();Kite.prototype=s;Rhombus.prototype=s;

Whilethisisconvenient,italsomeansnoonecantouchtheprototypebecauseitwillaffecteveryoneelse'sprototype.Thedrawbackisthatallcustommethodsneedtoownproperties,forexamplethis.getArea.

It'sagoodideatohavemethodssharedamonginstancesanddefined intheprototype,insteadofrecreatingthemforeveryobject.ThefollowingexamplemovesthecustomgetArea()methodstotheprototype.

Intheinheritancefunction,you'llseethechildrenonlyinherittheparent'sprototype.Soownpropertiessuchasthis.lineswillnotbeset.Therefore,youneedtohaveeachchildconstructorcallitsuberinordertogettheownproperties,forexample:

Child.prototype.uber.call(this,args...)

Anothernice-to-havefeatureiscarryingovertheprototypepropertiesalreadyaddedtothechild.Thisallowsthechildtoinheritfirstandthenaddmorecustomizationsortheotherway around as well, which is just a little more convenient.

functioninherit(Child,Parent){//rememberprototypevarextensions=Child.prototype;//inheritancewithanintermediateF()varF=function(){};F.prototype=Parent.prototype;Child.prototype=newF();//resetconstructorChild.prototype.constructor=Child;//rememberparentChild.prototype.uber=Parent;//keeptrackofwhoinheritstheParent

if (!Parent.children) {Parent.children=[];}Parent.children.push(Child);//carryoverstuffprevisoulyaddedtotheprototype//becausetheprototypeisnowoverwrittencompletelyfor(variinextensions){if(extensions.hasOwnProperty(i)){

Page 598: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Child.prototype[i]=extensions[i];}}}

EverythingaboutShape(),Line(),andPoint()staysthesame.Thechangesareinthechildrenonly:

functionTriangle(a,b,c){Triangle.prototype.uber.call(this);

this.points = [a, b, c];}Triangle.prototype.getArea=function(){varp=this.getPerimeter(),s=p/2;returnMath.sqrt(s*(s-this.lines[0].length)*(s-this.lines[1].length)*(s-this.lines[2].length));};functionRectangle(p,side_a,side_b){//callingparentShape()Rectangle.prototype.uber.call(this);this.points=[p,newPoint(p.x+side_a,p.y),newPoint(p.x+side_a,p.y+side_b),newPoint(p.x,p.y+side_b)];}Rectangle.prototype.getArea=function(){//Previsoulywehadaccesstoside_aandside_b//insidetheconstructorclosure.Nomore.//option1:addownpropertiesthis.side_aandthis.side_b

// option 2: use what we already have:varlines=this.getLines();returnlines[0].length*lines[1].length;};functionSquare(p,side){this.uber.call(this,p,side,side);//thiscallisshorterthanSquare.prototype.uber.call()//butmaybackfireincaseyouinherit//fromSquareandcalluber//tryit:-)}

Inheritance:

inherit(Triangle,Shape);inherit(Rectangle,Shape);

Page 599: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

inherit(Square,Rectangle);

Testing:

>varsq=newSquare(newPoint(0,0),100);>sq.draw();>sq.getArea();10000

Testingthatinstanceofiscorrect:

>sq.constructor===Square;true>sqinstanceofSquare;true>sqinstanceofRectangle;true>sqinstanceofShape;

true

Thechildrenarrays:

>Shape.children[1]===Rectangle;true>Rectangle.children[0]===Triangle;false>Rectangle.children[0]===Square;

true>Square.children;undefined

Anduberlooksoktoo:

>sq.uber===Rectangle;true

CallingisPrototypeOf()alsoreturnsexpectedresults:

Shape.prototype.isPrototypeOf(sq);trueRectangle.prototype.isPrototypeOf(sq);trueTriangle.prototype.isPrototypeOf(sq);false

Thefullcodeisavailableathttp://www.phpied.com/files/canvas/index2.html,togetherwiththeadditionalKite(),Circle(),andsoonfromthepreviousexercise.

Page 600: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Chapter 7, The Browser EnvironmentLets practice the following exercise:

Page 601: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Exercises1. Thetitleclockprogramisasfollows:

setInterval(function(){document.title=newDate().toTimeString();},1000);

2. Toanimateresizingofa200x200popupto400x400,usethefollowingcode:

varw=window.open('http://phpied.com','my','width=200,height=200');vari=setInterval((function(){varsize=200;returnfunction(){size+=5;w.resizeTo(size,size);if(size===400){clearInterval(i);}

};}()),100);

Every100ms(1/10thofasecond)thepop-upsizeincreasesbyfivepixels.Youkeepareferencetotheintervalisoyoucanclearitoncedone.Thevariablesizetracksthepop-upsize(andwhynotkeepitprivateinsideaclosure).

3. Theearthquakeprogramisasfollows:

vari=setInterval((function(){varstart=+newDate();//Date.now()inES5returnfunction(){w.moveTo(Math.round(Math.random()*100),Math.round(Math.random()*100));if(newDate()-start>5000){clearInterval(i);}};}()),20);

Tryallofthem,butusingrequestAnimationFrame()insteadofsetInterval().4. AdifferentwalkDOM()withacallbackisasfollows:

functionwalkDOM(n,cb){cb(n);vari,children=n.childNodes,len=children.length,child;for(i=0;i<len;i++){

Page 602: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

child=n.childNodes[i];if(child.hasChildNodes()){walkDOM(child,cb);}}}

Testing:

> walkDOM(document.documentElement,console.dir.bind(console));htmlheadtitlebodyh1...

5. Toremovecontentandcleanupfunctions,usethefollowingcode:

//helperfunctionisFunction(f){returnObject.prototype.toString.call(f)==="[objectFunction]";}functionremoveDom(node){vari,len,attr;//firstdrilldowninspectingthechildren//andonlyafterthatremovethecurrentnodewhile(node.firstChild){removeDom(node.firstChild);}//notallnodeshaveattributes,e.g.textnodesdon'tlen=node.attributes?node.attributes.length:0;

//cleanuploop//e.g.node===<body>,//node.attributes[0].name==="onload"//node.onload===function()...//node.onloadisnotenumerablesowecan'tuse//afor-inloopandhavetogotheattributesroutefor(i=0;i<len;i++){attr=node[node.attributes[i].name];if(isFunction(attr)){//console.log(node,attr);attr=null;}}node.parentNode.removeChild(node);}

Page 603: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

Testing:

>removeDom(document.body);

6. Toincludescriptsdynamically,usethefollowingcode:

functioninclude(url){vars=document.createElement('script');s.src=url;document.getElementsByTagName('head')[0].appendChild(s);}

Testing:

>include("http://www.phpied.com/files/jinc/1.js");>include("http://www.phpied.com/files/jinc/2.js");

7. Events:Theeventutilityprogramisasfollows:

varmyevent=(function(){//wrapsomeprivatestuffinaclosurevaradd,remove,toStr=Object.prototype.toString;//helperfunctiontoArray(a){//alreadyanarrayif(toStr.call(a)==='[objectArray]'){returna;}

// duck-typing HTML collections, arguments etcvarresult,i,len;if('length'ina){for(result=[],i=0,len=a.length;i<len;i++){result[i]=a[i];}returnresult;}//primitivesandnon-array-likeobjects//becomethefirstandsinglearrayelementreturn[a];}//defineadd()andremove()depending//onthebrowser'scapabilitiesif(document.addEventListener){add=function(node,ev,cb){node.addEventListener(ev,cb,false);};remove=function(node,ev,cb){

Page 604: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

node.removeEventListener(ev,cb,false);};}elseif(document.attachEvent){add=function(node,ev,cb){node.attachEvent('on'+ev,cb);};remove=function(node,ev,cb){node.detachEvent('on'+ev,cb);};}else{add=function(node,ev,cb){node['on'+ev]=cb;};remove=function(node,ev){node['on'+ev]=null;};}//publicAPIreturn{

addListener: function (element, event_name, callback) {//elementcouldalsobeanarrayofelementselement=toArray(element);for(vari=0;i<element.length;i++){add(element[i],event_name,callback);}},removeListener:function(element,event_name,callback){//sameasadd(),onlypracticingadifferentloopvari=0,els=toArray(element),len=els.length;for(;i<len;i++){remove(els[i],event_name,callback);}},getEvent:function(event){returnevent||window.event;},getTarget:function(event){vare=this.getEvent(event);returne.target||e.srcElement;},

stopPropagation: function (event) {vare=this.getEvent(event);if(e.stopPropagation){e.stopPropagation();}else{e.cancelBubble=true;}

Page 605: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

},preventDefault:function(event){vare=this.getEvent(event);if(e.preventDefault){e.preventDefault();}else{e.returnValue=false;}}};}());

Testing:Gotoanypagewithlinks,executethefollowing,andthenclickanylink:

functionmyCallback(e){e=myevent.getEvent(e);alert(myevent.getTarget(e).href);myevent.stopPropagation(e);myevent.preventDefault(e);}myevent.addListener(document.links,'click',myCallback);

8. Moveadivaroundwiththekeyboardusing thefollowingcode:

//addadivtothebottomofthepagevardiv=document.createElement('div');div.style.cssText='width:100px;height:100px;background:red;position:absolute;';document.body.appendChild(div);//remembercoordinates

var x = div.offsetLeft;vary=div.offsetTop;myevent.addListener(document.body,'keydown',function(e){//preventscrollingmyevent.preventDefault(e);switch(e.keyCode){case37://leftx--;break;case38://upy--;break;case39://rightx++;break;case40://downy++;break;

Page 606: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

default://notinterested}//movediv.style.left=x+'px';div.style.top=y+'px';});

9. YourownAjaxutility:

varajax={getXHR:function(){varids=['MSXML2.XMLHTTP.3.0','MSXML2.XMLHTTP','Microsoft.XMLHTTP'];varxhr;if(typeofXMLHttpRequest==='function'){xhr=newXMLHttpRequest();}else{//IE:trytofindanActiveXobjecttousefor(vari=0;i<ids.length;i++){try{xhr=newActiveXObject(ids[i]);

break;}catch(e){}}}returnxhr;},request:function(url,method,cb,post_body){varxhr=this.getXHR();xhr.onreadystatechange=(function(myxhr){returnfunction(){if(myxhr.readyState===4&&myxhr.status===200){cb(myxhr);}};}(xhr));xhr.open(method.toUpperCase(),url,true);xhr.send(post_body||'');}};

Whentesting,rememberthatsameoriginrestrictionsapply,soyouhavetobeonthesamedomain.Youcangotohttp://www.phpied.com/files/jinc/,whichisadirectorylistingandthentestintheconsole:

functionmyCallback(xhr){alert(xhr.responseText);}ajax.request('1.css','get',myCallback);

Page 607: Object-Oriented JavaScript - Third Edition · 2017. 4. 20. · ES6 object literals Object properties and attributes ES6 object methods Copy properties using Object.assign Compare

ajax.request('1.css','post',myCallback,'first=John&last=Smith');

Theresultofthetwoisthesame,butifyoulookintotheNetworktaboftheWebInspector,youcanseethatthesecondisindeedaPOSTrequestwithabody.