table of contentsedu-9.de/uploads/books/javascript-handbook.pdf · javascript is now also the...
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