TableofContents
Introduction
1.1
GettingStarted
1.2
WhyTypeScript
1.2.1
JavaScript
1.3
Awful
1.3.1
FutureJavaScriptNow
Classes
1.4
1.4.1
ClassesEmit
1.4.1.1
ClassesSuper
1.4.1.2
ClassesExtensibility
1.4.1.3
ArrowFunctions
1.4.2
RestParameters
1.4.3
let
1.4.4
const
1.4.5
Destructuring
1.4.6
for...of
1.4.7
Iterators
1.4.8
TemplateStrings
1.4.9
SpreadOperator
1.4.10
Enums
1.4.11
Promise
1.4.12
Generators
1.4.13
AsyncAwait
1.4.14
Project
1.5
CompilationContext
tsconfig.json
1.5.1
1.5.1.1
DeclarationSpaces
1.5.2
Modules
1.5.3
FileModuleDetails
1.5.3.1
globals.d.ts
1.5.3.2
2
Namespaces
1.5.4
NodeJSQuickStart
1.6
BrowserQuickStart
1.7
TypeScript'sTypeSystem
1.8
JSMigrationGuide
1.8.1
AmbientDeclarations
1.8.2
DeclarationFiles
1.8.2.1
Variables
1.8.2.2
Interfaces
1.8.2.3
lib.d.ts
1.8.3
Functions
1.8.4
TypeAssertion
1.8.5
Freshness
1.8.6
TypeGuard
1.8.7
StringLiteralType
1.8.8
Readonly
1.8.9
TypeInference
1.8.10
TypeCompatibility
1.8.11
DiscriminatedUnions
1.8.12
JSX
1.9
TIPs
1.10
QuickObjectReturn
1.10.1
StringBasedEnums
1.10.2
NominalTyping
1.10.3
StatefulFunctions
1.10.4
BindisBad
1.10.5
Currying
1.10.6
TypeInstantiation
1.10.7
LazyObjectLiteralInitialization
1.10.8
ClassesareUseful
1.10.9
AvoidExportDefault
1.10.10
LimitPropertySetters
1.10.11
nullisbad
1.10.12
outFilecaution
1.10.13
3
JQuerytips
1.10.14
staticconstructors
1.10.15
singletonpattern
1.10.16
Functionparameters
1.10.17
Truthy
1.10.18
StyleGuide
1.11
CommonErrors
1.12
TypeScriptCompilerInternals
1.13
Program
1.13.1
AST
1.13.2
TIP:VisitChildren
1.13.2.1
TIP:SyntaxKindenum
1.13.2.2
Trivia
1.13.2.3
Scanner
1.13.3
Parser
1.13.4
ParserFunctions
Binder
1.13.4.1
1.13.5
BinderFunctions
1.13.5.1
BinderDeclarations
1.13.5.2
BinderContainer
1.13.5.3
BinderSymbolTable
1.13.5.4
BinderErrorReporting
1.13.5.5
Checker
1.13.6
CheckerDiagnostics
1.13.6.1
CheckerErrorReporting
1.13.6.2
Emitter
1.13.7
EmitterFunctions
1.13.7.1
EmitterSourceMaps
1.13.7.2
Contributing
1.13.8
4
Introduction
TypeScriptDeepDive
I'vebeenlookingattheissuesthatturnupcommonlywhenpeoplestartusingTypeScript.
ThisisbasedonthelessonsfromStackOverflow/DefinitelyTypedandgeneralengagement
withtheTypeScriptcommunity.Youcanfollowforupdatesanddon'tforgetto★onGithub
GetStarted
Ifyouareheretoreadthebookonlinegetstarted.
OtherOptions
Youcanalsodownloadoneofthefollowing:
EPUBforiPad,iPhone,Mac
PDFforWindowsandothers
MOBIforKindle
SpecialThanks
Alltheamazingcontributors
Share
ShareURL: />
5
GettingStarted
GettingStartedwithTypeScript
TypeScriptVersion
GettingStartedWithTypeScript
TypeScriptcompilesintoJavaScript.JavaScriptiswhatyouareactuallygoingtoexecute
(eitherinthebrowserorontheserver).Soyouaregoingtoneedthefollowing:
TypeScriptcompiler(OSSavailableinsourceandonNPM)
ATypeScripteditor(youcanusenotepadifyouwantbutIusealm )
TypeScriptVersion
InsteadofusingthestableTypeScriptcompilerwewillbepresentingalotofnewstuffinthis
bookthatmaynotbeassociatedwithaversionnumberyet.Igenerallyrecommendpeople
tousethenightlyversionbecausethecompilertestsuiteonlycatchesmorebugsover
time.
Youcaninstallitonthecommandlineas
npminstall-gtypescript@next
6
GettingStarted
Andnowthecommandline tscwillbethelatestandgreatest.VariousIDEssupportittoo,
e.g.
almalwaysshipswiththelatestTypeScriptversion.
Youcanaskvscodetousethisversionbycreating .vscode/settings.jsonwiththe
followingcontents:
{
"typescript.tsdk":"./node_modules/typescript/lib"
}
TypeScriptdefinitions
TypeScripthasaconceptofadeclarationfileforexternalJavaScriptcodebases.High
qualityfilesexistfornearly90%ofthetopJavaScriptlibrariesoutthereinaprojectcalled
DefinitelyTyped.Youwillneed typingstogetthesedefintions.Don'tworry,wewillexplain
whatthismeanslater...justinstallfornow:
npminstall-gtypings
GettingtheSourceCode
Thesourceforthisbookisavailableinthebooksgithubrepository
mostofthecodesamplescan
becopiedintoalmandyoucanplaywiththemasis.Forcodesamplesthatneedadditional
setup(e.g.npmmodules),wewilllinkyoutothecodesamplebeforepresentingthecode.
e.g.
this/will/be/the/link/to/the/code.ts
//Thiswillbethecodeunderdiscussion
WithadevsetupoutofthewayletsjumpintoTypeScriptsyntax.
7
WhyTypeScript
WhyTypeScript
TherearetwomaingoalsofTypeScript:
ProvideanoptionaltypesystemforJavaScript.
ProvideplannedfeaturesfromfutureJavaScripteditionstocurrentJavaScriptengines
Thedesireforthesegoalsismotivatedbelow.
TheTypeScripttypesystem
Youmightbewondering"WhyaddtypestoJavaScript?"
Typeshaveprovenabilitytoenhancecodequalityandunderstandability.Largeteams
(google,microsoft,facebook)havecontinuallyarrivedatthisconclusion.Specifically:
Typesincreaseyouragilitywhendoingrefactoring.Itsbetterforthecompilertocatch
errorsthantohavethingsfailatruntime.
Typesareoneofthebestformsofdocumentationyoucanhave.Thefunctionsignature
isatheoremandthefunctionbodyistheproof.
Howevertypeshaveawayofbeingunnecessarilyceremonious.TypeScriptisvery
particularaboutkeepingthebarriertoentryaslowaspossible.Here'show:
YourJavaScriptisTypeScript
TypeScriptprovidescompiletimetypesafetyforyourJavaScriptcode.Thisisnosurprise
givenitsname.Thegreatthingisthatthetypesarecompletelyoptional.YourJavaScript
code .jsfilecanberenamedtoa .tsfileandTypeScriptwillstillgiveyoubackvalid
.jsequivalenttotheoriginalJavaScriptfile.TypeScriptisintentionallyandstrictlya
supersetofJavaScriptwithoptionalTypechecking.
TypescanbeImplicit
TypeScriptwilltrytoinferasmuchofthetypeinformationasitcaninordertogiveyoutype
safetywithminimalcostofproductivityduringcodedevelopment.Forexample,inthe
followingexampleTypeScriptwillknowthatfooisoftype numberbelowandwillgivean
erroronthesecondlineasshown:
8
WhyTypeScript
varfoo=123;
foo='456';//Error:cannotassign`string`to`number`
//Isfooanumberorastring?
Thistypeinferenceiswellmotivated.Ifyoudostufflikeshowninthisexample,then,inthe
restofyourcode,youcannotbecertainthat fooisa numberora string.Suchissues
turnupofteninlargemulti-filecodebases.Wewilldeepdiveintothetypeinferencerules
later.
TypescanbeExplicit
Aswe'vementionedbefore,TypeScriptwillinferasmuchasitcansafely,howeveryoucan
useannotationsto:
1. Helpalongthecompiler,andmoreimportantlydocumentstuffforthenextdeveloper
whohastoreadyourcode(thatmightbefutureyou!).
2. Enforcethatwhatthecompilersees,iswhatyouthoughtitshouldsee.Thatisyour
understandingofthecodematchesanalgorithmicanalysisofthecode(donebythe
compiler).
TypeScriptusespostfixtypeannotationspopularinotheroptionallyannotatedlanguages
(e.g.ActionScriptandF#).
varfoo:number=123;
Soifyoudosomethingwrongthecompilerwillerrore.g.:
varfoo:number='123';//Error:cannotassigna`string`toa`number`
WewilldiscussallthedetailsofalltheannotationsyntaxsupportedbyTypeScriptinalater
chapter.
Typesarestructural
Insomelanguages(specificallynominallytypedones)statictypingresultsinunnecessary
ceremonybecauseeventhoughyouknowthatthecodewillworkfinethelanguage
semanticsforceyoutocopystuffaround.ThisiswhystufflikeautomapperforC#isvitalfor
C#.InTypeScriptbecausewereallywantittobeeasyforJavaScriptdeveloperswitha
9
WhyTypeScript
minimumcognitiveoverload,typesarestructural.Thismeansthatducktypingisafirstclass
languageconstruct.Considerthefollowingexample.Thefunction iTakePoint2Dwillaccept
anythingthatcontainsallthethings( xand y)itexpects:
interfacePoint2D{
x:number;
y:number;
}
interfacePoint3D{
x:number;
y:number;
z:number;
}
varpoint2D:Point2D={x:0,y:10}
varpoint3D:Point3D={x:0,y:10,z:20}
functioniTakePoint2D(point:Point2D){/*dosomething*/}
iTakePoint2D(point2D);//exactmatchokay
iTakePoint2D(point3D);//extrainformationokay
iTakePoint2D({x:0});//Error:missinginformation`y`
TypeerrorsdonotpreventJavaScriptemit
TomakeiteasyforyoutomigrateyourJavaScriptcodetoTypeScript,evenifthereare
compilationerrors,bydefaultTypeScriptwillemitvalidJavaScriptthebestthatitcan.e.g.
varfoo=123;
foo='456';//Error:cannotassigna`string`toa`number`
willemitthefollowingjs:
varfoo=123;
foo='456';
SoyoucanincrementallyupgradeyourJavaScriptcodetoTypeScript.Thisisverydifferent
fromhowmanyotherlanguagecompilersworkandyetanotherreasontomoveto
TypeScript.
Typescanbeambient
AmajordesigngoalofTypeScriptwastomakeitpossibleforyoutosafelyandeasilyuse
existingJavaScriptlibrariesinTypeScript.TypeScriptdoesthisbymeansofdeclaration.
TypeScriptprovidesyouwithaslidingscaleofhowmuchorhowlittleeffortyouwanttoput
10
WhyTypeScript
inyourdeclarations,themoreeffortyouputthemoretypesafety+codeintelligenceyou
get.NotethatdefinitionsformostofthepopularJavaScriptlibrarieshavealreadybeen
writtenforyoubytheDefinitelyTypedcommunitysoformostpurposeseither:
1. Thedefinitionfilealreadyexists.
2. Orattheveryleast,youhaveavastlistofwellreviewedTypeScriptdeclaration
templatesalreadyavailable
Asaquickexampleofhowyouwouldauthoryourowndeclarationfile,consideratrivial
exampleofjquery.Bydefault(asistobeexpectedofgoodJScode)TypeScriptexpectsyou
todeclare(i.e.use varsomewhere)beforeyouuseavariable
$('.awesome').show();//Error:cannotfindname`$`
AsaquickfixyoucantellTypeScriptthatthereisindeedsomethingcalled $:
declarevar$:any;
$('.awesome').show();//Okay!
Ifyouwantyoucanbuildonthisbasicdefinitionandprovidemoreinformationtohelp
protectyoufromerrors:
declarevar$:{
(selector:string)=>any;
};
$('.awesome').show();//Okay!
$(123).show();//Error:selectorneedstobeastring
WewilldiscussthedetailsofcreatingTypeScriptdefinitionsforexistingJavaScriptindetail
lateronceyouknowmoreaboutTypeScript(e.g.stufflike interfaceandthe any).
FutureJavaScript=>Now
TypeScriptprovidesanumberoffeaturesthatareplannedinES6forcurrentJavaScript
engines(thatonlysupportES5etc).Thetypescriptteamisactivelyaddingthesefeatures
andthislistisonlygoingtogetbiggerovertimeandwewillcoverthisinitsownsection.But
justasaspecimenhereisanexampleofaclass:
11
WhyTypeScript
classPoint{
constructor(publicx:number,publicy:number){
}
add(point:Point){
returnnewPoint(this.x+point.x,this.y+point.y);
}
}
varp1=newPoint(0,10);
varp2=newPoint(10,20);
varp3=p1.add(p2);//{x:10,y:30}
andthelovelyfatarrowfunction:
varinc=(x)=>x+1;
Summary
InthissectionwehaveprovidedyouwiththemotivationanddesigngoalsofTypeScript.
WiththisoutofthewaywecandigintothenittygrittydetailsofTypeScript.
12
JavaScript
YourJavaScriptisTypeScript
Therewere(andwillcontinuetobe)alotofcompetitorsinSomesyntaxtoJavaScript
compilers.TypeScriptisdifferentfromtheminthatYourJavaScriptisTypeScript.Here'sa
diagram:
HoweveritdoesmeanthatyouneedtolearnJavaScript(thegoodnewisyouonlyneedto
learnJavaScript).TypeScriptisjuststandardizingallthewaysyouprovidegood
documentationonJavaScript.
Justgivingyouanewsyntaxdoesn'thelpfixbug(lookingatyouCoffeeScript).
Creatinganewlanguageabstractsyoutoofarfromyourruntimes,communities
(lookingatyouDart).
TypeScriptisjustJavaScriptwithdocs.
13
JavaScript
MakingJavaScriptBetter
TypeScriptwilltrytoprotectyoufromportionsofJavaScriptthatneverworked(soyoudon't
needtorememberthisstuff):
[]+[];//JavaScriptwillgiveyou""(whichmakeslittlesense),TypeScriptwiller
ror
//
//otherthingsthatarenonsensicalinJavaScript
//-don'tgivearuntimeerror(makingdebugginghard)
//-butTypeScriptwillgiveacompiletimeerror(makingdebuggingunnecessary)
//
{}+[];//JS:0,TSError
[]+{};//JS:"[objectObject]",TSError
{}+{};//JS:NaN,TSError
"hello"-1;//JS:NaN,TSError
EssentaillyTypeScriptislintingJavaScript.Justdoingabetterjobatitthenotherlintersthat
don'thavetypeinformation.
YoustillneedtolearnJavaScript
ThatsaidTypeScriptisverypragmaticaboutthefactthatyoudowriteJavaScriptsothere
aresomethingsaboutJavaScriptthatyoustillneedtoknowinordertonotbecaughtoffguard.Letsdiscussthemnext.
14
Awful
JavaScripttheawfulparts
Herearesomeawful(misunderstood)partsofJavaScriptthatyoumustknow.
Note:TypeScriptisasupersetofJavaScript.Justwithdocumentationthatcanactually
beusedbycompilers/IDEs;)
NullandUndefined
Factisyouwillneedtodealwithboth.Justcheckforeitherwith ==check.
///Imageyouaredoing`foo.bar==undefined`wherebarcanbeoneof:
console.log(undefined==undefined);//true
console.log(null==undefined);//true
console.log(0==undefined);//false
console.log(''==undefined);//false
console.log(false==undefined);//false
So ==undefinedor( ==null)willworkonlyfor undefinedor null.Yougenerallydon't
wanttomakeadistinctionbetweenthetwo.
undefined
RememberhowIsaidyoushoulduse ==null.Ofcourseyoudo(causeIjustsaidit^).
Don'tuseitforrootlevelthings.Instrictmodeifyouuse fooand fooisundefinedyou
geta ReferenceErrorexceptionandthewholecallstackunwinds.
Youshouldusestrictmode...andinfacttheTScompilerwillinsertitforyouifyouuse
modules...moreonthoselaterinthebooksoyoudon'thavetobeexplicitaboutit:)
Sotocheckifavariableisdefinedornotatagloballevelyounormallyuse typeof:
if(typeofsomeglobal==='undefined'){
//someglobalisnowsafetouse
console.log(someglobal);
}
this
15
Awful
Anyaccessto thiskeywordwithinafunctionisactuallycontrolledbyhowthefunctionis
actuallycalled.Itiscommonlyreferredtoasthe callingcontext.
Hereisanexample:
functionfoo(){
console.log(this);
}
foo();//logsouttheglobale.g.`window`inbrowsers
letbar={
foo
}
bar.foo();//Logsout`bar`as`foo`wascalledon`bar`
Sobemindfulofyourusageof this.Ifyouwanttodisconnect thisinaclassfromthe
callingcontextuseanarrowfunction,moreonthatlater.
Next
That'sit.ThosearethesimplemisunderstoodportionsofJavaScriptthatstillresultin
variousbugfordevelopersthatarenewtothelanguage.
16
FutureJavaScriptNow
FutureJavaScript:Now
OneofthemainsellingpointsofTypeScriptisthatitallowsyoutouseabunchoffeatures
fromES6andbeyondincurrent(ES3andES5level)JavaScriptengines(likecurrent
browsersandNodeJS).Herewedeepdiveintowhythesefeaturesareusefulfollowedby
howthesefeaturesareimplementedinTypeScript.
Note:NotallofthesefeaturesareslatedforimmediateadditiontoJavaScriptbutprovide
greatutilitytoyourcodeorganizationandmaintenance.Alsonotethatyouarefreetoignore
anyoftheconstructsthatdon'tmakesenseforyourproject,althoughyouwillendupusing
mostofthemeventually;)
17
Classes
Classes
ThereasonwhyitsimportanttohaveclassesinJavaScriptasafirstclassitemisthat:
1. Classesofferausefulstructuralabstraction
2. Providesaconsistentwayfordeveloperstouseclassesinsteadofeveryframework
(emberjs,reactjsetc)comingupwiththeirownversion.
3. ObjectOrientedDevelopersalreadyunderstandclasses.
FinallyJavaScriptdeveloperscanhave class.HerewehaveabasicclasscalledPoint:
classPoint{
x:number;
y:number;
constructor(x:number,y:number){
this.x=x;
this.y=y;
}
add(point:Point){
returnnewPoint(this.x+point.x,this.y+point.y);
}
}
varp1=newPoint(0,10);
varp2=newPoint(10,20);
varp3=p1.add(p2);//{x:10,y:30}
ThisclassgeneratesthefollowingJavaScriptonES5emit:
varPoint=(function(){
functionPoint(x,y){
this.x=x;
this.y=y;
}
Point.prototype.add=function(point){
returnnewPoint(this.x+point.x,this.y+point.y);
};
returnPoint;
})();
ThisisafairlyidiomatictraditionalJavaScriptclasspatternnowasafirstclasslanguage
construct.Notethat constructorisoptional.
Inheritance
18
Classes
ClassesinTypeScript(likeotherlanguages)supportsingleinheritanceusingthe extends
keywordasshownbelow:
classPoint3DextendsPoint{
z:number;
constructor(x:number,y:number,z:number){
super(x,y);
this.z=z;
}
add(point:Point3D){
varpoint2D=super.add(point);
returnnewPoint3D(point2D.x,point2D.y,this.z+point.z);
}
}
Ifyouhaveaconstructorinyourclassthenyoumustcalltheparentconstructorfromyour
constructor(TypeScriptwillpointthisouttoyou).Thisensuresthatthestuffthatitneedsto
seton thisgetsset.Followedbythecallto superyoucanaddanyadditionalstuffyou
wanttodoinyourconstructor(hereweaddanothermember z).
Notethatyouoverrideparentmemberfunctionseasily(hereweoverride add)andstilluse
thefunctionalityofthesuperclassinyourmembers(using super.syntax).
Statics
TypeScriptclassessupport staticpropertiesthataresharedbyallinstancesoftheclass.
Anaturalplacetoput(andaccess)themisontheclassitselfandthatiswhatTypeScript
does:
classSomething{
staticinstances=0;
constructor(){
Something.instances++;
}
}
vars1=newSomething();
vars2=newSomething();
console.log(Something.instances);//2
Youcanhavestaticmembersaswellasstaticfunctions.
AccessModifiers
19
Classes
TypeScriptsupportsaccessmodifiers public, privateand protectedwhichdetermine
theaccessibilityofa classmemberasshownbelow:
accessibleon
public
private
protected
classinstances
yes
no
no
class
yes
yes
yes
classchildren
yes
no
yes
Notethatatruntime(inthegeneratedJS)thesehavenosignificancebutwillgiveyou
compiletimeerrorsifyouusethemincorrectly.Anexampleofeachisshownbelow:
classFooBase{
publicx:number;
privatey:number;
protectedz:number;
}
//EFFECTONINSTANCES
varfoo=newFooBase();
foo.x;//okay
foo.y;//ERROR:private
foo.z;//ERROR:protected
//EFFECTONCHILDCLASSES
classFooChildextendsFooBase{
constructor(){
super();
this.x;//okay
this.y;//ERROR:private
this.z;//okay
}
}
Asalwaysthesemodifiersworkforbothmemberpropertiesandmemberfunctions.
Abstract
abstractcanbethoughtofasanaccessmodifier.Wepresentitseparatelybecause
opposedtothepreviouslymentionedmodifiersitcanbeona classaswellasanymember
oftheclass.Havingan abstractmodifierprimarilymeansthatsuchfunctionalitycannotbe
directlyinvoked.
abstractmembersarecommonlyusedasameansofprovidingacontractfora
functionalitythatachildclassmustprovide. abstractclassescannotbedirectly
instantiated.Insteadtheusermustcreatesome classthatinheritfromthe abstract
20
Classes
class.
Defineusingconstructor
Havingamemberinaclassandinitializingitlikebelow:
classFoo{
x:number;
constructor(x:number){
this.x=x;
}
}
issuchacommonpatternthatTypeScriptprovidesashorthandwhereyoucanprefixthe
memberwithanaccessmodifieranditisautomaticallydeclaredontheclassandcopied
fromtheconstructor.Sothepreviousexamplecanbere-writtenas(notice public
x:number):
classFoo{
constructor(publicx:number){
}
}
Propertyinitializer
ThisisaniftyfeaturesupportedbyTypeScript(fromES7actually).Youcaninitializeany
memberoftheclassoutsidetheclassconstructor,usefultoprovidedefault(notice members
=[])
classFoo{
members=[];//Initializedirectly
add(x){
this.members.push(x);
}
}
21
ClassesEmit
WhatsupwiththeIIFE
Thejsgeneratedfortheclasscouldhavebeen:
functionPoint(x,y){
this.x=x;
this.y=y;
}
Point.prototype.add=function(point){
returnnewPoint(this.x+point.x,this.y+point.y);
};
ThereasonitswrappedinanImmediately-InvokedFunctionExpression(IIFE)i.e.
(function(){
//BODY
returnPoint;
})();
hastodowithinheritance.ItallowsTypeScripttocapturethebaseclassasavariable
_supere.g.
varPoint3D=(function(_super){
__extends(Point3D,_super);
functionPoint3D(x,y,z){
_super.call(this,x,y);
this.z=z;
}
Point3D.prototype.add=function(point){
varpoint2D=_super.prototype.add.call(this,point);
returnnewPoint3D(point2D.x,point2D.y,this.z+point.z);
};
returnPoint3D;
})(Point);
NoticethattheIIFEallowsTypeScripttoeasilycapturethebaseclass Pointina _super
variableandthatisusedconsistentlyintheclassbody.
__extends
YouwillnoticethatassoonasyouinheritaclassTypeScriptalsogeneratesthefollowing
function:
22
ClassesEmit
var__extends=this.__extends||function(d,b){
for(varpinb)if(b.hasOwnProperty(p))d[p]=b[p];
function__(){this.constructor=d;}
__.prototype=b.prototype;
d.prototype=new__();
};
Here dreferstothederivedclassand breferstothebaseclass.Thisfunctiondoestwo
things:
1. copiesthestaticmembersofthebaseclassontothechildclassi.e. for(varpinb)
if(b.hasOwnProperty(p))d[p]=b[p];
2. setsupthechildclassfunction'sprototypetooptionallylookupmembersontheparent's
protoi.e.effectively d.prototype.__proto__=b.prototype
Peoplerarelyhavetroubleunderstanding1,butmanypeoplestrugglewith2.soan
explanationisinorder
d.prototype.__proto__=b.prototype
AfterhavingtutoredmanypeopleaboutthisIfindthefollowingexplanationtobesimplest.
Firstwewillexplainhowthecodefrom __extendsisequivalenttothesimple
d.prototype.__proto__=b.prototype,andthenwhythislineinitselfissignificant.To
understandallthisyouneedtoknowthesethings:
1.
__proto__
2.
prototype
3. effectof newon thisinsidethecalledfunction
4. effectof newon prototypeand __proto__
AllobjectsinJavaScriptcontaina __proto__member.Thismemberisoftennotaccessible
inolderbrowsers(sometimesdocumentationreferstothismagicalpropertyas
[[prototype]]).Ithasoneobjective:Ifapropertyisnotfoundonanobjectduringlookup
(e.g. obj.property)thenitislookedupat obj.__proto__.property.Ifitisstillnotfound
then obj.__proto__.__proto__.propertytilleither:itisfoundorthelatest .__proto__itselfis
null.ThisexplainswhyJavaScriptiscalledtosupportprototypalinheritanceoutofthebox.
Thisisshowninthefollowingexample,whichyoucanruninthechromeconsoleornodejs:
23
ClassesEmit
varfoo={}
//setuponfooaswellasfoo.__proto__
foo.bar=123;
foo.__proto__.bar=456;
console.log(foo.bar);//123
deletefoo.bar;//removefromobject
console.log(foo.bar);//456
deletefoo.__proto__.bar;//removefromfoo.__proto__
console.log(foo.bar);//undefined
Coolsoyouunderstand __proto__.Anotherusefulinformationisthatall functionsin
JavaScripthaveapropertycalled prototypeandthatithasamember constructor
pointingbacktothefunction.Thisisshownbelow:
functionFoo(){}
console.log(Foo.prototype);//{}i.e.itexistsandisnotundefined
console.log(Foo.prototype.constructor===Foo);//Hasamembercalled`constructor`p
ointingbacktothefunction
Nowletslookateffectof newon thisinsidethecalledfunction.Basically thisinside
thecalledfunctionisgoingtopointtothenewlycreatedobjectthatwillbereturnedfromthe
function.It'ssimpletoseeifyoumutateapropertyon thisinsidethefunction:
functionFoo(){
this.bar=123;
}
//callwiththenewoperator
varnewFoo=newFoo();
console.log(newFoo.bar);//123
Nowtheonlyotherthingyouneedtoknowisthatcalling newonafunctioncopiesthe
prototypeofthefunctionintothe __proto__ofthenewlycreatedobjectthatisreturned
fromthefunctioncall.Hereiscodeyoucanruntocompletelyunderstandit:
functionFoo(){}
varfoo=newFoo();
console.log(foo.__proto__===Foo.prototype);//True!
That'sit.Nowlookatthefollowingstraightoutof __extends.I'vetakethelibertytonumber
theselines:
24
ClassesEmit
1function__(){this.constructor=d;}
2__.prototype=b.prototype;
3d.prototype=new__();
Readingthisfunctioninreversethe d.prototype=new__()online3effectivelymeans
d.prototype={__proto__:__.prototype}(becauseoftheeffectof newon prototypeand
__proto__),combineitwiththepreviousline(i.e.line2 __.prototype=b.prototype;)you
get d.prototype={__proto__:b.prototype}.
Butwaitwewanted d.prototype.__proto__i.e.justtheprotochangedandmaintaintheold
d.prototype.constructor.Thisiswherethesignificanceofthefirstline(i.e. function__(){
this.constructor=d;})comesin.Herewewilleffectivelyhave d.prototype={__proto__:
__.prototype,d.constructor=d}(becauseoftheeffectof newon thisinsidethecalled
function).Sosincewerestore d.prototype.constructor,theonlythingwehavetruly
mutatedisthe __proto__hence d.prototype.__proto__=b.prototype.
d.prototype.__proto__=b.prototypesignificance
Thesignificanceisthatitallowsyoutoaddmemberfunctionstoachildclassandinherit
othersfromthebaseclass.Thisisdemonstratedbythefollowingsimpleexample:
functionAnimal(){}
Animal.prototype.walk=function(){console.log('walk')};
functionBird(){}
Bird.prototype.__proto__=Animal.prototype;
Bird.prototype.fly=function(){console.log('fly')};
varbird=newBird();
bird.walk();
bird.fly();
Basically bird.flywillbelookedupfrom bird.__proto__.fly(rememberthat newmakes
the bird.__proto__pointto Bird.prototype)and bird.walk(aninheritedmember)willbe
lookedupfrom bird.__proto__.__proto__.walk(as bird.__proto__==Bird.prototypeand
bird.__proto__.__proto__== Animal.prototype).
25