table of contentsedu-9.de/uploads/books/javascript-handbook.pdf · javascript is now also the...

Post on 06-Mar-2021

2 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

TableofContentsPreface

IntroductiontoJavaScript

ECMAScript

ES6

ES2016

ES2017

ES2018

Codingstyle

LexicalStructure

Variables

Types

Expressions

Prototypalinheritance

Classes

Exceptions

Semicolons

Quotes

TemplateLiterals

Functions

ArrowFunctions

Closures

Arrays

Loops

Events

TheEventLoop

Asynchronousprogrammingandcallbacks

Promises

AsyncandAwait

LoopsandScope

Timers

2

this

StrictMode

Immediately-invokedFunctionExpressions(IIFE)

Mathoperators

TheMathobject

ESModules

CommonJS

Glossary

3

Preface

TheJavaScriptHandbookfollowsthe80/20rule:learnin20%ofthetimethe80%ofatopic.

Ifindthisapproachgivesawell-roundedoverview.ThisbookdoesnottrytocovereverythingunderthesunrelatedtoJavaScript.Ifyouthinksomespecifictopicshouldbeincluded,tellme.

YoucanreachmeonTwitter@flaviocopes.

Ihopethecontentsofthisbookwillhelpyouachievewhatyouwant:learnthebasicsofJavaScript.

ThisbookiswrittenbyFlavio.Ipublishwebdevelopmenttutorialseverydayonmywebsiteflaviocopes.com.

Enjoy!

Preface

4

IntroductiontoJavaScriptJavaScriptisoneofthemostpopularprogramminglanguagesintheworld,andnowwidelyusedalsooutsideofthebrowser.TheriseofNode.jsinthelastfewyearsunlockedbackenddevelopment,oncethedomainofJava,Ruby,Python,PHP,andmoretraditionalserver-sidelanguages.Learnallaboutit!

IntroductionJavaScriptisoneofthemostpopularprogramminglanguagesintheworld.

Created20yearsago,it'sgoneaverylongwaysinceitshumblebeginnings.

Beingthefirst-andtheonly-scriptinglanguagethatwassupportednativelybywebbrowsers,itsimplystuck.

Inthebeginnings,itwasnotnearlypowerfulasitistoday,anditwasmainlyusedforfancyanimationsandthemarvelknownatthetimeasDHTML.

Withthegrowingneedsthatthewebplatformdemands,JavaScripthadtheresponsibilitytogrowaswell,toaccommodatetheneedsofoneofthemostwidelyusedecosystemsoftheworld.

Manythingswereintroducedintheplatform,withbrowserAPIs,butthelanguagegrewquitealotaswell.

JavaScriptisnowwidelyusedalsooutsideofthebrowser.TheriseofNode.jsinthelastfewyearsunlockedbackenddevelopment,oncethedomainofJava,Ruby,PythonandPHPandmoretraditionalserver-sidelanguages.

JavaScriptisnowalsothelanguagepoweringdatabasesandmanymoreapplications,andit'sevenpossibletodevelopembeddedapplications,mobileapps,TVsetsappsandmuchmore.Whatstartedasatinylanguageinsidethebrowserisnowthemostpopularlanguageintheworld.

AbasicdefinitionofJavaScriptJavaScriptisaprogramminglanguagethatis:

highlevel:itprovidesabstractionsthatallowyoutoignorethedetailsofthemachinewhereit'srunningon.Itmanagesmemoryautomaticallywithagarbagecollector,soyou

IntroductiontoJavaScript

5

canfocusonthecodeinsteadofmanagingmemorylocations,andprovidesmanyconstructswhichallowyoutodealwithhighlypowerfulvariablesandobjects.dynamic:opposedtostaticprogramminglanguages,adynamiclanguageexecutesatruntimemanyofthethingsthatastaticlanguagedoesatcompiletime.Thishasprosandcons,anditgivesuspowerfulfeatureslikedynamictyping,latebinding,reflection,functionalprogramming,objectruntimealteration,closuresandmuchmore.dynamicallytyped:avariabledoesnotenforceatype.Youcanreassignanytypetoavariable,forexampleassigninganintegertoavariablethatholdsastring.weaklytyped:asopposedtostrongtyping,weakly(orloosely)typedlanguagesdonotenforcethetypeofanobject,allowingmoreflexibilitybutdenyingustypesafetyandtypechecking(somethingthatTypeScriptandFlowaimtoimprove)interpreted:it'scommonlyknownasaninterpretedlanguage,whichmeansthatitdoesnotneedacompilationstagebeforeaprogramcanrun,asopposedtoC,JavaorGoforexample.Inpractice,browsersdocompileJavaScriptbeforeexecutingit,forperformancereasons,butthisistransparenttoyou:thereisnoadditionalstepinvolved.multi-paradigm:thelanguagedoesnotenforceanyparticularprogrammingparadigm,unlikeJavaforexamplewhichforcestheuseofobjectorientedprogramming,orCthatforcesimperativeprogramming.YoucanwriteJavaScriptusinganobject-orientedparadigm,usingprototypesandthenew(asofES6)classessyntax.YoucanwriteJavaScriptinfunctionalprogrammingstyle,withitsfirstclassfunctions,oreveninanimperativestyle(C-like).

Incaseyou'rewondering,JavaScripthasnothingtodowithJava,it'sapoornamechoicebutwehavetolivewithit.

JavaScriptversionsLetmeintroducethetermECMAScripthere.WehaveacompleteguidededicatedtoECMAScriptwhereyoucandiveintoitmore,buttostartwith,youjustneedtoknowthatECMAScript(alsocalledES)isthenameoftheJavaScriptstandard.

JavaScriptisanimplementationofthatstandard.That'swhyyou'llhearaboutES6,ES2015,ES2016,ES2017,ES2018andsoon.

Foraverylongtime,theversionofJavaScriptthatallbrowserranwasECMAScript3.Version4wascanceledduetofeaturecreep(theyweretryingtoaddtoomanythingsatonce),whileES5wasahugeversionforJS.

ES2015,alsocalledES6,washugeaswell.

Sincethen,theonesinchargedecidedtoreleaseoneversionperyear,toavoidhavingtoomuchtimeidlebetweenreleases,andhaveafasterfeedbackloop.

IntroductiontoJavaScript

6

Currently,thelatestapprovedJavaScriptversionisES2017.

IntroductiontoJavaScript

7

ECMAScriptECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.DiscovereverythingaboutECMAScript,andthelastfeaturesaddedinES6,7,8

WheneveryoureadaboutJavaScriptyou'llinevitablyseeoneoftheseterms:

ES3ES5ES6ES7ES8ES2015ES2016ES2017ECMAScript2017ECMAScript2016

ECMAScript

8

ECMAScript2015

Whatdotheymean?

Theyareallreferringtoastandard,calledECMAScript.

ECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.

BesideJavaScript,otherlanguagesimplement(ed)ECMAScript,including:

ActionScript(theFlashscriptinglanguage),whichislosingpopularitysinceFlashwillbeofficiallydiscontinuedin2020JScript(theMicrosoftscriptingdialect),sinceatthetimeJavaScriptwassupportedonlybyNetscapeandthebrowserwarswereattheirpeak,MicrosofthadtobuilditsownversionforInternetExplorer

butofcourseJavaScriptisthemostpopularandwidelyusedimplementationofES.

Whythisweirdname? EcmaInternationalisaSwissstandardsassociationwhoisinchargeofdefininginternationalstandards.

WhenJavaScriptwascreated,itwaspresentedbyNetscapeandSunMicrosystemstoEcmaandtheygaveitthenameECMA-262aliasECMAScript.

ThispressreleasebyNetscapeandSunMicrosystems(themakerofJava)mighthelpfigureoutthenamechoice,whichmightincludelegalandbrandingissuesbyMicrosoftwhichwasinthecommittee,accordingtoWikipedia.

AfterIE9,MicrosoftstoppedstoppedbrandingitsESsupportinbrowsersasJScriptandstartedcallingitJavaScript(atleast,Icouldnotfindreferencestoitanymore)

Soasof201x,theonlypopularlanguagesupportingtheECMAScriptspecisJavaScript.

CurrentECMAScriptversionThecurrentECMAScriptversionisES2018.

ItwasreleasedinJune2018.

Whenisthenextversioncomingout?HistoricallyJavaScripteditionshavebeenstandardizedduringthesummer,sowecanexpectECMAScript2019tobereleasedinsummer2019,butthisisjustspeculation.

ECMAScript

9

WhatisTC39TC39isthecommitteethatevolvesJavaScript.

ThemembersofTC39arecompaniesinvolvedinJavaScriptandbrowservendors,includingMozilla,Google,Facebook,Apple,Microsoft,Intel,PayPal,SalesForceandothers.

Everystandardversionproposalmustgothroughvariousstages,whichareexplainedhere.

ESVersionsIfounditpuzzlingwhysometimesanESversionisreferencedbyeditionnumberandsometimesbyyear,andIamconfusedbytheyearbychancebeing-1onthenumber,whichaddstothegeneralconfusionaroundJS/ES

BeforeES2015,ECMAScriptspecificationswerecommonlycalledbytheiredition.SoES5istheofficialnamefortheECMAScriptspecificationupdatepublishedin2009.

Whydoesthishappen?DuringtheprocessthatledtoES2015,thenamewaschangedfromES6toES2015,butsincethiswasdonelate,peoplestillreferenceditasES6,andthecommunityhasnotlefttheeditionnamingbehind-theworldisstillcallingESreleasesbyeditionnumber.

Thistableshouldclearthingsabit:

Edition Officialname Datepublished

ES9 ES2018 June2018

ES8 ES2017 June2017

ES7 ES2016 June2016

ES6 ES2015 June2015

ES5.1 ES5.1 June2011

ES5 ES5 December2009

ES4 ES4 Abandoned

ES3 ES3 December1999

ES2 ES2 June1998

ES1 ES1 June1997

ESNext

ECMAScript

10

ES.NextisanamethatalwaysindicatesthenextversionofJavaScript.

Soatthetimeofwriting,ES9hasbeenreleased,andES.NextisES10

ECMAScript

11

ES6ECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.DiscovereverythingaboutECMAScript,andthelastfeaturesaddedinES6,akaES2015

ECMAScript2015,alsoknownasES6,isafundamentalversionoftheECMAScriptstandard.

Published4yearsafterthelateststandardrevision,ECMAScript5.1,italsomarkedtheswitchfromeditionnumbertoyearnumber.

SoitshouldnotbenamedasES6(althougheveryonecallsitassuch)butES2015instead.

ES5was10yearsinthemaking,from1999to2009,andassuchitwasalsoafundamentalandveryimportantrevisionofthelanguage,butnowmuchtimehaspassedthatit'snotworthdiscussinghowpre-ES5codeworked.

SincethislongtimepassedbetweenES5.1andES6,thereleaseisfullofimportantnewfeaturesandmajorchangesinsuggestedbestpracticesindevelopingJavaScriptprograms.TounderstandhowfundamentalES2015is,justkeepinmindthatwiththisversion,thespecificationdocumentwentfrom250pagesto~600.

ThemostimportantchangesinES2015include

ArrowfunctionsPromisesGeneratorsletand constClassesModulesMultilinestringsTemplateliteralsDefaultparametersThespreadoperator|DestructuringassignmentsEnhancedobjectliteralsThefor..ofloopMapandSet

Eachofthemhasadedicatedsectioninthisarticle.

ArrowFunctions

ES6

12

ArrowfunctionssincetheirintroductionchangedhowmostJavaScriptcodelooks(andworks).

Visually,it'sasimpleandwelcomechange,from:

constfoo=functionfoo(){

//...

}

to

constfoo=()=>{

//...

}

Andifthefunctionbodyisaone-liner,just:

constfoo=()=>doSomething()

Also,ifyouhaveasingleparameter,youcouldwrite:

constfoo=param=>doSomething(param)

Thisisnotabreakingchange,regular functionswillcontinuetoworkjustasbefore.

Anew thisscopeThe thisscopewitharrowfunctionsisinheritedfromthecontext.

Withregular functions thisalwaysreferstothenearestfunction,whilewitharrowfunctionsthisproblemisremoved,andyouwon'tneedtowrite varthat=thiseveragain.

PromisesPromises(checkthefullguidetopromises)allowustoeliminatethefamous"callbackhell",althoughtheyintroduceabitmorecomplexity(whichhasbeensolvedinES2017with async,ahigherlevelconstruct).

PromiseshavebeenusedbyJavaScriptdeveloperswellbeforeES2015,withmanydifferentlibrariesimplementations(e.g.jQuery,q,deferred.js,vow...),andthestandardputacommongroundacrossdifferences.

Byusingpromisesyoucanrewritethiscode

ES6

13

setTimeout(function(){

console.log('Ipromisedtorunafter1s')

setTimeout(function(){

console.log('Ipromisedtorunafter2s')

},1000)

},1000)

as

constwait=()=>newPromise((resolve,reject)=>{

setTimeout(resolve,1000)

})

wait().then(()=>{

console.log('Ipromisedtorunafter1s')

returnwait()

})

.then(()=>console.log('Ipromisedtorunafter2s'))

GeneratorsGeneratorsareaspecialkindoffunctionwiththeabilitytopauseitself,andresumelater,allowingothercodetoruninthemeantime.

Thecodedecidesthatithastowait,soitletsothercode"inthequeue"torun,andkeepstherighttoresumeitsoperations"whenthethingit'swaitingfor"isdone.

Allthisisdonewithasingle,simplekeyword: yield.Whenageneratorcontainsthatkeyword,theexecutionishalted.

Ageneratorcancontainmany yieldkeywords,thushaltingitselfmultipletimes,andit'sidentifiedbythe *functionkeyword,whichisnottobeconfusedwiththepointerdereferenceoperatorusedinlowerlevelprogramminglanguagessuchasC,C++orGo.

GeneratorsenablewholenewparadigmsofprogramminginJavaScript,allowing:

2-waycommunicationwhileageneratorisrunninglong-livedwhileloopswhichdonotfreezeyourprogram

Hereisanexampleofageneratorwhichexplainshowitallworks.

function*calculator(input){

vardoubleThat=2*(yield(input/2))

varanother=yield(doubleThat)

return(input*doubleThat*another)

}

ES6

14

Weinitializeitwith

constcalc=calculator(10)

Thenwestarttheiteratoronourgenerator:

calc.next()

Thisfirstiterationstartstheiterator.Thecodereturnsthisobject:

{

done:false

value:5

}

Whathappensis:thecoderunsthefunction,with input=10asitwaspassedinthegeneratorconstructor.Itrunsuntilitreachesthe yield,andreturnsthecontentof yield:input/2=5.Sowegotavalueof5,andtheindicationthattheiterationisnotdone(thefunctionisjustpaused).

Intheseconditerationwepassthevalue 7:

calc.next(7)

andwhatwegotbackis:

{

done:false

value:14

}

7wasplacedasthevalueof doubleThat.Important:youmightreadlike input/2wastheargument,butthat'sjustthereturnvalueofthefirstiteration.Wenowskipthat,andusethenewinputvalue, 7,andmultiplyitby2.

Wethenreachthesecondyield,andthatreturns doubleThat,sothereturnedvalueis 14.

Inthenext,andlast,iteration,wepassin100

calc.next(100)

andinreturnwegot

ES6

15

{

done:true

value:14000

}

Astheiterationisdone(nomoreyieldkeywordsfound)andwejustreturn (input*doubleThat*another)whichamountsto 10*14*100.

letand constvaristraditionallyfunctionscoped.

letisanewvariabledeclarationwhichisblockscoped.

Thismeansthatdeclaring letvariablesinaforloop,insideaniforinaplainblockisnotgoingtoletthatvariable"escape"theblock,while varsarehoisteduptothefunctiondefinition.

constisjustlike let,butimmutable.

InJavaScriptmovingforward,you'llseelittletono vardeclarationsanymore,just letandconst.

constinparticular,maybesurprisingly,isverywidelyusednowadayswithimmutabilitybeingverypopular.

ClassesTraditionallyJavaScriptistheonlymainstreamlanguagewithprototype-basedinheritance.ProgrammersswitchingtoJSfromclass-basedlanguagefounditpuzzling,butES2015introducedclasses,whicharejustsyntacticsugarovertheinnerworking,butchangedalothowwebuildJavaScriptprograms.

Nowinheritanceisveryeasyandresemblesotherobject-orientedprogramminglanguages:

classPerson{

constructor(name){

this.name=name

}

hello(){

return'Hello,Iam'+this.name+'.'

}

}

ES6

16

classActorextendsPerson{

hello(){

returnsuper.hello()+'Iamanactor.'

}

}

vartomCruise=newActor('TomCruise')

tomCruise.hello()

(theaboveprogramprints"Hello,IamTomCruise.Iamanactor.")

Classesdonothaveexplicitclassvariabledeclarations,butyoumustinitializeanyvariableintheconstructor.

Constructor

Classeshaveaspecialmethodcalled constructorwhichiscalledwhenaclassisinitializedvia new.

Super

Theparentclasscanbereferencedusing super().

Gettersandsetters

Agetterforapropertycanbedeclaredas

classPerson{

getfullName(){

return`${this.firstName}${this.lastName}`

}

}

Settersarewritteninthesameway:

classPerson{

setage(years){

this.theAge=years

}

}

Modules

ES6

17

BeforeES2015,therewereatleast3majormodulescompetingstandards,whichfragmentedthecommunity:

AMDRequireJSCommonJS

ES2015standardizedtheseintoacommonformat.

Importingmodules

Importingisdoneviathe import...from...construct:

import*from'mymodule'

importReactfrom'react'

import{React,Component}from'react'

importReactasMyLibraryfrom'react'

Exportingmodules

Youcanwritemodulesandexportanythingtoothermodulesusingthe exportkeyword:

exportvarfoo=2

exportfunctionbar(){/*...*/}

TemplateLiteralsTemplateliteralsareanewsyntaxtocreatestrings:

constaString=`Astring`

Theyprovideawaytoembedexpressionsintostrings,effectivelyinterpolatingthevalues,byusingthe ${a_variable}syntax:

constvar='test'

conststring=`something${var}`//somethingtest

Youcanperformmorecomplexexpressionsaswell:

conststring=`something${1+2+3}`

conststring2=`something${foo()?'x':'y'}`

ES6

18

andstringscanspanovermultiplelines:

conststring3=`Hey

this

string

isawesome!`

Comparehowweusedtodomultilinestringspre-ES2015:

varstr='One\n'+

'Two\n'+

'Three'

Seethispostforanin-depthguideontemplateliterals

DefaultparametersFunctionsnowsupportdefaultparameters:

constfoo=function(index=0,testing=true){/*...*/}

foo()

ThespreadoperatorYoucanexpandanarray,anobjectorastringusingthespreadoperator ....

Let'sstartwithanarrayexample.Given

consta=[1,2,3]

youcancreateanewarrayusing

constb=[...a,4,5,6]

Youcanalsocreateacopyofanarrayusing

constc=[...a]

Thisworksforobjectsaswell.Cloneanobjectwith:

ES6

19

constnewObj={...oldObj}

Usingstrings,thespreadoperatorcreatesanarraywitheachcharinthestring:

consthey='hey'

constarrayized=[...hey]//['h','e','y']

Thisoperatorhassomeprettyusefulapplications.Themostimportantoneistheabilitytouseanarrayasfunctionargumentinaverysimpleway:

constf=(foo,bar)=>{}

consta=[1,2]

f(...a)

(inthepastyoucoulddothisusing f.apply(null,a)butthat'snotasniceandreadable)

DestructuringassignmentsGivenanobject,youcanextractjustsomevaluesandputthemintonamedvariables:

constperson={

firstName:'Tom',

lastName:'Cruise',

actor:true,

age:54,//madeup

}

const{firstName:name,age}=person

nameand agecontainthedesiredvalues.

Thesyntaxalsoworksonarrays:

consta=[1,2,3,4,5]

[first,second,,,fifth]=a

EnhancedObjectLiteralsInES2015ObjectLiteralsgainedsuperpowers.

Simplersyntaxtoincludevariables

ES6

20

Insteadofdoing

constsomething='y'

constx={

something:something

}

youcando

constsomething='y'

constx={

something

}

Prototype

Aprototypecanbespecifiedwith

constanObject={y:'y'}

constx={

__proto__:anObject

}

super()

constanObject={y:'y',test:()=>'zoo'}

constx={

__proto__:anObject,

test(){

returnsuper.test()+'x'

}

}

x.test()//zoox

Dynamicproperties

constx={

['a'+'_'+'b']:'z'

}

x.a_b//z

For-ofloop

ES6

21

ES5backin2009introduced forEach()loops.Whilenice,theyofferednowaytobreak,likeforloopsalwaysdid.

ES2015introducedthe for-ofloop,whichcombinestheconcisenessof forEachwiththeabilitytobreak:

//iterateoverthevalue

for(constvof['a','b','c']){

console.log(v);

}

//gettheindexaswell,using`entries()`

for(const[i,v]of['a','b','c'].entries()){

console.log(i,v);

}

MapandSetMapandSet(andtheirrespectivegarbagecollectedWeakMapandWeakSet)aretheofficialimplementationsoftwoverypopulardatastructures.

ES6

22

ES2016ECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.DiscovereverythingaboutECMAScript,andthelastfeaturesaddedinES2016,akaES7

ES7,officiallyknownasECMAScript2016,wasfinalizedinJune2016.

ComparedtoES6,ES7isatinyreleaseforJavaScript,containingjusttwofeatures:

Array.prototype.includesExponentiationOperator

Array.prototype.includes()Thisfeatureintroducesamorereadablesyntaxforcheckingifanarraycontainsanelement.

WithES6andlower,tocheckifanarraycontainedanelementyouhadtouse indexOf,whichcheckstheindexinthearray,andreturns -1iftheelementisnotthere.

Since -1isevaluatedasatruevalue,youcouldnotdoforexample

if(![1,2].indexOf(3)){

console.log('Notfound')

}

WiththisfeatureintroducedinES7wecando

if(![1,2].includes(3)){

console.log('Notfound')

}

ExponentiationOperatorTheexponentiationoperator **istheequivalentof Math.pow(),butbroughtintothelanguageinsteadofbeingalibraryfunction.

Math.pow(4,2)==4**2

ThisfeatureisaniceadditionformathintensiveJSapplications.

ES2016

23

The **operatorisstandardizedacrossmanylanguagesincludingPython,Ruby,MATLAB,Lua,Perlandmanyothers.

ES2016

24

ES2017ECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.DiscovereverythingaboutECMAScript,andthelastfeaturesaddedinES2017,akaES8

ECMAScript2017,edition8oftheECMA-262Standard(alsocommonlycalledES2017orES8),wasfinalizedinJune2017.

ComparedtoES6,ES8isatinyreleaseforJavaScript,butstillitintroducesveryusefulfeatures:

StringpaddingObject.valuesObject.entriesObject.getOwnPropertyDescriptors()TrailingcommasinfunctionparameterlistsandcallsAsyncfunctionsSharedmemoryandatomics

StringpaddingThepurposeofstringpaddingistoaddcharacterstoastring,soitreachesaspecificlength.

ES2017introducestwo Stringmethods: padStart()and padEnd().

padStart(targetLength[,padString])

padEnd(targetLength[,padString])

Sampleusage:

padStart()

'test'.padStart(4) 'test'

'test'.padStart(5) '_test'

'test'.padStart(8) '____test'

'test'.padStart(8,'abcd') 'abcdtest'

padEnd()

'test'.padEnd(4) 'test'

ES2017

25

'test'.padEnd(5) 'test_'

'test'.padEnd(8) 'test____'

'test'.padEnd(8,'abcd') 'testabcd'

(inthetable,_=space)

Object.values()Thismethodreturnsanarraycontainingalltheobjectownpropertyvalues.

Usage:

constperson={name:'Fred',age:87}

Object.values(person)//['Fred',87]

Object.values()alsoworkswitharrays:

constpeople=['Fred','Tony']

Object.values(people)//['Fred','Tony']

Object.entries()Thismethodreturnsanarraycontainingalltheobjectownproperties,asanarrayof [key,value]pairs.

Usage:

constperson={name:'Fred',age:87}

Object.entries(person)//[['name','Fred'],['age',87]]

Object.entries()alsoworkswitharrays:

constpeople=['Fred','Tony']

Object.entries(people)//[['0','Fred'],['1','Tony']]

getOwnPropertyDescriptors()Thismethodreturnsallown(non-inherited)propertiesdescriptorsofanobject.

AnyobjectinJavaScripthasasetofproperties,andeachofthesepropertieshasadescriptor.

ES2017

26

Adescriptorisasetofattributesofaproperty,andit'scomposedbyasubsetofthefollowing:

value:thevalueofthepropertywritable:truethepropertycanbechangedget:agetterfunctionfortheproperty,calledwhenthepropertyisreadset:asetterfunctionfortheproperty,calledwhenthepropertyissettoavalueconfigurable:iffalse,thepropertycannotberemovednoranyattributecanbechanged,exceptitsvalueenumerable:trueifthepropertyisenumerable

Object.getOwnPropertyDescriptors(obj)acceptsanobject,andreturnsanobjectwiththesetofdescriptors.

Inwhatwayisthisuseful?

ES2015gaveus Object.assign(),whichcopiesallenumerableownpropertiesfromoneormoreobjects,andreturnanewobject.

Howeverthereisaproblemwiththat,becauseitdoesnotcorrectlycopiespropertieswithnon-defaultattributes.

Ifanobjectforexamplehasjustasetter,it'snotcorrectlycopiedtoanewobject,usingObject.assign().

Forexamplewith

constperson1={

setname(newName){

console.log(newName)

}

}

Thiswon'twork:

constperson2={}

Object.assign(person2,person1)

Butthiswillwork:

constperson3={}

Object.defineProperties(person3,Object.getOwnPropertyDescriptors(person1))

Asyoucanseewithasimpleconsoletest:

person1.name='x'

ES2017

27

;('x')

person2.name='x'

person3.name='x'

;('x')

person2missesthesetter,itwasnotcopiedover.

ThesamelimitationgoesforshallowcloningobjectswithObject.create().

TrailingcommasThisfeatureallowstohavetrailingcommasinfunctiondeclarations,andinfunctionscalls:

constdoSomething=(var1,var2)=>{

//...

}

doSomething('test2','test2')

Thischangewillencouragedeveloperstostoptheugly"commaatthestartoftheline"habit.

AsyncfunctionsCheckthededicatedpostaboutasync/await

ES2017introducedtheconceptofasyncfunctions,andit'sthemostimportantchangeintroducedinthisECMAScriptedition.

Asyncfunctionsareacombinationofpromisesandgeneratorstoreducetheboilerplatearoundpromises,andthe"don'tbreakthechain"limitationofchainingpromises.

Whytheyareuseful

It'sahigherlevelabstractionoverpromises.

WhenPromiseswereintroducedinES2015,theyweremeanttosolveaproblemwithasynchronouscode,andtheydid,butoverthe2yearsthatseparatedES2015andES2017,itwasclearthatpromisescouldnotbethefinalsolution.Promiseswereintroducedtosolvethefamouscallbackhellproblem,buttheyintroducedcomplexityontheirown,andsyntaxcomplexity.Theyweregoodprimitivesaroundwhichabettersyntaxcouldbeexposedtothedevelopers:enterasyncfunctions.

ES2017

28

Aquickexample

Codemakinguseofasynchronousfunctionscanbewrittenas

functiondoSomethingAsync(){

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

}

asyncfunctiondoSomething(){

console.log(awaitdoSomethingAsync())

}

console.log('Before')

doSomething()

console.log('After')

Theabovecodewillprintthefollowingtothebrowserconsole:

Before

After

Ididsomething//after3s

Multipleasyncfunctionsinseries

Asyncfunctionscanbechainedveryeasily,andthesyntaxismuchmorereadablethanwithplainpromises:

functionpromiseToDoSomething(){

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),10000)

})

}

asyncfunctionwatchOverSomeoneDoingSomething(){

constsomething=awaitpromiseToDoSomething()

returnsomething+'andIwatched'

}

asyncfunctionwatchOverSomeoneWatchingSomeoneDoingSomething(){

constsomething=awaitwatchOverSomeoneDoingSomething()

returnsomething+'andIwatchedaswell'

}

watchOverSomeoneWatchingSomeoneDoingSomething().then(res=>{

console.log(res)

})

ES2017

29

SharedMemoryandAtomicsWebWorkersareusedtocreatemultithreadedprogramsinthebrowser.

Theyofferamessagingprotocolviaevents.SinceES2017,youcancreateasharedmemoryarraybetweenwebworkersandtheircreator,usinga SharedArrayBuffer.

Sinceit'sunknownhowmuchtimewritingtoasharedmemoryportiontakestopropagate,Atomicsareawaytoenforcethatwhenreadingavalue,anykindofwritingoperationiscompleted.

Anymoredetailonthiscanbefoundinthespecproposal,whichhassincebeenimplemented.

ES2017

30

ES2018ECMAScriptisthestandarduponwhichJavaScriptisbased,andit'softenabbreviatedtoES.DiscovereverythingaboutECMAScript,andthelastfeaturesaddedinES2018,akaES9

ES2018isthelatestversionoftheECMAScriptstandard.

Whatarethenewthingsintroducedinit?

Rest/SpreadPropertiesES6introducedtheconceptofarestelementwhenworkingwitharraydestructuring:

constnumbers=[1,2,3,4,5]

[first,second,...others]=numbers

andspreadelements:

constnumbers=[1,2,3,4,5]

constsum=(a,b,c,d,e)=>a+b+c+d+e

constsum=sum(...numbers)

ES2018introducesthesamebutforobjects.

Restproperties:

const{first,second,...others}={first:1,second:2,third:3,fourth:4,fifth:5

}

first//1

second//2

others//{third:3,fourth:4,fifth:5}

Spreadpropertiesallowtocreateanewobjectbycombiningthepropertiesoftheobjectpassedafterthespreadoperator:

constitems={first,second,...others}

items//{first:1,second:2,third:3,fourth:4,fifth:5}

Asynchronousiteration

ES2018

31

Thenewconstruct for-await-ofallowsyoutouseanasynciterableobjectastheloopiteration:

forawait(constlineofreadLines(filePath)){

console.log(line)

}

Sincethisuses await,youcanuseitonlyinside asyncfunctions,likeanormal await(seeasync/await)

Promise.prototype.finally()Whenapromiseisfulfilled,successfullyitcallsthe then()methods,oneafteranother.

Ifsomethingfailsduringthis,the then()methodsarejumpedandthe catch()methodisexecuted.

finally()allowyoutorunsomecoderegardlessofthesuccessfulornotsuccessfulexecutionofthepromise:

fetch('file.json')

.then(data=>data.json())

.catch(error=>console.error(error))

.finally(()=>console.log('finished'))

RegularExpressionimprovements

RegExplookbehindassertions:matchastringdependingonwhatprecedesit

Thisisalookahead:youuse ?=tomatchastringthat'sfollowedbyaspecificsubstring:

/Roger(?=Waters)/

/Roger(?=Waters)/.test('Rogerismydog')//false

/Roger(?=Waters)/.test('RogerismydogandRogerWatersisafamousmusician')//true

?!performstheinverseoperation,matchingifastringisnotfollowedbyaspecificsubstring:

/Roger(?!Waters)/

/Roger(?!Waters)/.test('Rogerismydog')//true

/Roger(?!Waters)/.test('RogerWatersisafamousmusician')//false

ES2018

32

Lookaheadsusethe ?=symbol.Theywerealreadyavailable.

Lookbehinds,anewfeature,uses ?<=.

/(?<=Roger)Waters/

/(?<=Roger)Waters/.test('PinkWatersismydog')//false

/(?<=Roger)Waters/.test('RogerismydogandRogerWatersisafamousmusician')//true

Alookbehindisnegatedusing ?<!:

/(?<!Roger)Waters/

/(?<!Roger)Waters/.test('PinkWatersismydog')//true

/(?<!Roger)Waters/.test('RogerismydogandRogerWatersisafamousmusician')//false

Unicodepropertyescapes \p{…}and \P{…}

Inaregularexpressionpatternyoucanuse \dtomatchanydigit, \stomatchanycharacterthat'snotawhitespace, \wtomatchanyalphanumericcharacter,andsoon.

ThisnewfeatureextendsthisconcepttoallUnicodecharactersintroducing \p{}andisnegation \P{}.

Anyunicodecharacterhasasetofproperties.Forexample Scriptdeterminesthelanguagefamily, ASCIIisabooleanthat'strueforASCIIcharacters,andsoon.Youcanputthispropertyinthegraphparentheses,andtheregexwillcheckforthattobetrue:

/^\p{ASCII}+$/u.test('abc')//✅

/^\p{ASCII}+$/u.test('ABC@')//✅

/^\p{ASCII}+$/u.test('ABC ')//❌

ASCII_Hex_Digitisanotherbooleanproperty,thatchecksifthestringonlycontainsvalidhexadecimaldigits:

/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF')//✅

/^\p{ASCII_Hex_Digit}+$/u.test('h')//❌

Therearemanyotherbooleanproperties,whichyoujustcheckbyaddingtheirnameinthegraphparentheses,including Uppercase, Lowercase, White_Space, Alphabetic, Emojiandmore:

/^\p{Lowercase}$/u.test('h')//✅

/^\p{Uppercase}$/u.test('H')//✅

ES2018

33

/^\p{Emoji}+$/u.test('H')//❌

/^\p{Emoji}+$/u.test(' ')//✅

Inadditiontothosebinaryproperties,youcancheckanyoftheunicodecharacterpropertiestomatchaspecificvalue.Inthisexample,Icheckifthestringiswritteninthegreekorlatinalphabet:

/^\p{Script=Greek}+$/u.test('ελληνικά')//✅

/^\p{Script=Latin}+$/u.test('hey')//✅

Readmoreaboutallthepropertiesyoucanusedirectlyontheproposal.

Namedcapturinggroups

InES2018acapturinggroupcanbeassignedtoaname,ratherthanjustbeingassignedaslotintheresultarray:

constre=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/

constresult=re.exec('2015-01-02')

//result.groups.year==='2015';

//result.groups.month==='01';

//result.groups.day==='02';

The sflagforregularexpressions

The sflag,shortforsingleline,causesthe .tomatchnewlinecharactersaswell.Withoutit,thedotmatchesregularcharactersbutnotthenewline:

/hi.welcome/.test('hi\nwelcome')//false

/hi.welcome/s.test('hi\nwelcome')//true

ES2018

34

CodingstyleThisJavaScriptCodingStyleisthesetofconventionsIuseeverydaywhenusingJavaScript.It'salivedocument,withthemainsetofrulesIfollow

Acodingstyleisanagreementwithyourselfandyourteam,tokeepconsistencyonaproject.

Anifyoudon'thaveateam,it'sanagreementwithyou,toalwayskeepyourcodeuptoyourstandards.

Havingfixedrulesonyourcodewritingformathelpsalotinordertohaveamorereadableandmanagedcode.

PopularStyleGuidesThereareaquiteafewofthemaround,herearethe2mostcommononesintheJavaScriptworld:

TheGoogleJavaScriptStyleGuideTheAirBnbJavaScriptStyleGuide

It'suptoyoutofollowoneofthose,orcreateyourownstyleguide.

BeconsistentwiththeprojectyouworkonEvenifyoupreferasetofstyles,whenworkingonaprojectyoushouldusethatprojectstyle.

AnOpenSourceprojectonGitHubmightfollowasetofrules,anotherprojectyouworkonwithateammightfollowanentirelydifferentone.

Prettierisanawesometoolthatenforcescodeformatting,useit.

MyownpreferencesMyowntakeonJavaScriptstyleis:

AlwaysusethelatestESversion.UseBabelifoldbrowsersupportisnecessary.

Indentation:usespacesinsteadoftabs,indentusing2spaces.

Semicolons:don'tusesemicolons.

Codingstyle

35

Linelength:trytocutlinesat80chars,ifpossible.

InlineComments:useinlinecommentsinyourcode.Useblockcommentsonlytodocument.

Nodeadcode:Don'tleaveoldcodecommented,"justincase"itwillbeusefullater.Keeponlythecodeyouneednow,versioncontrol/yournotesappismeantforthis.

Onlycommentwhenuseful:Don'taddcommentsthatdon'thelpunderstandwhatthecodeisdoing.Ifthecodeisself-explainingthroughtheuseofgoodvariableandfunctionnaming,andJSDocfunctioncomments,don'taddacomment.

Variabledeclarations:alwaysdeclarevariablestoavoidpollutingtheglobalobject.Neveruse var.Defaultto const,onlyuse letifyoureassignthevariable.

Constants:declareallconstantsinCAPS.Use _toseparatewordsina VARIABLE_NAME.

Functions:usearrowfunctionsunlessyouhaveaspecificreasontouseregularfunctions,likeinobjectmethodsorconstructors,duetohow thisworks.Declarethemasconst,anduseimplicitreturnsifpossible.

consttest=(a,b)=>a+b

constanother=a=>a+2

Feelfreetousenestedfunctionstohidehelperfunctionstotherestofthecode.

Names:functionnames,variablenamesandmethodnamesalwaysstartwithalowercaseletter(unlessyouidentifythemasprivate,readbelow),andarecamelCased.Onlyconstructorfunctionsandclassnamesshouldstartcapitalized.Ifyouuseaframeworkthatrequiresspecificconventions,changeyourhabitsaccordingly.Filenamesshouldallbelowercase,withwordsseparatedby -.

Statement-specificformatsandrules:

if

if(condition){

statements

}

if(condition){

statements

}else{

statements

}

if(condition){

statements

}elseif(condition){

Codingstyle

36

statements

}else{

statements

}

for

Alwaysinitializethelengthintheinitializationtocacheit,don'tinsertitinthecondition.

Avoidusing forinexceptwithusedinconjunctionwith .hasOwnProperty().Prefer forof(seeJavaScriptLoops)

for(initialization;condition;update){

statements

}

while

while(condition){

statements

}

do

do{

statements

}while(condition);

switch

switch(expression){

caseexpression:

statements

default:

statements

}

try

try{

statements

}catch(variable){

statements

}

try{

statements

}catch(variable){

Codingstyle

37

statements

}finally{

statements

}

Whitespace:usewhitespacewiselytoimprovereadability:putawhitespaceafterakeywordfollowedbya (;before&afterabinaryoperation( +, -, /, *, &&..);insidetheforstatement,aftereach ;toseparateeachpartofthestatement;aftereach ,.

Newlines:usenewlinestoseparateblocksofcodethatperformlogicallyrelatedoperations.

Quotesfavorsinglequotes 'insteadofdoublequotes ".DoublequotesareastandardinHTMLattributes,sousingsinglequoteshelpsremoveproblemswhendealingwithHTMLstrings.Usetemplateliteralswhenappropriateinsteadofvariableinterpolation.

Codingstyle

38

LexicalStructureAdeepdiveintothebuildingblocksofJavaScript:unicode,semicolons,whitespace,casesensitivity,comments,literals,identifiersandreservedwords

UnicodeJavaScriptiswritteninUnicode.ThismeansyoucanuseEmojisasvariablenames,butmoreimportantly,youcanwriteidentifiersinanylanguage,forexampleJapaneseorChinese,withsomerules.

SemicolonsJavaScripthasaveryC-likesyntax,andyoumightseelotsofcodesamplesthatfeaturesemicolonsattheendofeachline.

Semicolonsaren'tmandatory,andJavaScriptdoesnothaveanyproblemincodethatdoesnotusethem,andlatelymanydevelopers,especiallythosecomingfromlanguagesthatdonothavesemicolons,startedavoidingusingthem.

Youjustneedtoavoiddoingstrangethingsliketypingstatementsonmultiplelines

return

variable

orstartingalinewithparentheses( [or ()andyou'llbesafe99.9%ofthetimes(andyourlinterwillwarnyou).

Itgoestopersonalpreference,andlatelyIhavedecidedtoneveradduselesssemicolons,soonthissiteyou'llneverseethem.

WhitespaceJavaScriptdoesnotconsiderwhitespacemeaningful.Spacesandlinebreakscanbeaddedinanyfashionyoumightlike,eventhoughthisisintheory.

Inpractice,youwillmostlikelykeepawelldefinedstyleandadheretowhatpeoplecommonlyuse,andenforcethisusingalinterorastyletoolsuchasPrettier.

LexicalStructure

39

ForexampleIliketoalways2characterstoindent.

CasesensitiveJavaScriptiscasesensitive.Avariablenamed somethingisdifferentfrom Something.

Thesamegoesforanyidentifier.

CommentsYoucanusetwokindofcommentsinJavaScript:

/**/

//

Thefirstcanspanovermultiplelinesandneedstobeclosed.

Thesecondcommentseverythingthat'sonitsright,onthecurrentline.

LiteralsandIdentifiersWedefineasliteralavaluethatiswritteninthesourcecode,forexampleanumber,astring,abooleanoralsomoreadvancedconstructs,likeObjectLiteralsorArrayLiterals:

5

'Test'

true

['a','b']

{color:'red',shape:'Rectangle'}

Anidentifierisasequenceofcharactersthatcanbeusedtoidentifyavariable,afunction,anobject.Itcanstartwithaletter,thedollarsign $oranunderscore _,anditcancontaindigits.UsingUnicode,alettercanbeanyallowedchar,forexampleanemoji .

Test

test

TEST

_test

Test1

$test

LexicalStructure

40

ThedollarsigniscommonlyusedtoreferenceDOMelements.

ReservedwordsYoucan'tuseasidentifiersanyofthefollowingwords:

break

do

instanceof

typeof

case

else

new

var

catch

finally

return

void

continue

for

switch

while

debugger

function

this

with

default

if

throw

delete

in

try

class

enum

extends

super

const

export

import

implements

let

private

public

interface

package

protected

static

yield

becausetheyarereservedbythelanguage.

LexicalStructure

41

LexicalStructure

42

VariablesAvariableisaliteralassignedtoanidentifier,soyoucanreferenceanduseitlaterintheprogram.LearnhowtodeclareonewithJavaScript

IntroductiontoJavaScriptVariablesAvariableisaliteralassignedtoanidentifier,soyoucanreferenceanduseitlaterintheprogram.

VariablesinJavaScriptdonothaveanytypeattached.Onceyouassignaspecificliteraltypetoavariable,youcanlaterreassignthevariabletohostanyothertype,withouttypeerrorsoranyissue.

ThisiswhyJavaScriptissometimesreferencedas"untyped".

Avariablemustbedeclaredbeforeyoucanuseit.Thereare3waystodoit,using var, letor const,andthose3waysdifferinhowyoucaninteractwiththevariablelateron.

Using varUntilES2015, varwastheonlyconstructavailablefordefiningvariables.

vara=0

Ifyouforgettoadd varyouwillbeassigningavaluetoanundeclaredvariable,andtheresultsmightvary.

Inmodernenvironments,withstrictmodeenabled,youwillgetanerror.Inolderenvironments(orwithstrictmodedisabled)thiswillsimplyinitializethevariableandassignittotheglobalobject.

Ifyoudon'tinitializethevariablewhenyoudeclareit,itwillhavethe undefinedvalueuntilyouassignavaluetoit.

vara//typeofa==='undefined'

Youcanredeclarethevariablemanytimes,overridingit:

vara=1

Variables

43

vara=2

Youcanalsodeclaremultiplevariablesatonceinthesamestatement:

vara=1,b=2

Thescopeistheportionofcodewherethevariableisvisible.

Avariableinitializedwith varoutsideofanyfunctionisassignedtotheglobalobject,hasaglobalscopeandisvisibleeverywhere.Avariableinitializedwith varinsideafunctionisassignedtothatfunction,it'slocalandisvisibleonlyinsideit,justlikeafunctionparameter.

Anyvariabledefinedintoafunctionwiththesamenameofaglobalvariabletakesprecedenceovertheglobalvariable,shadowingit.

It'simportanttounderstandthatablock(identifiedbyapairofcurlybraces)doesnotdefineanewscope.Anewscopeisonlycreatedwhenafunctioniscreated,because varhasnotblockscope,butfunctionscope.

Insideafunction,anyvariabledefinedinitisvisiblethroughoutallthefunctioncode,evenifthevariableisdeclaredattheendofthefunctionitcanstillbereferencedinthebeginning,becauseJavaScriptbeforeexecutingthecodeactuallymovesallvariablesontop(somethingthatiscalledhoisting).Toavoidconfusion,alwaysdeclarevariablesatthebeginningofafunction.

Using letletisanewfeatureintroducedinES2015andit'sessentiallyablockscopedversionofvar.Itsscopeislimitedtotheblock,statementorexpressionwhereit'sdefined,andallthecontainedinnerblocks.

ModernJavaScriptdevelopersmightchoosetoonlyuse letandcompletelydiscardtheuseof var.

If letseemsanobscureterm,justread letcolor='red'asletthecolorberedandallhasmuchmoresense

Defining letoutsideofanyfunction-contraryto var-doesnotcreateaglobalvariable.

Using const

Variables

44

Variablesdeclaredwith varor letcanbechangedlateronintheprogram,andreassigned.Aoncea constisinitialized,itsvaluecanneverbechangedagain,anditcan'tbereassignedtoadifferentvalue.

consta='test'

Wecan'tassignadifferentliteraltothe aconst.Wecanhowevermutate aifit'sanobjectthatprovidesmethodsthatmutateitscontents.

constdoesnotprovideimmutability,justmakessurethatthereferencecan'tbechanged.

consthasblockscope,sameas let.

ModernJavaScriptdevelopersmightchoosetoalwaysuse constforvariablesthatdon'tneedtobereassignedlaterintheprogram.

Why?Becauseweshouldalwaysusethesimplestconstructavailabletoavoidmakingerrorsdowntheroad.

Variables

45

TypesYoumightsometimesreadthatJSisuntyped,butthat'sincorrect.It'struethatyoucanassignallsortsofdifferenttypestoavariable,butJavaScripthastypes.Inparticular,itprovidesprimitivetypes,andobjecttypes.

PrimitivetypesPrimitivetypesare

NumbersStringsBooleans

Andtwospecialtypes:

nullundefined

Let'sseethemindetailinthenextsections.

NumbersInternally,JavaScripthasjustonetypefornumbers:everynumberisafloat.

Anumericliteralisanumberrepresentedinthesourcecode,amddependingonhowit'swritten,itcanbeanintegerliteralorafloatingpointliteral.

Integers:

10

5354576767321

0xCC//hex

Floats:

3.14

.1234

5.2e4//5.2*10^4

Strings

Types

46

Astringtypeisasequenceofcharacters.It'sdefinedinthesourcecodeasastringliteral,whichisenclosedinquotesordoublequotes

'Astring'

"Anotherstring"

Stringscanspanacrossmultiplelinesbyusingthebackslash

"A\

string"

Astringcancontainescapesequencesthatcanbeinterpretedwhenthestringisprinted,like\ntocreateanewline.Thebackslashisalsousefulwhenyouneedtoenterforexampleaquoteinastringenclosedinquotes,topreventthechartobeinterpretedasaclosingquote:

'I\'madeveloper'

Stringscanbejoinedusingthe+operator:

"A"+"string"

Templatestrings

IntroducedinES2015,templatestringsarestringliteralsthatallowamorepowerfulwaytodefinestrings.

`astring`

Youcanperformstringsubstitution,embeddingtheresultofanyJSexpression:

`astringwith${something}`

`astringwith${something+somethingElse}`

`astringwith${obj.something()}`

Youcanhavemultilinestringseasily:

`astring

with

${something}`

Booleans

Types

47

JavaScriptdefinestworeservedwordsforbooleans:trueandfalse.Manycomparisionoperations == === < >(andsoon)returneitheroneortheother.

if, whilestatementsandothercontrolstructuresusebooleanstodeterminetheflowoftheprogram.

Theydon'tjustaccepttrueorfalse,butalsoaccepttruthyandfalsyvalues.

Falsyvalues,valuesinterpretedasfalse,are

0

-0

NaN

undefined

null

''//emptystring

Alltherestisconsideredatruthyvalue.

nullnullisaspecialvaluethatindicatestheabsenceofavalue.

It'sacommonconceptinotherlanguagesaswell,canbeknownas nilor NoneinPythonforexample.

undefinedundefinedindicatesthatavariablehasnotbeeninitializedandthevalueisabsent.

It'scommonlyreturnedbyfunctionswithno returnvalue.Whenafunctionacceptsaparameterbutthat'snotsetbythecaller,it'sundefined.

Todetectifavalueis undefined,youusetheconstruct:

typeofvariable==='undefined'

ObjecttypesAnythingthat'snotaprimitivetypeisanobjecttype.

Types

48

Functions,arraysandwhatwecallobjectsareobjecttypes.Theyarespecialontheirown,buttheyinheritmanypropertiesofobjects,likehavingpropertiesandalsohavingmethodsthatcanactonthoseproperties.

Types

49

ExpressionsExpressionsareunitsofcodethatcanbeevaluatedandresolvetoavalue.ExpressionsinJScanbedividedincategories.

ArithmeticexpressionsUnderthiscategorygoallexpressionsthatevaluatetoanumber:

1/2

i++

i-=2

i*2

StringexpressionsExpressionsthatevaluatetoastring:

'A'+'string'

'A'+='string'

PrimaryexpressionsUnderthiscategorygovariablereferences,literalsandconstants:

2

0.02

'something'

true

false

this//thecurrentobject

undefined

i//whereiisavariableoraconstant

butalsosomelanguagekeywords:

function

class

function*//thegeneratorfunction

yield//thegeneratorpauser/resumer

yield*//delegatetoanothergeneratororiterator

Expressions

50

asyncfunction*//asyncfunctionexpression

await//asyncfunctionpause/resume/waitforcompletion

/pattern/i//regex

()//grouping

Arrayandobjectinitializersexpressions

[]//arrayliteral

{}//objectliteral

[1,2,3]

{a:1,b:2}

{a:{b:1}}

LogicalexpressionsLogicalexpressionsmakeuseoflogicaloperatorsandresolvetoabooleanvalue:

a&&b

a||b

!a

Left-hand-sideexpressions

new//createaninstanceofaconstructor

super//callstheparentconstructor

...obj//expressionusingthespreadoperator

Propertyaccessexpressions

object.property//referenceaproperty(ormethod)ofanobject

object[property]

object['property']

Objectcreationexpressions

newobject()

newa(1)

newMyRectangle('name',2,{a:4})

Expressions

51

Functiondefinitionexpressions

function(){}

function(a,b){returna*b}

(a,b)=>a*b

a=>a*2

()=>{return2}

InvocationexpressionsThesyntaxforcallingafunctionormethod

a.x(2)

window.resize()

Expressions

52

PrototypalinheritanceJavaScriptisquiteuniqueinthepopularprogramminglanguageslandscapebecauseofitsusageofprototypalinheritance.Let'sfindoutwhatthatmeans

JavaScriptisquiteuniqueinthepopularprogramminglanguageslandscapebecauseofitsusageofprototypalinheritance.

Whilemostobject-orientedlanguagesuseaclass-basedinheritancemodel,JavaScriptisbasedontheprototypeinheritancemodel.

Whatdoesthismean?

EverysingleJavaScriptobjecthasaproperty,called prototype,whichpointstoadifferentobject.

Thisdifferentobjectistheobjectprototype.

Ourobjectusesthatobjectprototypetoinheritpropertiesandmethods.

Sayyouhaveanobjectcreatedusingtheobjectliteralsyntax:

constcar={}

oronecreatedwiththe newObjectsyntax:

constcar=newObject()

inanycase,theprototypeof caris Object:

Ifyouinitializeanarray,whichisanobject:

constlist=[]

//or

constlist=newArray()

theprototypeis Array.

Youcanverifythisbycheckingthe __proto__getter:

car.__proto__==Object.prototype//true

car.__proto__==newObject().__proto__//true

list.__proto__==Object.prototype//false

list.__proto__==Array.prototype//true

list.__proto__==newArray().__proto__//true

Prototypalinheritance

53

Iusethe __proto__propertyhere,whichisnon-standardbutwidelyimplementedinbrowsers.Amorereliablewaytogetaprototypeistouse Object.getPrototypeOf(newObject())

Allthepropertiesandmethodsoftheprototypeareavailabletotheobjectthathasthatprototype:

Object.prototypeisthebaseprototypeofalltheobjects:

Array.prototype.__proto__==Object.prototype

Ifyouwonderwhat'stheprototypeoftheObject.prototype,thereisnoprototype.It'saspecialsnowflake❄ .

Theaboveexampleyousawisanexampleoftheprototypechainatwork.

IcanmakeanobjectthatextendsArrayandanyobjectIinstantiateusingit,willhaveArrayandObjectinitsprototypechainandinheritpropertiesandmethodsfromalltheancestors.

Inadditiontousingthe newoperatortocreateanobject,orusingtheliteralssyntaxforobjectsandarrays,youcaninstantiateanobjectusing Object.create().

Thefirstargumentpassedistheobjectusedasprototype:

Prototypalinheritance

54

constcar=Object.create({})

constlist=Object.create(Array)

Youcanchecktheprototypeofanobjectusingthe isPrototypeOf()method:

Array.isPrototypeOf(list)//true

Payattentionbecauseyoucaninstantiateanarrayusing

constlist=Object.create(Array.prototype)

andinthiscase Array.isPrototypeOf(list)isfalse,whileArray.prototype.isPrototypeOf(list)istrue.

Prototypalinheritance

55

ClassesIn2015theECMAScript6(ES6)standardintroducedclasses.Learnallaboutthem

In2015theECMAScript6(ES6)standardintroducedclasses.

Beforethat,JavaScriptonlyhadaquiteuniquewaytoimplementinheritance.Itsprototypalinheritance,whileinmyopiniongreat,wasdifferentfromanyotherpopularprogramminglanguage.

PeoplecomingfromJavaorPythonorotherlanguageshadahardtimeunderstandingtheintricaciesofprototypalinheritance,sotheECMAScriptcommitteedecidedtointroduceasyntacticsugarontopofthem,andresemblehowclasses-basedinheritanceworksinotherpopularimplementations.

Thisisimportant:JavaScriptunderthehoodsisstillthesame,andyoucanaccessanobjectprototypeintheusualway.

AclassdefinitionThisishowaclasslooks.

classPerson{

constructor(name){

this.name=name

}

hello(){

return'Hello,Iam'+this.name+'.'

}

}

Aclasshasanidentifier,whichwecanusetocreatenewobjectsusing newClassIdentifier().

Whentheobjectisinitialized,the constructormethodiscalled,withanyparameterspassed.

Aclassalsohasasmanymethodsasitneeds.Inthiscase helloisamethodandcanbecalledonallobjectsderivedfromthisclass:

constflavio=newPerson('Flavio')

flavio.hello()

Classes

56

ClassesinheritanceAclasscanextendanotherclass,andobjectsinitializedusingthatclassinheritallthemethodsofbothclasses.

Iftheinheritedclasshasamethodwiththesamenameasoneoftheclasseshigherinthehierarchy,theclosestmethodtakesprecedence:

classProgrammerextendsPerson{

hello(){

returnsuper.hello()+'Iamaprogrammer.'

}

}

constflavio=newProgrammer('Flavio')

flavio.hello()

(theaboveprogramprints"Hello,IamFlavio.Iamaprogrammer.")

Classesdonothaveexplicitclassvariabledeclarations,butyoumustinitializeanyvariableintheconstructor.

Insideaclass,youcanreferencetheparentclasscalling super().

StaticmethodsNormallymethodsaredefinedontheinstance,notontheclass.

Staticmethodsareexecutedontheclassinstead:

classPerson{

staticgenericHello(){

return'Hello'

}

}

Person.genericHello()//Hello

PrivatemethodsJavaScriptdoesnothaveabuilt-inwaytodefineprivateorprotectedmethods.

Thereareworkarounds,butIwon'tdescribethemhere.

Classes

57

GettersandsettersYoucanaddmethodsprefixedwith getor settocreateagetterandsetter,whicharetwodifferentpiecesofcodethatareexecutebasedonwhatyouaredoing:accessingthevariable,ormodifyingitsvalue.

classPerson{

constructor(name){

this.name=name

}

setname(value){

this.name=value

}

getname(){

returnthis.name

}

}

Ifyouonlyhaveagetter,thepropertycannotbeset,andanyattemptatdoingsowillbeignored:

classPerson{

constructor(name){

this.name=name

}

getname(){

returnthis.name

}

}

Ifyouonlyhaveasetter,youcanchangethevaluebutnotaccessitfromtheoutside:

classPerson{

constructor(name){

this.name=name

}

setname(value){

this.name=value

}

}

Classes

58

Classes

59

ExceptionsWhenthecoderunsintoanunexpectedproblem,theJavaScriptidiomaticwaytohandlethissituationisthroughexceptions

Whenthecoderunsintoanunexpectedproblem,theJavaScriptidiomaticwaytohandlethissituationisthroughexceptions.

CreatingexceptionsAnexceptioniscreatedusingthe throwkeyword:

throwvalue

where valuecanbeanyJavaScriptvalueincludingastring,anumberoranobject.

AssoonasJavaScriptexecutesthisline,thenormalprogramflowishaltedandthecontrolisheldbacktothenearestexceptionhandler.

HandlingexceptionsAnexceptionhandlerisa try/ catchstatement.

Anyexceptionraisedinthelinesofcodeincludedinthe tryblockishandledinthecorresponding catchblock:

try{

//linesofcode

}catch(e){

}

einthisexampleistheexceptionvalue.

Youcanaddmultiplehandlers,thatcancatchdifferentkindsoferrors.

finally

Exceptions

60

TocompletethisstatementJavaScripthasanotherstatementcalled finally,whichcontainscodethatisexecutedregardlessoftheprogramflow,iftheexceptionwashandledornot,iftherewasanexceptionoriftherewasn't:

try{

//linesofcode

}catch(e){

}finally{

}

Youcanuse finallywithouta catchblock,toserveasawaytocleanupanyresourceyoumighthaveopenedinthe tryblock,likefilesornetworkrequests:

try{

//linesofcode

}finally{

}

Nested tryblockstryblockscanbenested,andanexceptionisalwayshandledinthenearestcatchblock:

try{

//linesofcode

try{

//otherlinesofcode

}finally{

//otherlinesofcode

}

}catch(e){

}

Ifanexceptionisraisedintheinner try,it'shandledintheouter catchblock.

Exceptions

61

SemicolonsJavaScriptsemicolonsareoptional.Ipersonallylikeavoidingusingsemicolonsinmycode,butmanypeoplepreferthem.

SemicolonsinJavaScriptdividethecommunity.Someprefertousethemalways,nomatterwhat.Othersliketoavoidthem.

Afterusingsemicolonsforyears,inthefallof2017Idecidedtotryavoidingthemasneeded,andIdidsetupPrettiertoautomaticallyremovesemicolonsfrommycode,unlessthereisaparticularcodeconstructthatrequiresthem.

NowIfinditnaturaltoavoidsemicolons,Ithinkthecodelooksbetterandit'scleanertoread.

ThisisallpossiblebecauseJavaScriptdoesnotstrictlyrequiresemicolons.Whenthereisaplacewhereasemicolonwasneeded,itaddsitbehindthescenes.

TheprocessthatdoesthisiscalledAutomaticSemicolonInsertion.

It'simportanttoknowtherulesthatpowersemicolons,toavoidwritingcodethatwillgeneratebugsbecausedoesnotbehavelikeyouexpect.

TherulesofJavaScriptAutomaticSemicolonInsertionTheJavaScriptparserwillautomaticallyaddasemicolonwhen,duringtheparsingofthesourcecode,itfindstheseparticularsituations:

1. whenthenextlinestartswithcodethatbreaksthecurrentone(codecanspawnonmultiplelines)

2. whenthenextlinestartswitha },closingthecurrentblock3. whentheendofthesourcecodefileisreached4. whenthereisa returnstatementonitsownline5. whenthereisa breakstatementonitsownline6. whenthereisa throwstatementonitsownline7. whenthereisa continuestatementonitsownline

ExamplesofcodethatdoesnotdowhatyouthinkBasedonthoserules,herearesomeexamples.

Semicolons

62

Takethis:

consthey='hey'

constyou='hey'

constheyYou=hey+''+you

['h','e','y'].forEach((letter)=>console.log(letter))

You'llgettheerror UncaughtTypeError:Cannotreadproperty'forEach'ofundefinedbecausebasedonrule 1JavaScripttriestointerpretthecodeas

consthey='hey';

constyou='hey';

constheyYou=hey+''+you['h','e','y'].forEach((letter)=>console.log(letter))

Suchpieceofcode:

(1+2).toString()

prints "3".

consta=1

constb=2

constc=a+b

(a+b).toString()

insteadraisesa TypeError:bisnotafunctionexception,becauseJavaScripttriestointerpretitas

consta=1

constb=2

constc=a+b(a+b).toString()

Anotherexamplebasedonrule4:

(()=>{

return

{

color:'white'

}

})()

Semicolons

63

You'dexpectthereturnvalueofthisimmediately-invokedfunctiontobeanobjectthatcontainsthe colorproperty,butit'snot.Instead,it's undefined,becauseJavaScriptinsertsasemicolonafter return.

Insteadyoushouldputtheopeningbracketrightafter return:

(()=>{

return{

color:'white'

}

})()

You'dthinkthiscodeshows'0'inanalert:

1+1

-1+1===0?alert(0):alert(2)

butitshows2instead,becauseJavaScriptperrule1interpretsitas:

1+1-1+1===0?alert(0):alert(2)

ConclusionBecareful.Somepeopleareveryopinionatedonsemicolons.Idon'tcarehonestly,thetoolgivesustheoptionnottouseit,sowecanavoidsemicolons.

I'mnotsuggestinganything,otherthanpickingyourowndecision.

Wejustneedtopayabitofattention,evenifmostofthetimesthosebasicscenariosnevershowupinyourcode.

Picksomerules:

becarefulwith returnstatements.Ifyoureturnsomething,additonthesamelineasthereturn(samefor break, throw, continue)neverstartalinewithparentheses,thosemightbeconcatenatedwiththepreviouslinetoformafunctioncall,orarrayelementreference

Andultimately,alwaystestyourcodetomakesureitdoeswhatyouwant

Semicolons

64

Semicolons

65

QuotesAnoverviewofthequotesallowedinJavaScriptandtheiruniquefeatures

JavaScriptallowsyoutouse3typesofquotes:

singlequotesdoublequotesbackticks

Thefirst2areessentiallythesame:

consttest='test'

constbike="bike"

There'slittletonodifferenceinusingoneortheother.Theonlydifferenceliesinhavingtoescapethequotecharacteryouusetodelimitthestring:

consttest='test'

consttest='te\'st'

consttest='te"st'

consttest="te\"st"

consttest="te'st"

Therearevariousstyleguidesthatrecommendalwaysusingonestylevstheother.

Ipersonallyprefersinglequotesallthetime,andusedoublequotesonlyinHTML.

BackticksarearecentadditiontoJavaScript,sincetheywereintroducedwithES6in2015.

Theyhaveauniquefeature:theyallowmultilinestrings.

Multilinestringsarealsopossibleusingregularstrings,usingescapecharacters:

constmultilineString='Astring\nonmultiplelines'

Usingbackticks,youcanavoidusinganescapecharacter:

constmultilineString=`Astring

onmultiplelines`

Notjustthat.Youcaninterpolatevariablesusingthe ${}syntax:

constmultilineString=`Astring

Quotes

66

on${1+1}lines`

ThosearecalledTemplateLiterals.

Quotes

67

TemplateLiteralsIntroducedinES2015,akaES6,TemplateLiteralsofferanewwaytodeclarestrings,butalsosomenewinterestingconstructswhicharealreadywidelypopular.

IntroductiontoTemplateLiteralsTemplateLiteralsareanewES2015/ES6featurethatallowyoutoworkwithstringsinanovelwaycomparedtoES5andbelow.

Thesyntaxatafirstglanceisverysimple,justusebackticksinsteadofsingleordoublequotes:

consta_string=`something`

Theyareuniquebecausetheyprovidealotoffeaturesthatnormalstringsbuiltwithquotes,inparticular:

theyofferagreatsyntaxtodefinemultilinestringstheyprovideaneasywaytointerpolatevariablesandexpressionsinstringstheyallowtocreateDSLswithtemplatetags

Let'sdiveintoeachoftheseindetail.

MultilinestringsPre-ES6,tocreateastringspannedovertwolinesyouhadtousethe \characterattheendofaline:

conststring='firstpart\

secondpart'

Thisallowstocreateastringon2lines,butit'srenderedonjustoneline:

firstpartsecondpart

Torenderthestringonmultiplelinesaswell,youexplicitlyneedtoadd \nattheendofeachline,likethis:

conststring='firstline\n\

TemplateLiterals

68

secondline'

or

conststring='firstline\n'+

'secondline'

Templateliteralsmakemultilinestringsmuchsimpler.

Onceatemplateliteralisopenedwiththebacktick,youjustpressentertocreateanewline,withnospecialcharacters,andit'srenderedas-is:

conststring=`Hey

this

string

isawesome!`

Keepinmindthatspaceismeaningful,sodoingthis:

conststring=`First

Second`

isgoingtocreateastringlikethis:

First

Second

aneasywaytofixthisproblemisbyhavinganemptyfirstline,andappendingthetrim()methodrightaftertheclosingbacktick,whichwilleliminateanyspacebeforethefirstcharacter:

conststring=`

First

Second`.trim()

InterpolationTemplateliteralsprovideaneasywaytointerpolatevariablesandexpressionsintostrings.

Youdosobyusingthe ${...}syntax:

constvar='test'

TemplateLiterals

69

conststring=`something${var}`//somethingtest

insidethe ${}youcanaddanything,evenexpressions:

conststring=`something${1+2+3}`

conststring2=`something${foo()?'x':'y'}`

TemplatetagsTaggedtemplatesisonefeaturesthatmightsoundlessusefulatfirstforyou,butit'sactuallyusedbylotsofpopularlibrariesaround,likeStyledComponentsorApollo,theGraphQLclient/serverlib,soit'sessentialtounderstandhowitworks.

InStyledComponentstemplatetagsareusedtodefineCSSstrings:

constButton=styled.button`

font-size:1.5em;

background-color:black;

color:white;

`;

InApollotemplatetagsareusedtodefineaGraphQLqueryschema:

constquery=gql`

query{

...

}

`

The styled.buttonand gqltemplatetagshighlightedinthoseexamplesarejustfunctions:

functiongql(literals,...expressions){

}

thisfunctionreturnsastring,whichcanbetheresultofanykindofcomputation.

literalsisanarraycontainingthetemplateliteralcontenttokenizedbytheexpressionsinterpolations.

expressionscontainsalltheinterpolations.

Ifwetakeanexampleabove:

TemplateLiterals

70

conststring=`something${1+2+3}`

literalsisanarraywithtwoitems.Thefirstis something,thestringuntilthefirstinterpolation,andthesecondisanemptystring,thespacebetwenetheendofthefirstinterpolation(weonlyhaveone)andtheendofthestring.

expressionsinthiscaseisanarraywithasingleitem, 6.

Amorecomplexexampleis:

conststring=`something

another${'x'}

newline${1+2+3}

test`

inthiscase literalsisanarraywherethefirstitemis:

`something

another`

thesecondis:

`

newline`

andthethirdis:

`

test`

expressionsinthiscaseisanarraywithtwoitems, xand 6.

Thefunctionthatispassedthosevaluescandoanythingwiththem,andthisisthepowerofthiskindfeature.

Themostsimpleexampleisreplicatingwhatthestringinterpolationdoes,bysimplyjoiningliteralsand expressions:

constinterpolated=interpolate`Ipaid${10}€`

andthisishow interpolateworks:

functioninterpolate(literals,...expressions){

letstring=``

TemplateLiterals

71

for(const[i,val]ofexpressions){

string+=literals[i]+val

}

string+=literals[literals.length-1]

returnstring

}

TemplateLiterals

72

FunctionsLearnallaboutfunctions,fromthegeneraloverviewtothetinydetailsthatwillimprovehowyouusethem

IntroductionEverythinginJavaScripthappensinfunctions.

Afunctionisablockofcode,selfcontained,thatcanbedefinedonceandrunanytimesyouwant.

Afunctioncanoptionallyacceptparameters,andreturnsonevalue.

FunctionsinJavaScriptareobjects,aspecialkindofobjects:functionobjects.Theirsuperpowerliesinthefactthattheycanbeinvoked.

Inaddition,functionsaresaidtobefirstclassfunctionsbecausetheycanbeassignedtoavalue,andtheycanbepassedasargumentsandusedasareturnvalue.

Syntax

Functions

73

Let'sstartwiththe"old",pre-ES6/ES2015syntax.Here'safunctiondeclaration:

functiondosomething(foo){

//dosomething

}

(now,inpostES6/ES2015world,referredasaregularfunction)

Functionscanbeassignedtovariables(thisiscalledafunctionexpression):

constdosomething=function(foo){

//dosomething

}

Namedfunctionexpressionsaresimilar,butplaynicerwiththestackcalltrace,whichisusefulwhenanerroroccurs-itholdsthenameofthefunction:

constdosomething=functiondosomething(foo){

//dosomething

}

ES6/ES2015introducedarrowfunctions,whichareespeciallynicetousewhenworkingwithinlinefunctions,asparametersorcallbacks:

constdosomething=foo=>{

//dosomething

}

Arrowfunctionshaveanimportantdifferencefromtheotherfunctiondefinitionsabove,we'llseewhichonelaterasit'sanadvancedtopic.

ParametersAfunctioncanhaveoneormoreparameters.

constdosomething=()=>{

//dosomething

}

constdosomethingElse=foo=>{

//dosomething

}

constdosomethingElseAgain=(foo,bar)=>{

//dosomething

Functions

74

}

StartingwithES6/ES2015,functionscanhavedefaultvaluesfortheparameters:

constdosomething=(foo=1,bar='hey')=>{

//dosomething

}

Thisallowsyoutocallafunctionwithoutfillingalltheparameters:

dosomething(3)

dosomething()

ES2018introducedtrailingcommasforparameters,afeaturethathelpsreducingbugsduetomissingcommaswhenmovingaroundparameters(e.g.movingthelastinthemiddle):

constdosomething=(foo=1,bar='hey')=>{

//dosomething

}

dosomething(2,'ho!')

Youcanwrapallyourargumentsinanarray,andusethespreadoperatorwhencallingthefunction:

constdosomething=(foo=1,bar='hey')=>{

//dosomething

}

constargs=[2,'ho!']

dosomething(...args)

Withmanyparameters,rememberingtheordercanbedifficult.Usingobjects,destructuringallowstokeeptheparameternames:

constdosomething=({foo=1,bar='hey'})=>{

//dosomething

console.log(foo)//2

console.log(bar)//'ho!'

}

constargs={foo:2,bar:'ho!'}

dosomething(args)

Returnvalues

Functions

75

Everyfunctionreturnsavalue,whichbydefaultis undefined.

Anyfunctionisterminatedwhenitslinesofcodeend,orwhentheexecutionflowfindsareturnkeyword.

WhenJavaScriptencountersthiskeyworditexitsthefunctionexecutionandgivescontrolbacktoitscaller.

Ifyoupassavalue,thatvalueisreturnedastheresultofthefunction:

constdosomething=()=>{

return'test'

}

constresult=dosomething()//result==='test'

Youcanonlyreturnonevalue.

Tosimulatereturningmultiplevalues,youcanreturnanobjectliteral,oranarray,anduseadestructuringassignmentwhencallingthefunction.

Usingarrays:

Functions

76

Usingobjects:

NestedfunctionsFunctionscanbedefinedinsideotherfunctions:

constdosomething=()=>{

constdosomethingelse=()=>{}

dosomethingelse()

return'test'

}

Functions

77

Thenestedfunctionisscopedtotheoutsidefunction,andcannotbecalledfromtheoutside.

ObjectMethodsWhenusedasobjectproperties,functionsarecalledmethods:

constcar={

brand:'Ford',

model:'Fiesta',

start:function(){

console.log(`Started`)

}

}

car.start()

thisinArrowFunctionsThere'sanimportantbehaviorofArrowFunctionsvsregularFunctionswhenusedasobjectmethods.Considerthisexample:

constcar={

brand:'Ford',

model:'Fiesta',

start:function(){

console.log(`Started${this.brand}${this.model}`)

},

stop:()=>{

console.log(`Stopped${this.brand}${this.model}`)

}

}

The stop()methoddoesnotworkasyouwouldexpect.

Functions

78

Thisisbecausethehandlingof thisisdifferentinthetwofunctionsdeclarationsstyle. thisinthearrowfunctionreferstotheenclosingfunctioncontext,whichinthiscaseisthe windowobject:

this,whichreferstothehostobjectusing function()

Functions

79

Thisimpliesthatarrowfunctionsarenotsuitabletobeusedforobjectmethodsandconstructors(arrowfunctionconstructorswillactuallyraisea TypeErrorwhencalled).

IIFE,ImmediatelyInvocatedFunctionExpressionsAnIIFEisafunctionthat'simmediatelyexecutedrightafteritsdeclaration:

;(functiondosomething(){

console.log('executed')

})()

Youcanassigntheresulttoavariable:

constsomething=(functiondosomething(){

return'something'

})()

Theyareveryhandy,asyoudon'tneedtoseparatelycallthefunctionafteritsdefinition.

FunctionHoistingJavaScriptbeforeexecutingyourcodereordersitaccordingtosomerules.

Functionsinparticulararemovedatthetopoftheirscope.Thisiswhyit'slegaltowrite

dosomething()

functiondosomething(){

console.log('didsomething')

}

Internally,JavaScriptmovesthefunctionbeforeitscall,alongwithalltheotherfunctionsfoundinthesamescope:

Functions

80

functiondosomething(){

console.log('didsomething')

}

dosomething()

Now,ifyouusenamedfunctionexpressions,sinceyou'reusingvariablessomethingdifferenthappens.Thevariabledeclarationishoisted,butnotthevalue,sonotthefunction.

dosomething()

constdosomething=functiondosomething(){

console.log('didsomething')

}

Notgoingtowork:

Thisisbecausewhathappensinternallyis:

constdosomething

dosomething()

dosomething=functiondosomething(){

console.log('didsomething')

}

Thesamehappensfor letdeclarations. vardeclarationsdonotworkeither,butwithadifferenterror:

Functions

81

Thisisbecause vardeclarationsarehoistedandinitializedwith undefinedasavalue,whileconstand letarehoistedbutnotinitialized.

Functions

82

ArrowFunctionsArrowFunctionsareoneofthemostimpactfulchangesinES6/ES2015,andtheyarewidelyusednowadays.Theyslightlydifferfromregularfunctions.Findouthow

ArrowfunctionswereintroducedinES6/ECMAScript2015,andsincetheirintroductiontheychangedforeverhowJavaScriptcodelooks(andworks).

Inmyopinionthischangewassowelcomingthatyounowrarelyseeinmoderncodebasestheusageofthe functionkeyword.

Visually,it’sasimpleandwelcomechange,whichallowsyoutowritefunctionswithashortersyntax,from:

constmyFunction=functionfoo(){

//...

}

to

constmyFunction=()=>{

//...

}

Ifthefunctionbodycontainsjustasinglestatement,youcanomittheparenthesesandwriteallonasingleline:

constmyFunction=()=>doSomething()

Parametersarepassedintheparentheses:

constmyFunction=(param1,param2)=>doSomething(param1,param2)

Ifyouhaveone(andjustone)parameter,youcouldomittheparenthesescompletely:

constmyFunction=param=>doSomething(param)

Thankstothisshortsyntax,arrowfunctionsencouragetheuseofsmallfunctions.

Implicitreturn

ArrowFunctions

83

Arrowfunctionsallowyoutohaveanimplicitreturn:valuesarereturnedwithouthavingtousethe returnkeyword.

Itworkswhenthereisaon-linestatementinthefunctionbody:

constmyFunction=()=>'test'

myFunction()//'test'

Anotherexample,returninganobject(remembertowrapthecurlybracketsinparenthesestoavoiditbeingconsideredthewrappingfunctionbodybrackets):

constmyFunction=()=>({value:'test'})

myFunction()//{value:'test'}

How thisworksinarrowfunctionsthisisaconceptthatcanbecomplicatedtograsp,asitvariesalotdependingonthecontextandalsovariesdependingonthemodeofJavaScript(strictmodeornot).

It'simportanttoclarifythisconceptbecausearrowfunctionsbehaveverydifferentlycomparedtoregularfunctions.

Whendefinedasamethodofanobject,inaregularfunction thisreferstotheobject,soyoucando:

constcar={

model:'Fiesta',

manufacturer:'Ford',

fullName:function(){

return`${this.manufacturer}${this.model}`

}

}

calling car.fullName()willreturn "FordFiesta".

The thisscopewitharrowfunctionsisinheritedfromtheexecutioncontext.Anarrowfunctiondoesnotbind thisatall,soitsvaluewillbelookedupinthecallstack,sointhiscode car.fullName()willnotwork,andwillreturnthestring "undefinedundefined":

constcar={

model:'Fiesta',

manufacturer:'Ford',

fullName:()=>{

ArrowFunctions

84

return`${this.manufacturer}${this.model}`

}

}

Duetothis,arrowfunctionsarenotsuitedasobjectmethods.

Arrowfunctionscannotbeusedasconstructorsaswell,wheninstantiatinganobjectwillraisea TypeError.

Thisiswhereregularfunctionsshouldbeusedinstead,whendynamiccontextisnotneeded.

Thisisalsoaproblemwhenhandlingevents.DOMEventlistenersset thistobethetargetelement,andifyourelyon thisinaneventhandler,aregularfunctionisnecessary:

constlink=document.querySelector('#link')

link.addEventListener('click',()=>{

//this===window

})

constlink=document.querySelector('#link')

link.addEventListener('click',function(){

//this===link

})

ArrowFunctions

85

ClosuresAgentleintroductiontothetopicofclosures,keytounderstandinghowJavaScriptfunctionswork

Ifyou'veeverwrittenafunctioninJavaScript,youalreadymadeuseofclosures.

It'sakeytopictounderstand,whichhasimplicationsonthethingsyoucando.

Whenafunctionisrun,it'sexecutedwiththescopethatwasinplacewhenitwasdefined,andnotwiththestatethat'sinplacewhenitisexecuted.

Thescopebasicallyisthesetofvariableswhicharevisible.

AfunctionremembersitsLexicalScope,andit'sabletoaccessvariablesthatweredefinedintheparentscope.

Inshort,afunctionhasanentirebaggageofvariablesitcanaccess.

Letmeimmediatelygiveanexampletoclarifythis.

constbark=dog=>{

constsay=`${dog}barked!`

;(()=>console.log(say))()

}

bark(`Roger`)

Closures

86

Thislogstotheconsole Rogerbarked!,asexpected.

Whatifyouwanttoreturntheactioninstead:

constprepareBark=dog=>{

constsay=`${dog}barked!`

return()=>console.log(say)

}

constbark=prepareBark(`Roger`)

bark()

Thissnippetalsologstotheconsole Rogerbarked!.

Let'smakeonelastexample,whichreuses prepareBarkfortwodifferentdogs:

constprepareBark=dog=>{

constsay=`${dog}barked!`

return()=>{

console.log(say)

}

}

constrogerBark=prepareBark(`Roger`)

constsydBark=prepareBark(`Syd`)

rogerBark()

sydBark()

Thisprints

Rogerbarked!

Sydbarked!

Asyoucansee,thestateofthevariable sayislinkedtothefunctionthat'sreturnedfromprepareBark().

Alsonoticethatweredefineanew sayvariablethesecondtimewecall prepareBark(),butthatdoesnotaffectthestateofthefirst prepareBark()scope.

Thisishowaclosureworks:thefunctionthat'sreturnedkeepstheoriginalstateinitsscope.

Closures

87

ArraysJavaScriptarraysovertimegotmoreandmorefeatures,sometimesit'strickytoknowwhentousesomeconstructvsanother.Thispostaimstoexplainwhatyoushoulduse,asof2018

JavaScriptarraysovertimegotmoreandmorefeatures,sometimesit'strickytoknowwhentousesomeconstructvsanother.Thispostaimstoexplainwhatyoushouldusein2018.

Initializearray

consta=[]

consta=[1,2,3]

consta=Array.of(1,2,3)

consta=Array(6).fill(1)//initanarrayof6itemsofvalue1

Don'tusetheoldsyntax(justuseitfortypedarrays)

consta=newArray()//neveruse

consta=newArray(1,2,3)//neveruse

Arrays

88

Getlengthofthearray

constl=a.length

Iteratingthearray

Every

a.every(f)

Iterates auntil f()returnsfalse

Some

a.some(f)

Iterates auntil f()returnstrue

Iteratethearrayandreturnanewonewiththereturnedresultofafunction

constb=a.map(f)

Iterates aandbuildsanewarraywiththeresultofexecuting f()oneach aelement

Filteranarray

constb=a.filter(f)

Iterates aandbuildsanewarraywithelementsof athatreturnedtruewhenexecutingf()oneach aelement

Reduce

a.reduce((accumulator,currentValue,currentIndex,array)=>{

//...

Arrays

89

},initialValue)

reduce()executesacallbackfunctiononalltheitemsofthearrayandallowstoprogressivelycomputearesult.If initialValueisspecified, accumulatorinthefirstiterationwillequaltothatvalue.

Example:

;[1,2,3,4].reduce((accumulator,currentValue,currentIndex,array)=>{

returnaccumulator*currentValue

},1)

//iteration1:1*1=>return1

//iteration2:1*2=>return2

//iteration3:2*3=>return6

//iteration4:6*4=>return24

//returnvalueis24

forEach

ES6

a.forEach(f)

Iterates fon awithoutawaytostop

Example:

a.forEach(v=>{

console.log(v)

})

for..of

ES6

for(letvofa){

console.log(v)

}

for

for(leti=0;i<a.length;i+=1){

//a[i]

Arrays

90

}

Iterates a,canbestoppedusing returnor breakandaniterationcanbeskippedusingcontinue

@@iterator

ES6

Gettingtheiteratorfromanarrayreturnsaniteratorofvalues

consta=[1,2,3]

letit=a[Symbol.iterator]()

console.log(it.next().value)//1

console.log(it.next().value)//2

console.log(it.next().value)//3

.entries()returnsaniteratorofkey/valuepairs

letit=a.entries()

console.log(it.next().value)//[0,1]

console.log(it.next().value)//[1,2]

console.log(it.next().value)//[2,3]

.keys()allowstoiterateonthekeys:

letit=a.keys()

console.log(it.next().value)//0

console.log(it.next().value)//1

console.log(it.next().value)//2

.next()returns undefinedwhenthearrayends.Youcanalsodetectiftheiterationendedbylookingat it.next()whichreturnsa value,donepair. doneisalwaysfalseuntilthelastelement,whichreturns true.

Addingtoanarray

Addattheend

a.push(4)

Arrays

91

Addatthebeginning

a.unshift(0)

a.unshift(-2,-1)

Removinganitemfromanarray

Fromtheend

a.pop()

Fromthebeginning

a.shift()

Atarandomposition

a.splice(0,2)//getthefirst2items

a.splice(3,2)//getthe2itemsstartingfromindex3

Donotuse remove()asitleavesbehindundefinedvalues.

Removeandinsertinplace

a.splice(2,3,2,'a','b')//removes3itemsstartingfrom

//index2,andadds2items,

//stillstartingfromindex2

Joinmultiplearrays

consta=[1,2]

constb=[3,4]

a.concat(b)//1,2,3,4

Lookupthearrayforaspecificelement

Arrays

92

ES5

a.indexOf()

Returnstheindexofthefirstmatchingitemfound,or-1ifnotfound

a.lastIndexOf()

Returnstheindexofthelastmatchingitemfound,or-1ifnotfound

ES6

a.find((element,index,array)=>{

//returntrueorfalse

})

Returnsthefirstitemthatreturnstrue.Returnsundefinedifnotfound.

Acommonlyusedsyntaxis:

a.find(x=>x.id===my_id)

Theabovelinewillreturnthefirstelementinthearraythathas id===my_id.

findIndexreturnstheindexofthefirstitemthatreturnstrue,andifnotfound,itreturnsundefined:

a.findIndex((element,index,array)=>{

//returntrueorfalse

})

ES7

a.includes(value)

Returnstrueif acontains value.

a.includes(value,i)

Returnstrueif acontains valueaftertheposition i.

Arrays

93

Getaportionofanarray

a.slice()

SortthearraySortalphabetically(byASCIIvalue- 0-9A-Za-z)

consta=[1,2,3,10,11]

a.sort()//1,10,11,2,3

constb=[1,'a','Z',3,2,11]

b=a.sort()//1,11,2,3,Z,a

Sortbyacustomfunction

consta=[1,10,3,2,11]

a.sort((a,b)=>a-b)//1,2,3,10,11

Reversetheorderofanarray

a.reverse()

Getastringrepresentationofanarray

a.toString()

Returnsastringrepresentationofanarray

a.join()

Returnsastringconcatenationofthearrayelements.Passaparametertoaddacustomseparator:

a.join(',')

Copyanexistingarraybyvalue

Arrays

94

constb=Array.from(a)

constb=Array.of(...a)

Copyjustsomevaluesfromanexistingarray

constb=Array.from(a,x=>x%2==0)

Copyportionsofanarrayintothearrayitself,inotherpositions

consta=[1,2,3,4]

a.copyWithin(0,2)//[3,4,3,4]

constb=[1,2,3,4,5]

b.copyWithin(0,2)//[3,4,5,4,5]

//0iswheretostartcopyinginto,

//2iswheretostartcopyingfrom

constc=[1,2,3,4,5]

c.copyWithin(0,2,4)//[3,4,3,4,5]

//4isanendindex

Arrays

95

LoopsJavaScriptprovidesmanywaytoiteratethroughloops.ThistutorialexplainsallthevariouslooppossibilitiesinmodernJavaScript

IntroductionJavaScriptprovidesmanywaytoiteratethroughloops.Thistutorialexplainseachonewithasmallexampleandthemainproperties.

for

constlist=['a','b','c']

for(leti=0;i<list.length;i++){

console.log(list[i])//value

console.log(i)//index

}

Youcaninterrupta forloopusing breakYoucanfastforwardtothenextiterationofa forloopusing continue

Loops

96

forEachIntroducedinES5.Givenanarray,youcaniterateoveritspropertiesusing list.forEach():

constlist=['a','b','c']

list.forEach((item,index)=>{

console.log(item)//value

console.log(index)//index

})

//indexisoptional

list.forEach(item=>console.log(item))

unfortunatelyyoucannotbreakoutofthisloop.

do...while

constlist=['a','b','c']

leti=0

do{

console.log(list[i])//value

console.log(i)//index

i=i+1

}while(i<list.length)

Youcaninterrupta whileloopusing break:

do{

if(something)break

}while(true)

andyoucanjumptothenextiterationusing continue:

do{

if(something)continue

//dosomethingelse

}while(true)

while

constlist=['a','b','c']

leti=0

while(i<list.length){

Loops

97

console.log(list[i])//value

console.log(i)//index

i=i+1

}

Youcaninterrupta whileloopusing break:

while(true){

if(something)break

}

andyoucanjumptothenextiterationusing continue:

while(true){

if(something)continue

//dosomethingelse

}

Thedifferencewith do...whileisthat do...whilealwaysexecuteitscycleatleastonce.

for...in

Iteratesalltheenumerablepropertiesofanobject,givingthepropertynames.

for(letpropertyinobject){

console.log(property)//propertyname

console.log(object[property])//propertyvalue

}

for...of

ES2015introducedthe for...ofloop,whichcombinestheconcisenessofforEachwiththeabilitytobreak:

//iterateoverthevalue

for(constvalueof['a','b','c']){

console.log(value)//value

}

//gettheindexaswell,using`entries()`

for(const[index,value]of['a','b','c'].entries()){

console.log(index)//index

console.log(value)//value

}

Loops

98

Noticetheuseof const.Thisloopcreatesanewscopeineveryiteration,sowecansafelyusethatinsteadof let.

for...invs for...ofThedifferencewith for...inis:

for...ofiteratesoverthepropertyvaluesfor...initeratesthepropertynames

Loops

99

EventsJavaScriptinthebrowserusesanevent-drivenprogrammingmodel.Everythingstartsbyfollowinganevent.ThisisanintroductiontoJavaScripteventsandhoweventhandlingworks

IntroductionJavaScriptinthebrowserusesanevent-drivenprogrammingmodel.

Everythingstartsbyfollowinganevent.

TheeventcouldbetheDOMisloaded,oranasynchronousrequestthatfinishesfetching,orauserclickinganelementorscrollingthepage,ortheusertypesonthekeyboard.

Therearealotofdifferentkindofevents.

EventhandlersYoucanrespondtoanyeventusinganEventHandler,whichisjustafunctionthat'scalledwhenaneventoccurs.

Events

100

Youcanregistermultiplehandlersforthesameevent,andtheywillallbecalledwhenthateventhappens.

JavaScriptofferthreewaystoregisteraneventhandler:

Inlineeventhandlers

Thisstyleofeventhandlersisveryrarelyusedtoday,duetoitsconstrains,butitwastheonlywayintheJavaScriptearlydays:

<ahref="site.com"onclick="dosomething();">Alink</a>

DOMon-eventhandlers

Thisiscommonwhenanobjecthasatmostoneeventhandler,asthereisnowaytoaddmultiplehandlersinthiscase:

window.onload=()=>{

//windowloaded

}

It'smostcommonlyusedwhenhandlingXHRrequests:

constxhr=newXMLHttpRequest()

xhr.onreadystatechange=()=>{

//..dosomething

}

Youcancheckifanhandlerisalreadyassignedtoapropertyusing if('onsomething'inwindow){}.

Using addEventListener()

Thisisthemodernway.Thismethodallowstoregisterasmanyhandlersasweneed,andit'sthemostpopularyouwillfind:

window.addEventListener('load',()=>{

//windowloaded

})

Thismethodallowstoregisterasmanyhandlersasweneed,andit'sthemostpopularyouwillfind.

Events

101

NotethatIE8andbelowdidnotsupportthis,andinsteaduseditsown attachEvent()API.Keepitinmindifyouneedtosupportolderbrowsers.

ListeningondifferentelementsYoucanlistenon windowtointercept"global"events,liketheusageofthekeyboard,andyoucanlistenonspecificelementstocheckeventshappeningonthem,likeamouseclickonabutton.

Thisiswhy addEventListenerissometimescalledon window,sometimesonaDOMelement.

TheEventobjectAneventhandlergetsan Eventobjectasthefirstparameter:

constlink=document.getElementById('my-link')

link.addEventListener('click',event=>{

//linkclicked

})

Thisobjectcontainsalotofusefulpropertiesandmethods,like:

target,theDOMelementthatoriginatedtheeventtype,thetypeofeventstopPropagation(),calledtostoppropagatingtheeventintheDOM

(seethefulllist).

Otherpropertiesareprovidedbyspecifickindofevents,as Eventisaninterfacefordifferentspecificevents:

MouseEventKeyboardEventDragEventFetchEvent...andothers

EachofthosehasaMDNpagelinked,soyoucaninspectalltheirproperties.

ForexamplewhenaKeyboardEventhappens,youcancheckwhichkeywaspressed,inarreadableformat( Escape, Enterandsoon)bycheckingthe keyproperty:

window.addEventListener('keydown',event=>{

//keypressed

Events

102

console.log(event.key)

})

Onamouseeventwecancheckwhichmousebuttonwaspressed:

constlink=document.getElementById('my-link')

link.addEventListener('mousedown',event=>{

//mousebuttonpressed

console.log(event.button)//0=left,2=right

})

EventbubblingandeventcapturingBubblingandcapturingarethe2modelsthateventsusetopropagate.

SupposeyouDOMstructureis

<divid="container">

<button>Clickme</button>

</div>

Youwanttotrackwhenusersclickonthebutton,andyouhave2eventlisteners,oneonbutton,andoneon #container.Remember,aclickonachildelementwillalwayspropagatetoitsparents,unlessyoustopthepropagation(seelater).

Thoseeventlistenerswillbecalledinorder,andthisorderisdeterminedbytheeventbubbling/capturingmodelused.

Bubblingmeansthattheeventpropagatesfromtheitemthatwasclicked(thechild)uptoallitsparenttree,startingfromthenearestone.

Inourexample,thehandleron buttonwillfirebeforethe #containerhandler.

Capturingistheopposite:theoutereventhandlersarefiredbeforethemorespecifichandler,theoneon button.

Bydefaultalleventsbubble.

YoucanchoosetoadopteventcapturingbyapplyingathirdargumenttoaddEventListener,settingitto true:

document.getElementById('container').addEventListener(

'click',

()=>{

//windowloaded

},

Events

103

true

)

Notethatfirstallcapturingeventhandlersarerun.

Thenallthebubblingeventhandlers.

Theorderfollowsthisprinciple:theDOMgoesthroughallelementsstartingfromtheWindowobject,andgoestofindtheitemthatwasclicked.Whiledoingso,itcallsanyeventhandlerassociatedtotheevent(capturingphase).

Onceitreachesthetarget,itthenrepeatsthejourneyuptotheparentstreeuntiltheWindowobject,callingagaintheeventhandlers(bubblingphase).

StoppingthepropagationAneventonaDOMelementwillbepropagatedtoallitsparentelementstree,unlessit'sstopped.

<html>

<body>

<section>

<aid="my-link"...>

Aclickeventon awillpropagateto sectionandthen body.

Youcanstopthepropagationbycallingthe stopPropagation()methodofanEvent,usuallyattheendoftheeventhandler:

constlink=document.getElementById('my-link')

link.addEventListener('mousedown',event=>{

//processtheevent

//...

event.stopPropagation()

})

PopulareventsHere'salistofthemostcommoneventsyouwilllikelyhandle.

Load

loadisfiredon windowandthe bodyelementwhenthepagehasfinishedloading.

Events

104

Mouseevents

clickfireswhenamousebuttonisclicked. dblclickwhenthemouseisclickedtwotimes.Ofcourseinthiscase clickisfiredjustbeforethisevent. mousedown, mousemoveandmouseupcanbeusedincombinationtotrackdrag-and-dropevents.Becarefulwithmousemove,asitfiresmanytimesduringthemousemovement(seethrottlinglater)

Keyboardevents

keydownfireswhenakeyboardbuttonispressed(andanytimethekeyrepeatswhilethebuttonstayspressed). keyupisfiredwhenthekeyisreleased.

Scroll

The scrolleventisfiredon windoweverytimeyouscrollthepage.Insidetheeventhandleryoucancheckthecurrentscrollingpositionbychecking window.scrollY.

Keepinmindthatthiseventisnotaone-timething.Itfiresalotoftimesduringscrolling,notjustattheendorbeginningofthescrolling,sodon'tdoanyheavycomputationormanipulationinthehandler-usethrottlinginstead.

ThrottlingAswementionedabove, mousemoveand scrollaretwoeventsthatarenotfiredone-timeperevent,butrathertheycontinuouslycalltheireventhandlerfunctionduringallthedurationoftheaction.

Thisisbecausetheyprovidecoordinatessoyoucantrackwhat'shappening.

Ifyouperformacomplexoperationintheeventhandler,youwillaffecttheperformanceandcauseasluggishexperiencetoyoursiteusers.

LibrariesthatprovidethrottlinglikeLodashimplementitin100+linesofcode,tohandleeverypossibleusecase.Asimpleandeasytounderstandimplementationisthis,whichusessetTimeouttocachethescrolleventevery100ms:

letcached=null

window.addEventListener('scroll',event=>{

if(!cached){

setTimeout(()=>{

//youcanaccesstheoriginaleventat`cached`

cached=null

},100)

}

cached=event

Events

105

})

Events

106

TheEventLoopTheEventLoopisoneofthemostimportantaspectstounderstandaboutJavaScript.Thispostexplainsitinsimpleterms

IntroductionTheEventLoopisoneofthemostimportantaspectstounderstandaboutJavaScript.

I'veprogrammedforyearswithJavaScript,yetI'veneverfullyunderstoodhowthingsworkunderthehoods.It'scompletelyfinetonotknowthisconceptindetail,butasusual,it'shelpfultoknowhowitworks,andalsoyoumightjustbealittlecuriousatthispoint.

ThispostaimstoexplaintheinnerdetailsofhowJavaScriptworkswithasinglethread,andhowithandlesasynchronousfunctions.

YourJavaScriptcoderunssinglethreaded.Thereisjustonethinghappeningatatime.

Thisisalimitationthat'sactuallyveryhelpful,asitsimplifiesalothowyouprogramwithoutworryingaboutconcurrencyissues.

Youjustneedtopayattentiontohowyouwriteyourcodeandavoidanythingthatcouldblockthethread,likesynchronousnetworkcallsorinfiniteloops.

Ingeneral,inmostbrowsersthereisaneventloopforeverybrowsertab,tomakeeveryprocessisolatedandavoidawebpagewithinfiniteloopsorheavyprocessingtoblockyourentirebrowser.

Theenvironmentmanagesmultipleconcurrenteventloops,tohandleAPIcallsforexample.WebWorkersrunintheirowneventloopaswell.

Youmainlyneedtobeconcernedthatyourcodewillrunonasingleeventloop,andwritecodewiththisthinginmindtoavoidblockingit.

BlockingtheeventloopAnyJavaScriptcodethattakestoolongtoreturnbackcontroltotheeventloopwillblocktheexecutionofanyJavaScriptcodeinthepage,evenblocktheUIthread,andtheusercannotclickaround,scrollthepage,andsoon.

TheEventLoop

107

AlmostalltheI/OprimitivesinJavaScriptarenon-blocking.Networkrequests,Node.jsfilesystemoperations,andsoon.Beingblockingistheexception,andthisiswhyJavaScriptisbasedsomuchoncallbacks,andmorerecentlyonpromisesandasync/await.

ThecallstackThecallstackisaLIFOqueue(LastIn,FirstOut).

Theeventloopcontinuouslychecksthecallstacktoseeifthere'sanyfunctionthatneedstorun.

Whiledoingso,itaddsanyfunctioncallitfindstothecallstackandexecuteseachoneinorder.

Youknowtheerrorstacktraceyoumightbefamiliarwith,inthedebuggerorinthebrowserconsole?Thebrowserlooksupthefunctionnamesinthecallstacktoinformyouwhichfunctionoriginatesthecurrentcall:

TheEventLoop

108

AsimpleeventloopexplanationLet'spickanexample:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

bar()

baz()

}

foo()

TheEventLoop

109

Thiscodeprints

foo

bar

baz

asexpected.

Whenthiscoderuns,first foo()iscalled.Inside foo()wefirstcall bar(),thenwecallbaz().

Atthispointthecallstacklookslikethis:

Theeventlooponeveryiterationlooksifthere'ssomethinginthecallstack,andexecutesit:

TheEventLoop

110

untilthecallstackisempty.

QueuingfunctionexecutionTheaboveexamplelooksnormal,there'snothingspecialaboutit:JavaScriptfindsthingstoexecute,runstheminorder.

TheEventLoop

111

Let'sseehowtodeferafunctionuntilthestackisclear.

Theusecaseof setTimeout(()=>{}),0)istocallafunction,butexecuteitonceeveryotherfunctioninthecodehasexecuted.

Takethisexample:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

setTimeout(bar,0)

baz()

}

foo()

Thiscodeprints,maybesurprisingly:

foo

baz

bar

Whenthiscoderuns,firstfoo()iscalled.Insidefoo()wefirstcallsetTimeout,passing barasanargument,andweinstructittorunimmediatelyasfastasitcan,passing0asthetimer.Thenwecallbaz().

Atthispointthecallstacklookslikethis:

TheEventLoop

112

Hereistheexecutionorderforallthefunctionsinourprogram:

TheEventLoop

113

Whyisthishappening?

TheMessageQueue

TheEventLoop

114

WhensetTimeout()iscalled,theBrowserorNode.jsstartthetimer.Oncethetimerexpires,inthiscaseimmediatelyasweput0asthetimeout,thecallbackfunctionisputintheMessageQueue.

TheMessageQueueisalsowhereuser-initiatedeventslikeclickorkeyboardevents,orfetchresponsesarequeuedbeforeyourcodehastheopportunitytoreacttothem.OralsoDOMeventslike onLoad.

Theloopgivesprioritytothecallstack,anditfirstprocesseseverythingitfindsinthecallstack,andoncethere'snothinginthere,itgoestopickupthingsintheeventqueue.

Wedon'thavetowaitforfunctionslike setTimeout,fetchorotherthingstodotheirownwork,becausetheyareprovidedbythebrowser,andtheyliveontheirownthreads.Forexample,ifyousetthe setTimeouttimeoutto2seconds,youdon'thavetowait2seconds-thewaithappenselsewhere.

ES6JobQueueECMAScript2015introducedtheconceptoftheJobQueue,whichisusedbyPromises(alsointroducedinES6/ES2015).It'sawaytoexecutetheresultofanasyncfunctionassoonaspossible,ratherthanbeingputattheendofthecallstack.

Promisesthatresolvebeforethecurrentfunctionendswillbeexecutedrightafterthecurrentfunction.

Ifindnicetheanalogyofarollercoasterrideatanamusementpark:themessagequeueputsyoubackinqueuewithafteralltheotherpeopleinthequeue,whilethejobqueueisthefastpassticketthatletsyoutakeanotherriderightafteryoufinishedthepreviousone.

Example:

constbar=()=>console.log('bar')

constbaz=()=>console.log('baz')

constfoo=()=>{

console.log('foo')

setTimeout(bar,0)

newPromise((resolve,reject)=>

resolve('shouldberightafterbaz,beforebar')

).then(resolve=>console.log(resolve))

baz()

}

foo()

TheEventLoop

115

Thisprints

foo

baz

shouldberightafterbaz,beforebar

bar

That'sabigdifferencebetweenPromises(andAsync/await,whichisbuiltonpromises)andplainoldasynchronousfunctionsthrough setTimeout()orotherplatformAPIs.

TheEventLoop

116

AsynchronousprogrammingandcallbacksJavaScriptissynchronousbydefault,andissinglethreaded.Thismeansthatcodecannotcreatenewthreadsandruninparallel.Findoutwhatasynchronouscodemeansandhowitlookslike

AsynchronicityinProgrammingLanguagesComputersareasynchronousbydesign.

Asynchronousmeansthatthingscanhappenindependentlyofthemainprogramflow.

Inthecurrentconsumercomputers,everyprogramrunsforaspecifictimeslot,andthenitstopsitsexecutiontoletanotherprogramcontinueitsexecution.Thisthingrunsinacyclesofastthat'simpossibletonotice,andwethinkourcomputersrunmanyprogramssimultaneously,butthisisanillusion(exceptonmultiprocessormachines).

Programsinternallyuseinterrupts,asignalthat'semittedtotheprocessortogaintheattentionofthesystem.

Asynchronousprogrammingandcallbacks

117

Iwon'tgointotheinternalsofthis,butjustkeepinmindthatit'snormalforprogramstobeasynchronous,andhalttheirexecutionuntiltheyneedattention,andthecomputercanexecuteotherthingsinthemeantime.Whenaprogramiswaitingforaresponsefromthenetwork,itcannothalttheprocessoruntiltherequestfinishes.

Normally,programminglanguagesaresynchronous,andsomeprovideawaytomanageasynchronicity,inthelanguageorthroughlibraries.C,Java,C#,PHP,Go,Ruby,Swift,Python,theyareallsynchronousbydefault.Someofthemhandleasyncbyusingthreads,spawninganewprocess.

JavaScriptJavaScriptissynchronousbydefaultandissinglethreaded.Thismeansthatcodecannotcreatenewthreadsandruninparallel.

Linesofcodeareexecutedinseries,oneafteranother,forexample:

consta=1

constb=2

constc=a*b

console.log(c)

doSomething()

ButJavaScriptwasborninsidethebrowser,itsmainjob,inthebeginning,wastorespondtouseractions,like onClick, onMouseOver, onChange, onSubmitandsoon.Howcoulditdothiswithasynchronousprogrammingmodel?

Theanswerwasinitsenvironment.ThebrowserprovidesawaytodoitbyprovidingasetofAPIsthatcanhandlethiskindoffunctionality.

Morerecently,Node.jsintroducedanon-blockingI/Oenvironmenttoextendthisconcepttofileaccess,networkcallsandsoon.

CallbacksYoucan'tknowwhenauserisgoingtoclickabutton,sowhatyoudois,youdefineaneventhandlerfortheclickevent.Thiseventhandleracceptsafunction,whichwillbecalledwhentheeventistriggered:

document.getElementById('button').addEventListener('click',()=>{

//itemclicked

})

Asynchronousprogrammingandcallbacks

118

Thisistheso-calledcallback.

Acallbackisasimplefunctionthat'spassedasavaluetoanotherfunction,andwillonlybeexecutedwhentheeventhappens.WecandothisbecauseJavaScripthasfirst-classfunctions,whichcanbeassignedtovariablesandpassedaroundtootherfunctions(calledhigher-orderfunctions)

It'scommontowrapallyourclientcodeina loadeventlisteneronthe windowobject,whichrunsthecallbackfunctiononlywhenthepageisready:

window.addEventListener('load',()=>{

//windowloaded

//dowhatyouwant

})

Callbacksareusedeverywhere,notjustinDOMevents.

Onecommonexampleisbyusingtimers:

setTimeout(()=>{

//runsafter2seconds

},2000)

XHRrequestsalsoacceptacallback,inthisexamplebyassigningafunctiontoapropertythatwillbecalledwhenaparticulareventoccurs(inthiscase,thestateoftherequestchanges):

constxhr=newXMLHttpRequest()

xhr.onreadystatechange=()=>{

if(xhr.readyState===4){

xhr.status===200?console.log(xhr.responseText):console.error('error')

}

}

xhr.open('GET','https://yoursite.com')

xhr.send()

HandlingerrorsincallbacksHowdoyouhandleerrorswithcallbacks?OneverycommonstrategyistousewhatNode.jsadopted:thefirstparameterinanycallbackfunctionistheerrorobject:error-firstcallbacks

Ifthereisnoerror,theobjectis null.Ifthereisanerror,itcontainssomedescriptionoftheerrorandotherinformation.

fs.readFile('/file.json',(err,data)=>{

if(err!==null){

Asynchronousprogrammingandcallbacks

119

//handleerror

console.log(err)

return

}

//noerrors,processdata

console.log(data)

})

TheproblemwithcallbacksCallbacksaregreatforsimplecases!

Howevereverycallbackaddsalevelofnesting,andwhenyouhavelotsofcallbacks,thecodestartstobecomplicatedveryquickly:

window.addEventListener('load',()=>{

document.getElementById('button').addEventListener('click',()=>{

setTimeout(()=>{

items.forEach(item=>{

//yourcodehere

})

},2000)

})

})

Thisisjustasimple4-levelscode,butI'veseenmuchmorelevelsofnestingandit'snotfun.

Howdowesolvethis?

AlternativestocallbacksStartingwithES6,JavaScriptintroducedseveralfeaturesthathelpuswithasynchronouscodethatdonotinvolveusingcallbacks:

Promises(ES6)Async/Await(ES8)

Asynchronousprogrammingandcallbacks

120

PromisesPromisesareonewaytodealwithasynchronouscodeinJavaScript,withoutwritingtoomanycallbacksinyourcode.

IntroductiontopromisesApromiseiscommonlydefinedasaproxyforavaluethatwilleventuallybecomeavailable.

Promisesareonewaytodealwithasynchronouscode,withoutwritingtoomanycallbacksinyourcode.

Althoughbeingaroundsinceyears,theyhavebeenstandardizedandintroducedinES2015,andnowtheyhavebeensupersededinES2017byasyncfunctions.

AsyncfunctionsusethepromisesAPIastheirbuildingblock,sounderstandingthemisfundamentalevenifinnewercodeyou'lllikelyuseasyncfunctionsinsteadofpromises.

Howpromiseswork,inbrief

Onceapromisehasbeencalled,itwillstartinpendingstate.Thismeansthatthecallerfunctioncontinuestheexecution,whileitwaitsforthepromisetodoitsownprocessing,andgivethecallerfunctionsomefeedback.

Atthispoint,thecallerfunctionwaitsforittoeitherreturnthepromiseinaresolvedstate,orinarejectedstate,butasyouknowJavaScriptisasynchronous,sothefunctioncontinuesitsexecutionwhilethepromisedoesitwork.

WhichJSAPIusepromises?

Inadditiontoyourowncodeandlibrariescode,promisesareusedbystandardmodernWebAPIssuchas:

theBatteryAPItheFetchAPIServiceWorkers

It'sunlikelythatinmodernJavaScriptyou'llfindyourselfnotusingpromises,solet'sstartdivingrightintothem.

Promises

121

CreatingapromiseThePromiseAPIexposesaPromiseconstructor,whichyouinitializeusing newPromise():

letdone=true

constisItDoneYet=newPromise(

(resolve,reject)=>{

if(done){

constworkDone='HereisthethingIbuilt'

resolve(workDone)

}else{

constwhy='Stillworkingonsomethingelse'

reject(why)

}

}

)

Asyoucanseethepromisechecksthe doneglobalconstant,andifthat'strue,wereturnaresolvedpromise,otherwisearejectedpromise.

Using resolveand rejectwecancommunicatebackavalue,intheabovecasewejustreturnastring,butitcouldbeanobjectaswell.

ConsumingapromiseInthelastsection,weintroducedhowapromiseiscreated.

Nowlet'sseehowthepromisecanbeconsumedorused.

constisItDoneYet=newPromise(

//...

)

constcheckIfItsDone=()=>{

isItDoneYet

.then((ok)=>{

console.log(ok)

})

.catch((err)=>{

console.error(err)

})

}

Promises

122

Running checkIfItsDone()willexecutethe isItDoneYet()promiseandwillwaitforittoresolve,usingthe thencallback,andifthereisanerror,itwillhandleitinthe catchcallback.

ChainingpromisesApromisecanbereturnedtoanotherpromise,creatingachainofpromises.

AgreatexampleofchainingpromisesisgivenbytheFetchAPI,alayerontopoftheXMLHttpRequestAPI,whichwecanusetogetaresourceandqueueachainofpromisestoexecutewhentheresourceisfetched.

TheFetchAPIisapromise-basedmechanism,andcalling fetch()isequivalenttodefiningourownpromiseusing newPromise().

Exampleofchainingpromises

conststatus=(response)=>{

if(response.status>=200&&response.status<300){

returnPromise.resolve(response)

}

returnPromise.reject(newError(response.statusText))

}

constjson=(response)=>response.json()

fetch('/todos.json')

.then(status)

.then(json)

.then((data)=>{console.log('RequestsucceededwithJSONresponse',data)})

.catch((error)=>{console.log('Requestfailed',error)})

Inthisexample,wecall fetch()togetalistofTODOitemsfromthe todos.jsonfilefoundinthedomainroot,andwecreateachainofpromises.

Running fetch()returnsaresponse,whichhasmanyproperties,andwithinthosewereference:

status,anumericvaluerepresentingtheHTTPstatuscodestatusText,astatusmessage,whichis OKiftherequestsucceeded

responsealsohasa json()method,whichreturnsapromisethatwillresolvewiththecontentofthebodyprocessedandtransformedintoJSON.

Promises

123

Sogiventhosepremises,thisiswhathappens:thefirstpromiseinthechainisafunctionthatwedefined,called status(),thatcheckstheresponsestatusandifit'snotasuccessresponse(between200and299),itrejectsthepromise.

Thisoperationwillcausethepromisechaintoskipallthechainedpromiseslistedandwillskipdirectlytothe catch()statementatthebottom,loggingthe Requestfailedtextalongwiththeerrormessage.

Ifthatsucceedsinstead,itcallsthejson()functionwedefined.Sincethepreviouspromise,whensuccessful,returnedthe responseobject,wegetitasaninputtothesecondpromise.

Inthiscase,wereturnthedataJSONprocessed,sothethirdpromisereceivestheJSONdirectly:

.then((data)=>{

console.log('RequestsucceededwithJSONresponse',data)

})

andwesimplylogittotheconsole.

HandlingerrorsIntheexample,intheprevioussection,wehada catchthatwasappendedtothechainofpromises.

Whenanythinginthechainofpromisesfailsandraisesanerrororrejectsthepromise,thecontrolgoestothenearest catch()statementdownthechain.

newPromise((resolve,reject)=>{

thrownewError('Error')

})

.catch((err)=>{console.error(err)})

//or

newPromise((resolve,reject)=>{

reject('Error')

})

.catch((err)=>{console.error(err)})

Cascadingerrors

Ifinsidethe catch()youraiseanerror,youcanappendasecond catch()tohandleit,andsoon.

Promises

124

newPromise((resolve,reject)=>{

thrownewError('Error')

})

.catch((err)=>{thrownewError('Error')})

.catch((err)=>{console.error(err)})

Orchestratingpromises

Promise.all()

Ifyouneedtosynchronizedifferentpromises, Promise.all()helpsyoudefinealistofpromises,andexecutesomethingwhentheyareallresolved.

Example:

constf1=fetch('/something.json')

constf2=fetch('/something2.json')

Promise.all([f1,f2]).then((res)=>{

console.log('Arrayofresults',res)

})

.catch((err)=>{

console.error(err)

})

TheES2015destructuringassignmentsyntaxallowsyoutoalsodo

Promise.all([f1,f2]).then(([res1,res2])=>{

console.log('Results',res1,res2)

})

Youarenotlimitedtousing fetchofcourse,anypromiseisgoodtogo.

Promise.race()

Promise.race()runswhenthefirstofthepromisesyoupasstoitresolves,anditrunstheattachedcallbackjustonce,withtheresultofthefirstpromiseresolved.

Example:

constfirst=newPromise((resolve,reject)=>{

setTimeout(resolve,500,'first')

})

constsecond=newPromise((resolve,reject)=>{

Promises

125

setTimeout(resolve,100,'second')

})

Promise.race([first,second]).then((result)=>{

console.log(result)//second

})

Commonerrors

UncaughtTypeError:undefinedisnotapromise

Ifyougetthe UncaughtTypeError:undefinedisnotapromiseerrorintheconsole,makesureyouuse newPromise()insteadofjust Promise()

Promises

126

AsyncandAwaitDiscoverthemodernapproachtoasynchronousfunctionsinJavaScript.JavaScriptevolvedinaveryshorttimefromcallbackstoPromises,andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax

IntroductionJavaScriptevolvedinaveryshorttimefromcallbackstopromises(ES2015),andsinceES2017asynchronousJavaScriptisevensimplerwiththeasync/awaitsyntax.

Asyncfunctionsareacombinationofpromisesandgenerators,andbasically,theyareahigherlevelabstractionoverpromises.Letmerepeat:async/awaitisbuiltonpromises.

Whywereasync/awaitintroduced?Theyreducetheboilerplatearoundpromises,andthe"don'tbreakthechain"limitationofchainingpromises.

WhenPromiseswereintroducedinES2015,theyweremeanttosolveaproblemwithasynchronouscode,andtheydid,butoverthe2yearsthatseparatedES2015andES2017,itwasclearthatpromisescouldnotbethefinalsolution.

Promiseswereintroducedtosolvethefamouscallbackhellproblem,buttheyintroducedcomplexityontheirown,andsyntaxcomplexity.

Theyweregoodprimitivesaroundwhichabettersyntaxcouldbeexposedtothedevelopers,sowhenthetimewasrightwegotasyncfunctions.

Theymakethecodelooklikeit'ssynchronous,butit'sasynchronousandnon-blockingbehindthescenes.

HowitworksAnasyncfunctionreturnsapromise,likeinthisexample:

constdoSomethingAsync=()=>{

returnnewPromise((resolve)=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

AsyncandAwait

127

}

Whenyouwanttocallthisfunctionyouprepend await,andthecallingcodewillstopuntilthepromiseisresolvedorrejected.Onecaveat:theclientfunctionmustbedefinedasasync.Here'sanexample:

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

AquickexampleThisisasimpleexampleofasync/awaitusedtorunafunctionasynchronously:

constdoSomethingAsync=()=>{

returnnewPromise((resolve)=>{

setTimeout(()=>resolve('Ididsomething'),3000)

})

}

constdoSomething=async()=>{

console.log(awaitdoSomethingAsync())

}

console.log('Before')

doSomething()

console.log('After')

Theabovecodewillprintthefollowingtothebrowserconsole:

Before

After

Ididsomething//after3s

PromiseallthethingsPrependingthe asynckeywordtoanyfunctionmeansthatthefunctionwillreturnapromise.

Evenifit'snotdoingsoexplicitly,itwillinternallymakeitreturnapromise.

Thisiswhythiscodeisvalid:

constaFunction=async()=>{

return'test'

}

AsyncandAwait

128

aFunction().then(alert)//Thiswillalert'test'

andit'sthesameas:

constaFunction=async()=>{

returnPromise.resolve('test')

}

aFunction().then(alert)//Thiswillalert'test'

ThecodeismuchsimplertoreadAsyoucanseeintheexampleabove,ourcodelooksverysimple.Compareittocodeusingplainpromises,withchainingandcallbackfunctions.

Andthisisaverysimpleexample,themajorbenefitswillarisewhenthecodeismuchmorecomplex.

Forexamplehere'showyouwouldgetaJSONresource,andparseit,usingpromises:

constgetFirstUserData=()=>{

returnfetch('/users.json')//getuserslist

.then(response=>response.json())//parseJSON

.then(users=>users[0])//pickfirstuser

.then(user=>fetch(`/users/${user.name}`))//getuserdata

.then(userResponse=>response.json())//parseJSON

}

getFirstUserData()

Andhereisthesamefunctionalityprovidedusingawait/async:

constgetFirstUserData=async()=>{

constresponse=awaitfetch('/users.json')//getuserslist

constusers=awaitresponse.json()//parseJSON

constuser=users[0]//pickfirstuser

constuserResponse=awaitfetch(`/users/${user.name}`)//getuserdata

constuserData=awaituser.json()//parseJSON

returnuserData

}

getFirstUserData()

Multipleasyncfunctionsinseries

AsyncandAwait

129

Asyncfunctionscanbechainedveryeasily,andthesyntaxismuchmorereadablethanwithplainpromises:

constpromiseToDoSomething=()=>{

returnnewPromise(resolve=>{

setTimeout(()=>resolve('Ididsomething'),10000)

})

}

constwatchOverSomeoneDoingSomething=async()=>{

constsomething=awaitpromiseToDoSomething()

returnsomething+'andIwatched'

}

constwatchOverSomeoneWatchingSomeoneDoingSomething=async()=>{

constsomething=awaitwatchOverSomeoneDoingSomething()

returnsomething+'andIwatchedaswell'

}

watchOverSomeoneWatchingSomeoneDoingSomething().then((res)=>{

console.log(res)

})

Willprint:

IdidsomethingandIwatchedandIwatchedaswell

EasierdebuggingDebuggingpromisesishardbecausethedebuggerwillnotstepoverasynchronouscode.

Async/awaitmakesthisveryeasybecausetothecompilerit'sjustlikesynchronouscode.

AsyncandAwait

130

LoopsandScopeThereisonefeatureofJavaScriptthatmightcauseafewheadachestodevelopers,relatedtoloopsandscoping.Learnsometricksaboutloopsandscopingwithvarandlet

ThereisonefeatureofJavaScriptthatmightcauseafewheadachestodevelopers,relatedtoloopsandscoping.

Takethisexample:

constoperations=[]

for(vari=0;i<5;i++){

operations.push(()=>{

console.log(i)

})

}

for(constoperationofoperations){

operation()

}

Itbasicallyiteratesandfor5timesitaddsafunctiontoanarraycalledoperations.Thisfunctionsimplyconsolelogstheloopindexvariable i.

Lateritrunsthesefunctions.

Theexpectedresulthereshouldbe:

0

1

2

3

4

butactuallywhathappensisthis:

5

5

5

5

5

Whyisthisthecase?Becauseoftheuseof var.

Since vardeclarationsarehoisted,theabovecodeequalsto

LoopsandScope

131

vari;

constoperations=[]

for(i=0;i<5;i++){

operations.push(()=>{

console.log(i)

})

}

for(constoperationofoperations){

operation()

}

so,inthefor-ofloop, iisstillvisible,it'sequalto5andeveryreferenceto iinthefunctionisgoingtousethisvalue.

Sohowshouldwedotomakethingsworkaswewant?

Thesimplestsolutionistouse letdeclarations.IntroducedinES2015,theyareagreathelpinavoidingsomeoftheweirdthingsabout vardeclarations.

Simplychanging varto letintheloopvariableisgoingtoworkfine:

constoperations=[]

for(leti=0;i<5;i++){

operations.push(()=>{

console.log(i)

})

}

for(constoperationofoperations){

operation()

}

Here'stheoutput:

0

1

2

3

4

Howisthispossible?Thisworksbecauseoneveryloopiteration iiscreatedasanewvariableeachtime,andeveryfunctionaddedtothe operationsarraygetsitsowncopyof i.

Keepinmindyoucannotuse constinthiscase,becausetherewouldbeanerroras fortriestoassignanewvalueintheseconditeration.

LoopsandScope

132

Anotherwaytosolvethisproblemwasverycommoninpre-ES6code,anditiscalledImmediatelyInvokedFunctionExpression(IIFE).

Inthiscaseyoucanwraptheentirefunctionandbind itoit.Sinceinthiswayyou'recreatingafunctionthatimmediatelyexecutes,youreturnanewfunctionfromit,sowecanexecuteitlater:

constoperations=[]

for(vari=0;i<5;i++){

operations.push(((j)=>{

return()=>console.log(j)

})(i))

}

for(constoperationofoperations){

operation()

}

LoopsandScope

133

TimersWhenwritingJavaScriptcode,youmightwanttodelaytheexecutionofafunction.LearnhowtousesetTimeoutandsetIntervaltoschedulefunctionsinthefuture

setTimeout()

WhenwritingJavaScriptcode,youmightwanttodelaytheexecutionofafunction.

Thisisthejobof setTimeout.Youspecifyacallbackfunctiontoexecutelater,andavalueexpressinghowlateryouwantittorun,inmilliseconds:

setTimeout(()=>{

//runsafter2seconds

},2000)

setTimeout(()=>{

//runsafter50milliseconds

},50)

Thissyntaxdefinesanewfunction.Youcancallwhateverotherfunctionyouwantinthere,oryoucanpassanexistingfunctionname,andasetofparameters:

constmyFunction=(firstParam,secondParam)=>{

//dosomething

}

//runsafter2seconds

setTimeout(myFunction,2000,firstParam,secondParam)

Timers

134

setTimeoutreturnsthetimerid.Thisisgenerallynotused,butyoucanstorethisid,andclearitifyouwanttodeletethisscheduledfunctionexecution:

constid=setTimeout(()=>{

//shouldrunafter2seconds

},2000)

//Ichangedmymind

clearTimeout(id)

Zerodelay

Ifyouspecifythetimeoutdelayto 0,thecallbackfunctionwillbeexecutedassoonaspossible,butafterthecurrentfunctionexecution:

setTimeout(()=>{

console.log('after')

},0)

console.log('before')

willprint beforeafter.

ThisisespeciallyusefultoavoidblockingtheCPUonintensivetasksandletotherfunctionsbeexecutedwhileperformingaheavycalculation,byqueuingfunctionsinthescheduler.

Somebrowsers(IEandEdge)implementa setImmediate()methodthatdoesthissameexactfunctionality,butit'snotstandardandunavailableonotherbrowsers.Butit'sastandardfunctioninNode.js.

setInterval()

setIntervalisafunctionsimilarto setTimeout,withadifference:insteadofrunningthecallbackfunctiononce,itwillrunitforever,atthespecifictimeintervalyouspecify(inmilliseconds):

setInterval(()=>{

//runsevery2seconds

},2000)

Thefunctionaboverunsevery2secondsunlessyoutellittostop,using clearInterval,passingittheintervalidthat setIntervalreturned:

constid=setInterval(()=>{

Timers

135

//runsevery2seconds

},2000)

clearInterval(id)

It'scommontocall clearIntervalinsidethesetIntervalcallbackfunction,toletitauto-determineifitshouldrunagainorstop.ForexamplethiscoderunssomethingunlessApp.somethingIWaithasthevalue arrived:

constinterval=setInterval(()=>{

if(App.somethingIWait==='arrived'){

clearInterval(interval)

return

}

//otherwisedothings

},100)

RecursivesetTimeoutsetIntervalstartsafunctioneverynmilliseconds,withoutanyconsiderationaboutwhenafunctionfinisheditsexecution.

Ifafunctiontakesalwaysthesameamountoftime,it'sallfine:

Maybethefunctiontakesdifferentexecutiontimes,dependingonnetworkconditionsforexample:

Andmaybeonelongexecutionoverlapsthenextone:

Toavoidthis,youcanschedulearecursivesetTimeouttobecalledwhenthecallbackfunctionfinishes:

Timers

136

constmyFunction=()=>{

//dosomething

setTimeout(myFunction,1000)

}

setTimeout(

myFunction()

},1000)

toachievethisscenario:

setTimeoutand setIntervalareavailableinNode.js,throughtheTimersmodule.

Node.jsalsoprovides setImmediate(),whichisequivalenttousing setTimeout(()=>{},0),mostlyusedtoworkwiththeNode.jsEventLoop.

Timers

137

this`this`isavaluethathasdifferentvaluesdependingonwhereit'sused.NotknowingthistinydetailofJavaScriptcancausealotofheadaches,soit'sworthtaking5minutestolearnallthetricks

thisisavaluethathasdifferentvaluesdependingonwhereit'sused.

NotknowingthistinydetailofJavaScriptcancausealotofheadaches,soit'sworthtaking5minutestolearnallthetricks.

thisinstrictmodeOutsideanyobject, thisinstrictmodeisalways undefined.

NoticeImentionedstrictmode.Ifstrictmodeisdisabled(thedefaultstateifyoudon'texplicitlyadd 'usestrict'ontopofyourfile),youareintheso-calledsloppymode,and this-unlesssomespecificcasesmentionedherebelow-hasthevalueoftheglobalobject.

Whichmeans windowinabrowsercontext.

thisinmethodsAmethodisafunctionattachedtoanobject.

Youcanseeitinvariousforms.

this

138

Here'sone:

constcar={

maker:'Ford',

model:'Fiesta',

drive(){

console.log(`Drivinga${this.maker}${this.model}car!`)

}

}

car.drive()

//DrivingaFordFiestacar!

Inthiscase,usingaregularfunction, thisisautomaticallyboundtotheobject.

Note:theabovemethoddeclarationisthesameas drive:function(){...,butshorter:

constcar={

maker:'Ford',

model:'Fiesta',

drive:function(){

console.log(`Drivinga${this.maker}${this.model}car!`)

}

}

Thesameworksinthisexample:

constcar={

maker:'Ford',

model:'Fiesta'

}

car.drive=function(){

console.log(`Drivinga${this.maker}${this.model}car!`)

}

car.drive()

//DrivingaFordFiestacar!

Anarrowfunctiondoesnotworkinthesameway,asit'slexicallybound:

constcar={

maker:'Ford',

model:'Fiesta',

drive:()=>{

console.log(`Drivinga${this.maker}${this.model}car!`)

}

}

this

139

car.drive()

//Drivingaundefinedundefinedcar!

BindingarrowfunctionsYoucannotbindavaluetoanarrowfunction,likeyoudowithnormalfunctions.

It'ssimplynotpossibleduetothewaytheywork. thisislexicallybound,whichmeansitsvalueisderivedfromthecontextwheretheyaredefined.

Explicitlypassanobjecttobeusedas thisJavaScriptoffersafewwaystomap thistoanyobjectyouwant.

Using bind(),atthefunctiondeclarationstep:

constcar={

maker:'Ford',

model:'Fiesta'

}

constdrive=function(){

console.log(`Drivinga${this.maker}${this.model}car!`)

}.bind(car)

drive()

//DrivingaFordFiestacar!

Youcouldalsobindanexistingobjectmethodtoremapits thisvalue:

constcar={

maker:'Ford',

model:'Fiesta',

drive(){

console.log(`Drivinga${this.maker}${this.model}car!`)

}

}

constanotherCar={

maker:'Audi',

model:'A4'

}

car.drive.bind(anotherCar)()

//DrivingaAudiA4car!

this

140

Using call()or apply(),atthefunctioninvocationstep:

constcar={

maker:'Ford',

model:'Fiesta'

}

constdrive=function(kmh){

console.log(`Drivinga${this.maker}${this.model}carat${kmh}km/h!`)

}

drive.call(car,100)

//DrivingaFordFiestacarat100km/h!

drive.apply(car,[100])

//DrivingaFordFiestacarat100km/h!

Thefirstparameteryoupassto call()or apply()isalwaysboundto this.Thedifferencebetweencall()andapply()isjustthatthesecondonewantsanarrayastheargumentslist,whilethefirstacceptsavariablenumberofparameters,whichpassesasfunctionarguments.

ThespecialcaseofbrowsereventhandlersIneventhandlerscallbacks, thisreferstotheHTMLelementthatreceivedtheevent:

document.querySelector('#button').addEventListener('click',function(e){

console.log(this)//HTMLElement

}

Youcanbinditusing

document.querySelector('#button').addEventListener(

'click',

function(e){

console.log(this)//Windowifglobal,oryourcontext

}.bind(this)

)

this

141

StrictModeStrictModeisanES5feature,andit'sawaytomakeJavaScriptbehaveinabetterway.Andinadifferentway,asenablingStrictModechangesthesemanticsoftheJavaScriptlanguage.It'sreallyimportanttoknowthemaindifferencesbetweenJavaScriptcodeinstrictmode,andnormalJavaScript,whichisoftenreferredassloppymode

StrictModeisanES5feature,andit'sawaytomakeJavaScriptbehaveinabetterway.

Andinadifferentway,asenablingStrictModechangesthesemanticsoftheJavaScriptlanguage.

It'sreallyimportanttoknowthemaindifferencesbetweenJavaScriptcodeinstrictmode,and"normal"JavaScript,whichisoftenreferredassloppymode.

StrictModemostlyremovesfunctionalitythatwaspossibleinES3,anddeprecatedsinceES5(butnotremovedbecauseofbackwardscompatibilityrequirements)

HowtoenableStrictMode

StrictMode

142

Strictmodeisoptional.AswitheverybreakingchangeinJavaScript,wecan'tsimplychangehowthelanguagebehavesbydefault,becausethatwouldbreakgazillionsofJavaScriptaround,andJavaScriptputsalotofeffortintomakingsure1996JavaScriptcodestillworkstoday.It'sakeyofitssuccess.

Sowehavethe 'usestrict'directiveweneedtousetoenableStrictMode.

Youcanputitatthebeginningofafile,toapplyittoallthecodecontainedinthefile:

'usestrict'

constname='Flavio'

consthello=()=>'hey'

//...

YoucanalsoenableStrictModeforanindividualfunction,byputting 'usestrict'atthebeginningofthefunctionbody:

functionhello(){

'usestrict'

return'hey'

}

Thisisusefulwhenoperatingonlegacycode,whereyoudon'thavethetimetotestortheconfidencetoenablestrictmodeonthewholefile.

WhatchangesinStrictMode

Accidentalglobalvariables

Ifyouassignavaluetoanundeclaredvariable,JavaScriptbydefaultcreatesthatvariableontheglobalobject:

;(function(){

variable='hey'

})()(()=>{

name='Flavio'

})()

variable//'hey'

name//'Flavio'

TurningonStrictMode,anerrorisraisedifyoutrytodowhatwedidabove:

StrictMode

143

;(function(){

'usestrict'

variable='hey'

})()(()=>{

'usestrict'

myname='Flavio'

})()

Assignmenterrors

JavaScriptsilentlyfailssomeconversionerrors.

InStrictMode,thosesilenterrorsnowraiseissues:

constundefined=1(()=>{

'usestrict'

undefined=1

})()

StrictMode

144

ThesameappliestoInfinity,NaN, eval, argumentsandmore.

InJavaScriptyoucandefineapropertyofanobjecttobenotwritable,byusing

constcar={}

Object.defineProperty(car,'color',{value:'blue',writable:false})

Instrictmode,youcan'toverridethisvalue,whileinsloppymodethat'spossible:

Thesameworksforgetters:

constcar={

getcolor(){

return'blue'

}

}

car.color='red'(

//ok

()=>{

'usestrict'

StrictMode

145

car.color='yellow'//TypeError:Cannotsetpropertycolorof#<Object>whichhasonl

yagetter

}

)()

Sloppymodeallowstoextendanon-extensibleobject:

constcar={color:'blue'}

Object.preventExtensions(car)

car.model='Fiesta'(

//ok

()=>{

'usestrict'

car.owner='Flavio'//TypeError:Cannotaddpropertyowner,objectisnotextensible

}

)()

Also,sloppymodeallowstosetpropertiesonprimitivevalues,withoutfailing,butalsowithoutdoingnothingatall:

true.false=''(

//''

1

).name=

'xxx'//'xxx'

vartest='test'//undefined

test.testing=true//true

test.testing//undefined

Strictmodefailsinallthosecases:

;(()=>{

'usestrict'

true.false=''(

//TypeError:Cannotcreateproperty'false'onboolean'true'

1

).name=

'xxx'//TypeError:Cannotcreateproperty'name'onnumber'1'

'test'.testing=true//TypeError:Cannotcreateproperty'testing'onstring'test'

})()

Deletionerrors

Insloppymode,ifyoutrytodeleteapropertythatyoucannotdelete,JavaScriptsimplyreturnsfalse,whileinStrictMode,itraisesaTypeError:

deleteObject.prototype(

StrictMode

146

//false

()=>{

'usestrict'

deleteObject.prototype//TypeError:Cannotdeleteproperty'prototype'offunctionOb

ject(){[nativecode]}

}

)()

Functionargumentswiththesamename

Innormalfunctions,youcanhaveduplicateparameternames:

(function(a,a,b){

console.log(a,b)

})(1,2,3)

//23

(function(a,a,b){

'usestrict'

console.log(a,b)

})(1,2,3)

//UncaughtSyntaxError:Duplicateparameternamenotallowedinthiscontext

Notethatarrowfunctionsalwaysraisea SyntaxErrorinthiscase:

((a,a,b)=>{

console.log(a,b)

})(1,2,3)

//UncaughtSyntaxError:Duplicateparameternamenotallowedinthiscontext

Octalsyntax

OctalsyntaxinStrictModeisdisabled.Bydefault,prependinga 0toanumbercompatiblewiththeoctalnumericformatmakesit(sometimesconfusingly)interpretedasanoctalnumber:

(()=>{

console.log(010)

})()

//8

(()=>{

'usestrict'

console.log(010)

})()

//UncaughtSyntaxError:Octalliteralsarenotallowedinstrictmode.

StrictMode

147

YoucanstillenableoctalnumbersinStrictModeusingthe 0oXXsyntax:

;(()=>{

'usestrict'

console.log(0o10)

})()

//8

Removed with

StrictModedisablesthe withkeyword,toremovesomeedgecasesandallowmoreoptimizationatthecompilerlevel.

StrictMode

148

Immediately-invokedFunctionExpressions(IIFE)AnImmediately-invokedFunctionExpressionisawaytoexecutefunctionsimmediately,assoonastheyarecreated.IIFEsareveryusefulbecausetheydon'tpollutetheglobalobject,andtheyareasimplewaytoisolatevariablesdeclarations

AnImmediately-invokedFunctionExpression(IIFEforfriends)isawaytoexecutefunctionsimmediately,assoonastheyarecreated.

IIFEsareveryusefulbecausetheydon'tpollutetheglobalobject,andtheyareasimplewaytoisolatevariablesdeclarations.

ThisisthesyntaxthatdefinesanIIFE:

;(function(){

/**/

})()

IIFEscanbedefinedwitharrowfunctionsaswell:

Immediately-invokedFunctionExpressions(IIFE)

149

;(()=>{

/**/

})()

Webasicallyhaveafunctiondefinedinsideparentheses,andthenweappend ()toexecutethatfunction: (https://flaviocopes.com/*function*/)().

Thosewrappingparenthesesareactuallywhatmakeourfunction,internally,beconsideredanexpression.Otherwise,thefunctiondeclarationwouldbeinvalid,becausewedidn'tspecifyanyname:

Functiondeclarationswantaname,whilefunctionexpressionsdonotrequireit.

Youcouldalsoputtheinvokingparenthesesinsidetheexpressionparentheses,thereisnodifference,justastylingpreference:

(function(){

/**/

}())

(()=>{

/**/

}())

AlternativesyntaxusingunaryoperatorsThereissomeweirdersyntaxthatyoucanusetocreateanIIFE,butit'sveryrarelyusedintherealworld,anditreliesonusinganyunaryoperator:

;-(function(){

/**/

})()+

(function(){

/**/

})()

Immediately-invokedFunctionExpressions(IIFE)

150

~(function(){

/**/

})()

!(function(){

/**/

})()

(doesnotworkwitharrowfunctions)

NamedIIFEAnIIFEcanalsobenamedregularfunctions(notarrowfunctions).Thisdoesnotchangethefactthatthefunctiondoesnot"leak"totheglobalscope,anditcannotbeinvokedagainafteritsexecution:

;(functiondoSomething(){

/**/

})()

IIFEsstartingwithasemicolonYoumightseethisinthewild:

;(function(){

/**/

})()

ThispreventsissueswhenblindlyconcatenatingtwoJavaScriptfiles.SinceJavaScriptdoesnotrequiresemicolons,youmightconcatenatewithafilewithsomestatementsinitslastlinethatcausesasyntaxerror.

Thisproblemisessentiallysolvedwith"smart"codebundlerslikewebpack.

Immediately-invokedFunctionExpressions(IIFE)

151

MathoperatorsPerformingmathoperationsandcalculusisaverycommonthingtodowithanyprogramminglanguage.JavaScriptoffersseveraloperatorstohelpusworkwithnumbers

Performingmathoperationsandcalculusisaverycommonthingtodowithanyprogramminglanguage.

JavaScriptoffersseveraloperatorstohelpusworkwithnumbers.

Operators

Arithmeticoperators

Addition(+)

constthree=1+2

constfour=three+1

The +operatoralsoservesasstringconcatenationifyouusestrings,sopayattention:

constthree=1+2

three+1//4

'three'+1//three1

Subtraction(-)

consttwo=4-2

Division(https://flaviocopes.com/)

Returnsthequotientofthefirstoperatorandthesecond:

constresult=20/5//result===4

constresult=20/7//result===2.857142857142857

Ifyoudividebyzero,JavaScriptdoesnotraiseanyerrorbutreturnsthe Infinityvalue(or -Infinityifthevalueisnegative).

Mathoperators

152

1/0//Infinity

-1/0//-Infinity

Remainder(%)

Theremainderisaveryusefulcalculationinmanyusecases:

constresult=20%5//result===0

constresult=20%7//result===6

Areminderbyzeroisalways NaN,aspecialvaluethatmeans"NotaNumber":

1%0//NaN

-1%0//NaN

Multiplication(*)

1*2//2

-1*2//-2

Exponentiation(**)

Raisethefirstoperandtothepowersecondoperand

1**2//1

2**1//2

2**2//4

2**8//256

8**2//64

Unaryoperators

Increment(++)

Incrementanumber.Thisisaunaryoperator,andifputbeforethenumber,itreturnsthevalueincremented.

Ifputafterthenumber,itreturnstheoriginalvalue,thenincrementsit.

letx=0

x++//0

x//1

++x//2

Mathoperators

153

Decrement(--)

Worksliketheincrementoperator,exceptitdecrementsthevalue.

letx=0

x--//0

x//-1

--x//-2

Unarynegation(-)

Returnthenegationoftheoperand

letx=2

-x//-2

x//2

Unaryplus(+)

Iftheoperandisnotanumber,ittriestoconvertit.Otherwiseiftheoperandisalreadyanumber,itdoesnothing.

letx=2

+x//2

x='2'

+x//2

x='2a'

+x//NaN

AssignmentshortcutsTheregularassignmentoperator, =,hasseveralshortcutsforallthearithmeticoperatorswhichletyoucombineassignment,assigningtothefirstoperandtheresultoftheoperationswiththesecondoperand.

Theyare:

+=:additionassignment-=:subtractionassignment*=:multiplicationassignment

Mathoperators

154

/=:divisionassignment%=:remainderassignment**=:exponentiationassignment

Examples:

consta=0

a+=5//a===5

a-=2//a===3

a*=2//a===6

a/=2//a===3

a%=2//a===1

PrecedencerulesEverycomplexstatementwillintroduceprecedenceproblems.

Takethis:

consta=1*2+5/2%2

Theresultis2.5,butwhy?Whatoperationsareexecutedfirst,andwhichneedtowait?

Someoperationshavemoreprecedencethantheothers.Theprecedencerulesarelistedinthistable:

Operator Description

- + ++ -- unaryoperators,incrementanddecrement

* / % multiply/divide

+ - addition/subtraction

= += -= *= /= %= **= assignments

Operationsonthesamelevel(like +and -)areexecutedintheordertheyarefound

Followingthistable,wecansolvethiscalculation:

consta=1*2+5/2%2

consta=1*2+5/2%2

consta=2+2.5%2

consta=2+0.5

consta=2.5

Mathoperators

155

Mathoperators

156

TheMathobjectTheMathobjectcontainslotsofutilitiesmath-related.Thistutorialdescribesthemall

TheMathobjectcontainslotsofutilitiesmath-related.

Itcontainsconstantsandfunctions.

Constants

Item Description

Math.E Theconstante,baseofthenaturallogarithm(means~2.71828)

Math.LN10 Theconstantthatrepresentsthebasee(natural)logarithmof10

Math.LN2 Theconstantthatrepresentsthebasee(natural)logarithmof2

Math.LOG10E Theconstantthatrepresentsthebase10logarithmofe

Math.LOG2E Theconstantthatrepresentsthebase2logarithmofe

Math.PI Theπconstant(~3.14159)

Math.SQRT1_2 Theconstantthatrepresentsthereciprocalofthesquarerootof2

Math.SQRT2 Theconstantthatrepresentsthesquarerootof2

FunctionsAllthosefunctionsarestatic.Mathcannotbeinstantiated.

Math.abs()

Returnstheabsolutevalueofanumber

Math.abs(2.5)//2.5

Math.abs(-2.5)//2.5

Math.acos()

Returnsthearccosineoftheoperand

Theoperandmustbebetween-1and1

TheMathobject

157

Math.acos(0.8)//0.6435011087932843

Math.asin()

Returnsthearcsineoftheoperand

Theoperandmustbebetween-1and1

Math.asin(0.8)//0.9272952180016123

Math.atan()

Returnsthearctangentoftheoperand

Math.atan(30)//1.5374753309166493

Math.atan2()

Returnsthearctangentofthequotientofitsarguments.

Math.atan2(30,20)//0.982793723247329

Math.ceil()

Roundsanumberup

Math.ceil(2.5)//3

Math.ceil(2)//2

Math.ceil(2.1)//3

Math.ceil(2.99999)//3

Math.cos()

Returnthecosineofanangleexpressedinradiants

Math.cos(0)//1

Math.cos(Math.PI)//-1

Math.exp()

ReturnthevalueofMath.Emultipliedpertheexponentthat'spassedasargument

TheMathobject

158

Math.exp(1)//2.718281828459045

Math.exp(2)//7.38905609893065

Math.exp(5)//148.4131591025766

Math.floor()

Roundsanumberdown

Math.ceil(2.5)//2

Math.ceil(2)//2

Math.ceil(2.1)//2

Math.ceil(2.99999)//2

Math.log()

Returnthebasee(natural)logarithmofanumber

Math.log(10)//2.302585092994046

Math.log(Math.E)//1

Math.max()

Returnthehighestnumberinthesetofnumberspassed

Math.max(1,2,3,4,5)//5

Math.max(1)//1

Math.min()

Returnthesmallestnumberinthesetofnumberspassed

Math.max(1,2,3,4,5)//1

Math.max(1)//1

Math.pow()

Returnthefirstargumentraisedtothesecondargument

Math.pow(1,2)//1

Math.pow(2,1)//2

Math.pow(2,2)//4

Math.pow(2,4)//16

TheMathobject

159

Math.random()

Returnsapseudorandomnumberbetween0.0and1.0

Math.random()//0.9318168241227056

Math.random()//0.35268950194094395

Math.round()

Roundsanumbertothenearestinteger

Math.round(1.2)//1

Math.round(1.6)//2

Math.sin()

Calculatesthesinofanangleexpressedinradiants

Math.sin(0)//0

Math.sin(Math.PI)//1.2246467991473532e-16)

Math.sqrt()

Returnthesquarerootoftheargument

Math.sqrt(4)//2

Math.sqrt(16)//4

Math.sqrt(5)//2.23606797749979

Math.tan()

Calculatesthetangentofanangleexpressedinradiants

Math.tan(0)//0

Math.tan(Math.PI)//-1.2246467991473532e-16

TheMathobject

160

ESModulesESModulesistheECMAScriptstandardforworkingwithmodules.WhileNode.jshasbeenusingtheCommonJSstandardsinceyears,thebrowserneverhadamodulesystem,aseverymajordecisionsuchasamodulesystemmustbefirststandardizedbyECMAScriptandthenimplemented

IntroductiontoESModulesESModulesistheECMAScriptstandardforworkingwithmodules.

WhileNode.jshasbeenusingtheCommonJSstandardsinceyears,thebrowserneverhadamodulesystem,aseverymajordecisionsuchasamodulesystemmustbefirststandardizedbyECMAScriptandthenimplementedbythebrowser.

ThisstandardizationprocesscompletedwithES6andbrowsersstartedimplementingthisstandardtryingtokeepeverythingwellaligned,workingallinthesameway,andnowESModulesaresupportedinChrome,Safari,EdgeandFirefox(sinceversion60).

ESModules

161

Modulesareverycool,becausetheyletyouencapsulateallsortsoffunctionality,andexposethisfunctionalitytootherJavaScriptfiles,aslibraries.

TheESModulesSyntaxThesyntaxtoimportamoduleis:

importpackagefrom'module-name'

whileCommonJSuses

constpackage=require('module-name')

AmoduleisaJavaScriptfilethatexportsoneormorevalue(objects,functionsorvariables),usingthe exportkeyword.Forexample,thismoduleexportsafunctionthatreturnsastringuppercase:

uppercase.js

exportdefaultstr=>str.toUpperCase()

ESModules

162

Inthisexample,themoduledefinesasingle,defaultexport,soitcanbeananonymousfunction.Otherwiseitwouldneedanametodistinguishitfromotherexports.

Now,anyotherJavaScriptmodulecanimportthefunctionalityofferedbyuppercase.jsbyimportingit.

AnHTMLpagecanaddamodulebyusinga <script>tagwiththespecial type="module"attribute:

<scripttype="module"src="index.js"></script>

Note:thismoduleimportbehaveslikea deferscriptload.SeeefficientlyloadJavaScriptwithdeferandasync

It'simportanttonotethatanyscriptloadedwith type="module"isloadedinstrictmode.

Inthisexample,the uppercase.jsmoduledefinesadefaultexport,sowhenweimportit,wecanassignitanameweprefer:

importtoUpperCasefrom'./uppercase.js'

andwecanuseit:

toUpperCase('test')//'TEST'

Youcanalsouseanabsolutepathforthemoduleimport,toreferencemodulesdefinedonanotherdomain:

importtoUpperCasefrom'https://flavio-es-modules-example.glitch.me/uppercase.js'

Thisisalsovalidimportsyntax:

import{foo}from'/uppercase.js'

import{foo}from'../uppercase.js'

Thisisnot:

import{foo}from'uppercase.js'

import{foo}from'utils/uppercase.js'

It'seitherabsolute,orhasa ./or /beforethename.

ESModules

163

Otherimport/exportoptionsWesawthisexampleabove:

exportdefaultstr=>str.toUpperCase()

Thiscreatesonedefaultexport.Inafilehoweveryoucanexportmorethanonething,byusingthissyntax:

consta=1

constb=2

constc=3

export{a,b,c}

Anothermodulecanimportallthoseexportsusing

import*from'module'

Youcanimportjustafewofthoseexports,usingthedestructuringassignment:

import{a}from'module'

import{a,b}from'module'

Youcanrenameanyimport,forconvenience,using as:

import{a,bastwo}from'module'

Youcanimportthedefaultexport,andanynon-defaultexportbyname,likeinthiscommonReactimport:

importReact,{Component}from'react'

YoucancheckanESModulesexampleonhttps://glitch.com/edit/#!/flavio-es-modules-example?path=index.html

CORS

ESModules

164

ModulesarefetchedusingCORS.Thismeansthatifyoureferencescriptsfromotherdomains,theymusthaveavalidCORSheaderthatallowscross-siteloading(like Access-Control-Allow-Origin:*)

Whataboutbrowsersthatdonotsupportmodules?Useacombinationof type="module"and nomodule:

<scripttype="module"src="module.js"></script>

<scriptnomodulesrc="fallback.js"></script>

ConclusionESModulesareoneofthebiggestfeaturesintroducedinmodernbrowsers.TheyarepartofES6buttheroadtoimplementthemhasbeenlong.

Wecannowusethem!Butwemustalsorememberthathavingmorethanafewmodulesisgoingtohaveaperformancehitonourpages,asit'sonemorestepthatthebrowsermustperformatruntime.

WebpackisprobablygoingtostillbeahugeplayerevenifESModuleslandinthebrowser,buthavingsuchafeaturedirectlybuiltinthelanguageishugeforaunificationofhowmodulesworkintheclient-sideandonNode.jsaswell.

ESModules

165

CommonJSTheCommonJSmodulespecificationisthestandardusedinNode.jsforworkingwithmodules.Modulesareverycool,becausetheyletyouencapsulateallsortsoffunctionality,andexposethisfunctionalitytootherJavaScriptfiles,aslibraries

TheCommonJSmodulespecificationisthestandardusedinNode.jsforworkingwithmodules.

Client-sideJavaScriptthatrunsinthebrowserusesanotherstandard,calledESModules

Modulesareverycool,becausetheyletyouencapsulateallsortsoffunctionality,andexposethisfunctionalitytootherJavaScriptfiles,aslibraries.Theyletyoucreateclearlyseparateandreusablesnippetsoffunctionality,eachtestableonitsown.

ThehugenpmecosystemisbuiltuponthisCommonJSformat.

Thesyntaxtoimportamoduleis:

constpackage=require('module-name')

CommonJS

166

InCommonJS,modulesareloadedsynchronously,andprocessedintheordertheJavaScriptruntimefindsthem.Thissystemwasbornwithserver-sideJavaScriptinmind,andisnotsuitablefortheclient-side(thisiswhyESModuleswereintroduced).

AJavaScriptfileisamodulewhenitexportsoneormoreofthesymbolsitdefines,beingthemvariables,functions,objects:

uppercase.js

exports.uppercase=str=>str.toUpperCase()

AnyJavaScriptfilecanimportandusethismodule:

constuppercaseModule=require('uppercase.js')

uppercaseModule.uppercase('test')

AsimpleexamplecanbefoundinthisGlitch.

Youcanexportmorethanonevalue:

exports.a=1

exports.b=2

exports.c=3

andimportthemindividuallyusingthedestructuringassignment:

const{a,b,c}=require('./uppercase.js')

orjustexportonevalueusing:

//file.js

module.exports=value

andimportitusing

constvalue=require('./file.js')

CommonJS

167

GlossaryAguidetoafewtermsusedinfrontenddevelopmentthatmightbealientoyou

AsynchronousCodeisasynchronouswhenyouinitiatesomething,forgetaboutit,andwhentheresultisreadyyougetitbackwithouthavingtowaitforit.ThetypicalexampleisanAJAXcall,whichmighttakeevensecondsandinthemeantimeyoucompleteotherstuff,andwhentheresponseisready,thecallbackfunctiongetscalled.Promisesandasync/awaitarethemodernwaytohandleasync.

BlockInJavaScriptablockisdelimitedcurlybraces( {}).An ifstatementcontainsablock,aforloopcontainsablock.

BlockScopingWithFunctionScoping,anyvariabledefinedinablockisvisibleandaccessiblefrominsidethewholeblock,butnotoutsideofit.

CallbackAcallbackisafunctionthat'sinvokedwhensomethinghappens.Aclickeventassociatedtoanelementhasacallbackfunctionthat'sinvokedwhentheuserclickstheelement.Afetchrequesthasacallbackthat'scalledwhentheresourceisdownloaded.

DeclarativeAdeclarativeapproachiswhenyoutellthemachinewhatyouneedtodo,andyouletitfigureoutthedetails.Reactisconsidereddeclarative,asyoureasonaboutabstractionsratherthaneditingtheDOMdirectly.Everyhighlevelprogramminglanguageismoredeclarativethana

Glossary

168

lowlevelprogramminglanguagelikeAssembler.JavaScriptismoredeclarativethanC.HTMLisdeclarative.

FallbackAfallbackisusedtoprovideagoodexperiencewhenauserhasn'taccesstoaparticularfunctionality.ForexampleauserthatbrowseswithJavaScriptdisabledshouldbeabletohaveafallbacktoaplainHTMLversionofthepage.OrforabrowserthathasnotimplementedanAPI,youshouldhaveafallbacktoavoidcompletelybreakingtheexperienceoftheuser.

FunctionScopingWithFunctionScoping,anyvariabledefinedinafunctionisvisibleandaccessiblefrominsidethewholefunction.

ImmutabilityAvariableisimmutablewhenitsvaluecannotchangeafterit'screated.Amutablevariablecanbechanged.Thesameappliestoobjectsandarrays.

LexicalScopingLexicalScopingisaparticularkindofscopingwherevariablesofaparentfunctionaremadeavailabletoinnerfunctionsaswell.Thescopeofaninnerfunctionalsoincludesthescopeofaparentfunction.

PolyfillApolyfillisawaytoprovidenewfunctionalityavailableinmodernJavaScriptoramodernbrowserAPItoolderbrowsers.Apolyfillisaparticularkindofshim.

PurefunctionAfunctionthathasnosideeffects(doesnotmodifyexternalresources),anditsoutputisonlydeterminedbythearguments.Youcouldcallthisfunction1Mtimes,andgiventhesamesetofarguments,theoutputwillalwaysbethesame.

Glossary

169

ReassignmentJavaScriptwith varand letdeclarationallowsyoutoreassignavariableindefinitely.Withconstdeclarationsyoueffectivelydeclareanimmutablevalueforstrings,integers,booleans,andanobjectthatcannotbereassigned(butyoucanstillmodifyitthroughitsmethods).

ScopeScopeisthesetofvariablesthat'svisibletoapartoftheprogram.

ScopingScopingisthesetofrulesthat'sdefinedinaprogramminglanguagetodeterminethevalueofavariable.

ShimAshimisalittlewrapperaroundafunctionality,orAPI.It'sgenerallyusedtoabstractsomething,pre-fillparametersoraddapolyfillforbrowsersthatdonotsupportsomefunctionality.Youcanconsideritlikeacompatibilitylayer.

SideeffectAsideeffectiswhenafunctioninteractswithsomeotherfunctionorobjectoutsideit.Interactionwiththenetworkorthefilesystem,orwiththeUI,areallsideeffects.

StateStateusuallycomesintoplaywhentalkingaboutComponents.Acomponentcanbestatefulifitmanagesitsowndata,orstatelessifitdoesn't.

StatefulAstatefulcomponent,functionorclassmanagesitsownstate(data).Itcouldstoreanarray,acounteroranythingelse.

Glossary

170

StatelessAstatelesscomponent,functionorclassisalsocalleddumbbecauseit'sincapableofhavingitsowndatatomakedecisions,soitsoutputorpresentationisentirelybasedonitsarguments.Thisimpliesthatpurefunctionsarestateless.

StrictmodeStrictmodeisanECMAScript5.1newfeature,whichcausestheJavaScriptruntimetocatchmoreerrors,butithelpsyouimprovetheJavaScriptcodebydenyingundeclaredvariablesandotherthingsthatmightcauseoverlookedissueslikeduplicatedobjectpropertiesandothersubtlethings.Hint:useit.Thealternativeis"sloppymode"whichisnotagoodthingevenlookingatthenamewegaveit.

TreeShakingTreeshakingmeansremoving"deadcode"fromthebundleyoushiptoyourusers.Ifyouaddsomecodethatyouneveruseinyourimportstatements,that'snotgoingtobesenttotheusersofyourapp,toreducefilesizeandloadingtime.

Glossary

171

top related